diff options
author | John Levon <john.levon@joyent.com> | 2020-06-08 07:43:14 -0700 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2020-06-08 12:20:26 -0700 |
commit | b3263c9871d056ea54cca24eaeedd5a41fd333de (patch) | |
tree | f5673b8f100a07a90d890955c0d22739ab1ecda3 | |
parent | e1fb6a07e9492184a949d5a3ba446ff53b888a2b (diff) | |
download | illumos-joyent-b3263c9871d056ea54cca24eaeedd5a41fd333de.tar.gz |
12826 update to smatch 0.6.1-rc1-il-6
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/tools/smatch/src/Documentation/smatch.txt | 4 | ||||
-rw-r--r-- | usr/src/tools/smatch/src/Documentation/submitting-patches.md | 13 | ||||
-rw-r--r-- | usr/src/tools/smatch/src/Makefile | 2 | ||||
-rw-r--r-- | usr/src/tools/smatch/src/check_atomic_inc_dec.c | 159 | ||||
-rw-r--r-- | usr/src/tools/smatch/src/check_kernel_printf.c | 10 | ||||
-rw-r--r-- | usr/src/tools/smatch/src/smatch_db.c | 5 |
6 files changed, 163 insertions, 30 deletions
diff --git a/usr/src/tools/smatch/src/Documentation/smatch.txt b/usr/src/tools/smatch/src/Documentation/smatch.txt index b62e4507ee..dadd05d0da 100644 --- a/usr/src/tools/smatch/src/Documentation/smatch.txt +++ b/usr/src/tools/smatch/src/Documentation/smatch.txt @@ -1,9 +1,13 @@ Smatch +0. Introduction 1. Building Smatch 2. Using Smatch 3. Smatch vs Sparse +Section 0: Introduction + +The Smatch mailing list is <smatch@vger.kernel.org>. Section 1: Building Smatch --------------------------- diff --git a/usr/src/tools/smatch/src/Documentation/submitting-patches.md b/usr/src/tools/smatch/src/Documentation/submitting-patches.md index fb176ce51d..66d6cd175a 100644 --- a/usr/src/tools/smatch/src/Documentation/submitting-patches.md +++ b/usr/src/tools/smatch/src/Documentation/submitting-patches.md @@ -19,3 +19,16 @@ Kernel submitting process. Notice that sparse uses the MIT License. +4. Smatch is built on top of Sparse but it is licensed under the GPLv2+ the + git repostories are: + + https://github.com/error27/smatch + https://repo.or.cz/w/smatch.git + + They are identical mirrors so it doesn't matter which you use. + + Send patches for to Smatch to <smatch@vger.kernel.org>. If the code is + shared with both Sparse and Smatch then please send it to the Sparse + mailing list instead <linux-sparse@vger.kernel.org> and I will pick it up + from there. + diff --git a/usr/src/tools/smatch/src/Makefile b/usr/src/tools/smatch/src/Makefile index 7cd1db3039..8d7f2e66aa 100644 --- a/usr/src/tools/smatch/src/Makefile +++ b/usr/src/tools/smatch/src/Makefile @@ -1,4 +1,4 @@ -VERSION=0.6.1-rc1-il-5 +VERSION=0.6.1-rc1-il-6 ######################################################################## # The following variables can be overwritten from the command line diff --git a/usr/src/tools/smatch/src/check_atomic_inc_dec.c b/usr/src/tools/smatch/src/check_atomic_inc_dec.c index c83dc893b2..068cb5e535 100644 --- a/usr/src/tools/smatch/src/check_atomic_inc_dec.c +++ b/usr/src/tools/smatch/src/check_atomic_inc_dec.c @@ -24,14 +24,22 @@ static int my_id; STATE(inc); -STATE(orig); +STATE(start_state); STATE(dec); static struct smatch_state *unmatched_state(struct sm_state *sm) { - if (parent_is_gone_var_sym(sm->name, sm->sym)) + /* + * We default to decremented. For example, say we have: + * if (p) + * atomic_dec(p); + * <- p is decreemented. + * + */ + if ((sm->state == &dec) && + parent_is_gone_var_sym(sm->name, sm->sym)) return sm->state; - return &undefined; + return &start_state; } static struct stree *start_states; @@ -86,7 +94,7 @@ static struct sm_state *get_best_match(const char *key) return NULL; } -static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec) +static void db_inc_dec(struct expression *expr, int param, const char *key, int inc_dec) { struct sm_state *start_sm; struct expression *arg; @@ -129,7 +137,7 @@ static void db_inc_dec(struct expression *expr, int param, const char *key, cons set_start_state(name, sym, &inc); if (start_sm && start_sm->state == &inc) - set_state(my_id, name, sym, &orig); + set_state(my_id, name, sym, &start_state); else set_state(my_id, name, sym, &dec); } @@ -139,24 +147,70 @@ free: free_string(name); } +static const char *primitive_funcs[] = { + "atomic_inc_return", + "atomic_add_return", + "atomic_sub_return", + "atomic_sub_and_test", + "atomic_dec_and_test", + "_atomic_dec_and_lock", + "atomic_dec", + "atomic_long_inc", + "atomic_long_dec", + "atomic_inc", + "atomic_sub", + "refcount_inc", + "refcount_dec", + "refcount_add", + "refcount_add_not_zero", + "refcount_inc_not_zero", + "refcount_sub_and_test", + "refcount_dec_and_test", + "atomic_dec_if_positive", +}; + +static bool is_inc_dec_primitive(struct expression *expr) +{ + int i; + + while (expr->type == EXPR_ASSIGNMENT) + expr = strip_expr(expr->right); + if (expr->type != EXPR_CALL) + return false; + + if (expr->fn->type != EXPR_SYMBOL) + return false; + + for (i = 0; i < ARRAY_SIZE(primitive_funcs); i++) { + if (sym_name_is(primitive_funcs[i], expr->fn)) + return true; + } + + return false; +} + static void db_inc(struct expression *expr, int param, char *key, char *value) { - db_inc_dec(expr, param, key, value, ATOMIC_INC); + if (is_inc_dec_primitive(expr)) + return; + db_inc_dec(expr, param, key, ATOMIC_INC); } static void db_dec(struct expression *expr, int param, char *key, char *value) { - db_inc_dec(expr, param, key, value, ATOMIC_DEC); + if (is_inc_dec_primitive(expr)) + return; + db_inc_dec(expr, param, key, ATOMIC_DEC); } static void match_atomic_inc(const char *fn, struct expression *expr, void *_unused) { - db_inc_dec(expr, 0, "$->counter", "", ATOMIC_INC); + db_inc_dec(expr, 0, "$->counter", ATOMIC_INC); } static void match_atomic_dec(const char *fn, struct expression *expr, void *_unused) { - db_inc_dec(expr, 0, "$->counter", "", ATOMIC_DEC); + db_inc_dec(expr, 0, "$->counter", ATOMIC_DEC); } static void match_atomic_add(const char *fn, struct expression *expr, void *_unused) @@ -166,26 +220,53 @@ static void match_atomic_add(const char *fn, struct expression *expr, void *_unu amount = get_argument_from_call_expr(expr->args, 0); if (get_implied_value(amount, &sval) && sval_is_negative(sval)) { - db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC); + db_inc_dec(expr, 1, "$->counter", ATOMIC_DEC); return; } - db_inc_dec(expr, 1, "$->counter", "", ATOMIC_INC); + db_inc_dec(expr, 1, "$->counter", ATOMIC_INC); } static void match_atomic_sub(const char *fn, struct expression *expr, void *_unused) { - db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC); + db_inc_dec(expr, 1, "$->counter", ATOMIC_DEC); } static void refcount_inc(const char *fn, struct expression *expr, void *param) { - db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_INC); + db_inc_dec(expr, PTR_INT(param), "$->ref.counter", ATOMIC_INC); } static void refcount_dec(const char *fn, struct expression *expr, void *param) { - db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_DEC); + db_inc_dec(expr, PTR_INT(param), "$->ref.counter", ATOMIC_DEC); +} + +static void pm_runtime_get_sync(const char *fn, struct expression *expr, void *param) +{ + db_inc_dec(expr, PTR_INT(param), "$->power.usage_count.counter", ATOMIC_INC); +} + +static void match_implies_inc(const char *fn, struct expression *call_expr, + struct expression *assign_expr, void *param) +{ + db_inc_dec(call_expr, PTR_INT(param), "$->ref.counter", ATOMIC_INC); +} + +static void match_implies_atomic_dec(const char *fn, struct expression *call_expr, + struct expression *assign_expr, void *param) +{ + db_inc_dec(call_expr, PTR_INT(param), "$->counter", ATOMIC_DEC); +} + +static bool is_maybe_dec(struct sm_state *sm) +{ + if (sm->state == &dec) + return true; + if (slist_has_state(sm->possible, &dec) && + !slist_has_state(sm->possible, &inc)) + return true; + return false; } static void match_return_info(int return_id, char *return_ranges, struct expression *expr) @@ -194,9 +275,13 @@ static void match_return_info(int return_id, char *return_ranges, struct express const char *param_name; int param; + if (is_impossible_path()) + return; + FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { - if (sm->state != &inc && - sm->state != &dec) + if (sm->state != &inc && !is_maybe_dec(sm)) + continue; + if (sm->state == get_state_stree(start_states, my_id, sm->name, sm->sym)) continue; if (parent_is_gone_var_sym(sm->name, sm->sym)) continue; @@ -221,7 +306,7 @@ static int success_fail_positive(struct range_list *rl) if (!rl) return EMPTY; - if (sval_is_negative(rl_min(rl))) + if (!is_whole_rl(rl) && sval_is_negative(rl_min(rl))) return NEGATIVE; if (rl_min(rl).value == 0) @@ -237,14 +322,23 @@ static void check_counter(const char *name, struct symbol *sym) int inc_buckets[NUM_BUCKETS] = {}; int dec_buckets[NUM_BUCKETS] = {}; struct stree *stree, *orig_stree; + struct smatch_state *state; struct sm_state *return_sm; struct sm_state *sm; sval_t line = sval_type_val(&int_ctype, 0); int bucket; + /* static variable are probably just counters */ + if (sym->ctype.modifiers & MOD_STATIC && + !(sym->ctype.modifiers & MOD_TOPLEVEL)) + return; + FOR_EACH_PTR(get_all_return_strees(), stree) { orig_stree = __swap_cur_stree(stree); + if (is_impossible_path()) + goto swap_stree; + return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL); if (!return_sm) goto swap_stree; @@ -257,21 +351,23 @@ static void check_counter(const char *name, struct symbol *sym) goto swap_stree; sm = get_sm_state(my_id, name, sym); - if (!sm) - goto swap_stree; + if (sm) + state = sm->state; + else + state = &start_state; - if (sm->state != &inc && - sm->state != &dec && - sm->state != &orig) + if (state != &inc && + state != &dec && + state != &start_state) goto swap_stree; bucket = success_fail_positive(estate_rl(return_sm->state)); - if (sm->state == &inc) { + if (state == &inc) { add_range(&inc_lines, line, line); inc_buckets[bucket] = true; } - if (sm->state == &dec || sm->state == &orig) { + if (state == &dec || state == &start_state) { add_range(&dec_lines, line, line); dec_buckets[bucket] = true; } @@ -345,9 +441,14 @@ void check_atomic_inc_dec(int id) add_function_hook("atomic_add_return", &match_atomic_add, NULL); add_function_hook("atomic_sub_return", &match_atomic_sub, NULL); add_function_hook("atomic_sub_and_test", &match_atomic_sub, NULL); + add_function_hook("atomic_long_sub_and_test", &match_atomic_sub, NULL); + add_function_hook("atomic64_sub_and_test", &match_atomic_sub, NULL); add_function_hook("atomic_dec_and_test", &match_atomic_dec, NULL); + add_function_hook("atomic_long_dec_and_test", &match_atomic_dec, NULL); + add_function_hook("atomic64_dec_and_test", &match_atomic_dec, NULL); add_function_hook("_atomic_dec_and_lock", &match_atomic_dec, NULL); add_function_hook("atomic_dec", &match_atomic_dec, NULL); + add_function_hook("atomic_dec_return", &match_atomic_dec, NULL); add_function_hook("atomic_long_inc", &match_atomic_inc, NULL); add_function_hook("atomic_long_dec", &match_atomic_dec, NULL); add_function_hook("atomic_inc", &match_atomic_inc, NULL); @@ -356,11 +457,17 @@ void check_atomic_inc_dec(int id) add_function_hook("refcount_inc", &refcount_inc, INT_PTR(0)); add_function_hook("refcount_dec", &refcount_dec, INT_PTR(0)); add_function_hook("refcount_add", &refcount_inc, INT_PTR(1)); - add_function_hook("refcount_add_not_zero", &refcount_inc, INT_PTR(1)); - add_function_hook("refcount_inc_not_zero", &refcount_inc, INT_PTR(0)); + + return_implies_state("refcount_add_not_zero", 1, 1, &match_implies_inc, INT_PTR(1)); + return_implies_state("refcount_inc_not_zero", 1, 1, &match_implies_inc, INT_PTR(0)); + + return_implies_state("atomic_dec_if_positive", 0, INT_MAX, &match_implies_atomic_dec, INT_PTR(0)); + add_function_hook("refcount_sub_and_test", &refcount_dec, INT_PTR(1)); add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(0)); + add_function_hook("pm_runtime_get_sync", &pm_runtime_get_sync, INT_PTR(0)); + add_hook(&match_check_missed, END_FUNC_HOOK); add_hook(&match_after_func, AFTER_FUNC_HOOK); diff --git a/usr/src/tools/smatch/src/check_kernel_printf.c b/usr/src/tools/smatch/src/check_kernel_printf.c index 8992a83fd7..4b65da5a21 100644 --- a/usr/src/tools/smatch/src/check_kernel_printf.c +++ b/usr/src/tools/smatch/src/check_kernel_printf.c @@ -15,6 +15,8 @@ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt */ +#define _GNU_SOURCE + #include <assert.h> #include <ctype.h> #include <string.h> @@ -207,7 +209,7 @@ qualifier: return ++fmt - start; case 's': - if (qualifier) + if (qualifier && qualifier != 'l') sm_warning("qualifier '%c' ignored for %%s specifier", qualifier); spec->type = FORMAT_TYPE_STR; @@ -672,6 +674,12 @@ pointer(const char *fmt, struct expression *arg, int vaidx) vaidx, type_to_str(type)); return; } + + /* error pointers */ + if (*fmt == 'e') + fmt++; + + /* Just plain %p, nothing to check. */ if (!isalnum(*fmt)) return; diff --git a/usr/src/tools/smatch/src/smatch_db.c b/usr/src/tools/smatch/src/smatch_db.c index d31c3a17cf..8d3c3ca49d 100644 --- a/usr/src/tools/smatch/src/smatch_db.c +++ b/usr/src/tools/smatch/src/smatch_db.c @@ -2719,8 +2719,9 @@ const char *state_name_to_param_name(const char *state_name, const char *param_n return alloc_sname(buf); } - if (state_name[name_len] == '-' && /* check for '-' from "->" */ - strncmp(state_name, param_name, name_len) == 0) { + /* check for '-' from "->" */ + if (strncmp(state_name, param_name, name_len) == 0 && + state_name[name_len] == '-') { snprintf(buf, sizeof(buf), "%.*s$%s", star_cnt, "**********", state_name + name_len); return alloc_sname(buf); } |