elfs-clang-plugins

所属分类:编译器/解释器
开发工具:C++
文件大小:56KB
下载次数:0
上传日期:2018-10-29 23:26:14
上 传 者sh-1993
说明:  一组用于更安全的C编程的铿锵插件
(A collection of clang plugins for safer C programming)

文件列表:
LICENSE (1072, 2017-10-06)
Makefile (1626, 2017-10-06)
enums_conversion (0, 2017-10-06)
enums_conversion\enums_conversion.cpp (14098, 2017-10-06)
enums_conversion\test (0, 2017-10-06)
enums_conversion\test\include.mk (1317, 2017-10-06)
enums_conversion\test\negative_arrow.c (167, 2017-10-06)
enums_conversion\test\negative_assign.c (148, 2017-10-06)
enums_conversion\test\negative_assign_2.c (138, 2017-10-06)
enums_conversion\test\negative_bad_conditional.c (117, 2017-10-06)
enums_conversion\test\negative_bitwise_or.c (116, 2017-10-06)
enums_conversion\test\negative_compare.c (171, 2017-10-06)
enums_conversion\test\negative_compare_2.c (215, 2017-10-06)
enums_conversion\test\negative_if.c (153, 2017-10-06)
enums_conversion\test\negative_literal_int.c (105, 2017-10-06)
enums_conversion\test\negative_member.c (164, 2017-10-06)
enums_conversion\test\negative_not.c (120, 2017-10-06)
enums_conversion\test\negative_param.c (125, 2017-10-06)
enums_conversion\test\negative_return.c (113, 2017-10-06)
enums_conversion\test\negative_return_2.c (109, 2017-10-06)
enums_conversion\test\negative_switch.c (223, 2017-10-06)
enums_conversion\test\negative_var.c (108, 2017-10-06)
enums_conversion\test\negative_var_decl.c (145, 2017-10-06)
enums_conversion\test\negative_var_decl_2.c (135, 2017-10-06)
enums_conversion\test\positive.c (1450, 2017-10-06)
enums_conversion\test\test_enums_conersion_common.h (278, 2017-10-06)
fail.sh (193, 2017-10-06)
fail_expecting.sh (236, 2017-10-06)
include_cleaner (0, 2017-10-06)
include_cleaner\include_cleaner.cpp (23710, 2017-10-06)
include_cleaner\test (0, 2017-10-06)
include_cleaner\test\aliased_type.h (109, 2017-10-06)
include_cleaner\test\extern_func.h (45, 2017-10-06)
include_cleaner\test\extern_func_2.h (31, 2017-10-06)
include_cleaner\test\extern_var.h (23, 2017-10-06)
include_cleaner\test\foo.h (15, 2017-10-06)
... ...

# elfs-clang-plugins A collection of clang plugins for safer C programming. The plugins detect problems at compile time. * enums_conversion: Finds implicit casts to/from enums and integral types * `warn_unused_result`: Warns about functions declared without the `warn_unused_result` attribute * include_cleaner: Finds unused #includes * large_assignment: Finds large copies in assignments and initializations (size is configurable) * private: Prevents access to fields of structs that are defined in private.h files See below for more information about each plugin. Each plugin has a `test` directory with both positive and negative test cases, which also serve as good examples. # Usage Building the plugin requires llvm/clang development libraries to be installed, it expects an `llvm-config-***` to be available. On debian or ubuntu, try installing: llvm-3.7-dev clang-3.7 libclang-3.7-dev. You may need to use a PPA. Tested also on Centos 7.1, using the packages: llvm-static, llvm-libs, llvm-devel, clang-devel. You may need to get them from copr. Once you have the prerequisites, build & test: make make tests All the plugins are linked into a single .so file, for convenience, but are controlled individually via clang command line arguments. Example usage (once `clang_plugins.so` is built): clang -Xclang -load -Xclang ./clang_plugins.so \ -Xclang -add-plugin -Xclang include_cleaner \ -Xclang -add-plugin -Xclang enums_conversion \ -Xclang -add-plugin -Xclang large_assignment -Xclang -plugin-arg-large_assignment -Xclang 700 \ -c my_file.c -o my_file.o See `CFLAG_CLANG_PLUGINS` in `plugins.mk` for the full command line argument for using all plugins. # Plugins ## enums_conversion (Check [enums_conversion/README.md](https://github.com/sinelaw/elfs-clang-plugins/blob/master/enums_conversion/README.md) for more information about the enums_conversion plugin.) In C, enum types are implicitly convertible to other integral types. The following code compiles without warnings, even with `-Wall -Wextra` (tested on GCC 6.3 & clang 3.7): enum Result { OK, NO_BUNNIES }; enum Result get_bunnies(void) { return 3; } The enums_conversion plugin prevents such silly mistakes: clang -Xclang -load -Xclang ./clang_plugins.so -Xclang -add-plugin -Xclang enums_conversion -c /tmp/test.c /tmp/test.c:7:12: error: enum conversion to or from enum Result return 3; ^ 1 error generated. Among other cases detected by the plugin: * Passing, assigning or returning a value of the wrong type when an enum is expected * Using enums as bool in conditional expressions * Using values of wrong type in enum flag bitwise or `|` expressions * etc. There are cases (or styles of C coding) that use enums as actual numbers (such as array indices). In those cases you can use an explicit cast to make the fact that the enum needs to be converted, well, explicit. Note: The enums_conversion plugin uses AST matching to find violations - it works by looking for specific problematic patterns. A more complete approach would be to traverse the entire AST and perform a complete type-checking pass (or to augment the existing clang type checker, but as far as I can tell, a clang plugin can't do that). However, we found the AST matching approach to be quite effective, and it was easy to implement. ## `warn_unused_result` Both clang and gcc support the attribute `warn_unused_result` on functions, but provide no way to treat all functions as if they have the attribute, nor is there a way to warn about functions that don't have the attribute. The `warn_unused_result` plugin will emit a warning functions that **lack a `warn_unused_result` attribute**. The plugin only considers functions declared or defined in the current compilation unit. The plugin accepts an optional arg, `--static-only` which causes it to warn only about static functions (for when changing external APIs is too much work). Example: int foo(void); Compiler output: /tmp/test.c:1:5: warning: missing attribute warn_unused_result int foo(void); ## include_cleaner The include_cleaner plugin helps you get rid of unnecessary includes, for example: foo.h: struct Foo { }; bar.c: #include "foo.h" // never uses anything from foo.h In this case, the plugin will give an error: clang -Xclang -load -Xclang ./clang_plugins.so -Xclang -add-plugin -Xclang include_cleaner -c /tmp/bar.c /tmp/bar.c:1:1: warning: include cleaner: unused #include of '/tmp/foo.h' #include "foo.h" ^ 1 warning generated. The plugin expects your code to follow a certain pattern: 1. `foo.c` is always allowed to #include `foo.h` or `foo_api.h` 2. External files are always allowed to be #included (currently just anything in `/usr`) 3. Any other file that's #included must be used, by referencing a type, function or global defined directly in that file. Note that this prohibits "mega-h-files", which are .h files that just include other .h files in order to expose them. Our intention with this plugin is to enforce #including **only directly what you need**. It makes dependencies easier to understand. Also, the compiler doesn't need to work on all those unused files - in one case we saved >30% compilation time in a large project by just cleaning up our #includes. Files from `/usr` are always allowed because they don't follow any obvious pattern of who is responsible for what. `` doesn't actually define `errno` - it does a bunch of nested includes which eventually bring in the global variable. ## large_assignment Consider the following code: struct Context { char scratch_buffer[80*1024]; int field; }; void init_field(struct Context *ctx, int x) { *ctx = (struct Context) { /* 80 kb copy hiding here */ .field = x, }; } The large_assignment plugin helps to find assignments which look innocent but may incur a big copy. The size is configurable via a clang plugin command line argument. With the plugin, the above example yields: clang -Wall -Wextra -g -Xclang -load -Xclang ./clang_plugins.so \ -Xclang -add-plugin -Xclang large_assignment \ -Xclang -plugin-arg-large_assignment -Xclang 1024 \ -c /tmp/large.c -o /tmp/large.o /tmp/large.c:7:16: warning: large assignment of 81924 bytes is more than allowed 1024 bytes *ctx = (struct Context) { ^ 1 warning generated. To change the maximum allowed, use the command line arguments, e.g. `-Xclang -plugin-arg-large_assignment -Xclang 1024` # private The `private` plugin enforces a coding convention, where struct fields may not be accessed directly unless they are exposed in a public .h file. The plugin assumes that private .h files are suffixed with `_private.h` The rule is: `module.c` is allowed to access privates from `module_private.h`, but not from any other private file (e.g. stuff from `other_private.h` would not be allowed). Example project: foo.h: #include "foo_private.h" typedef struct _Foo Foo; /* Public API, defined in foo.c, supposedly (implementation doesn't matter for the example) */ void foo_init(Foo *); void foo_set_value(Foo *, int); foo_private.h: struct _Foo { int field; /* supposed to be private, accessible via API function */ }; usage.c: #include "foo.h" void bar(Foo *foo) { foo->field = 3; /* BAD! should use API foo_set_value() */ } The plugin complains about this API circumvention: clang -Wall -Wextra -g -Xclang -load -Xclang ./clang_plugins.so -Xclang -add-plugin -Xclang private -c /tmp/usage.c -o /tmp/usage.o /tmp/usage.c:5:14: warning: access to private member of _Foo foo->field = 3; /* BAD! should use API foo_set_value() */ ^ /tmp/foo_private.h:1:12: note: declaration of _Foo struct _Foo { ^ 1 warning generated. If a struct's internals are supposed to be exposed, you just need to define it in the non-private .h file. You sometimes want to allow accessing a private field. Common examples are tests, or when a module is deliberately split into several .c files all sharing the same `_private.h`. For those cases there is `FRIEND_OF`, a macro in `private_api.h`: /* FRIEND_OF takes a single *type name* as an argument */ FRIEND_OF(Foo); /* Put this a file level. Now we are allowed in this .c file to access internals of Foo. */ The idea is not to abuse `FRIEND_OF` too much.

近期下载者

相关文件


收藏者