Skip to content

Commit

Permalink
12826 update to smatch 0.6.1-rc1-il-6
Browse files Browse the repository at this point in the history
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
  • Loading branch information
John Levon committed Jun 8, 2020
1 parent e1fb6a0 commit b3263c9
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 30 deletions.
4 changes: 4 additions & 0 deletions usr/src/tools/smatch/src/Documentation/smatch.txt
Original file line number Diff line number Diff line change
@@ -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
---------------------------
Expand Down
13 changes: 13 additions & 0 deletions usr/src/tools/smatch/src/Documentation/submitting-patches.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

2 changes: 1 addition & 1 deletion usr/src/tools/smatch/src/Makefile
Original file line number Diff line number Diff line change
@@ -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
Expand Down
159 changes: 133 additions & 26 deletions usr/src/tools/smatch/src/check_atomic_inc_dec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -139,24 +147,70 @@ static void db_inc_dec(struct expression *expr, int param, const char *key, cons
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)
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
10 changes: 9 additions & 1 deletion usr/src/tools/smatch/src/check_kernel_printf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -207,7 +209,7 @@ format_decode(const char *fmt, struct printf_spec *spec)
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;
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions usr/src/tools/smatch/src/smatch_db.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit b3263c9

Please sign in to comment.