Print this page
12724 update smatch to 0.6.1-rc1-il-5
*** 13,22 ****
--- 13,24 ----
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
*/
+ #include <ctype.h>
+
#include "smatch.h"
#include "smatch_extra.h"
#include "smatch_slist.h"
static int my_id;
*** 23,38 ****
STATE(inc);
STATE(orig);
STATE(dec);
static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec)
{
! struct smatch_state *start_state;
struct expression *arg;
char *name;
struct symbol *sym;
while (expr->type == EXPR_ASSIGNMENT)
expr = strip_expr(expr->right);
if (expr->type != EXPR_CALL)
return;
--- 25,100 ----
STATE(inc);
STATE(orig);
STATE(dec);
+ static struct smatch_state *unmatched_state(struct sm_state *sm)
+ {
+ if (parent_is_gone_var_sym(sm->name, sm->sym))
+ return sm->state;
+ return &undefined;
+ }
+
+ static struct stree *start_states;
+ static struct stree_stack *saved_stack;
+ static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
+ {
+ struct smatch_state *orig;
+
+ orig = get_state_stree(start_states, my_id, name, sym);
+ if (!orig)
+ set_state_stree(&start_states, my_id, name, sym, start);
+ else if (orig != start)
+ set_state_stree(&start_states, my_id, name, sym, &undefined);
+ }
+
+ static struct sm_state *get_best_match(const char *key)
+ {
+ struct sm_state *sm;
+ struct sm_state *match;
+ int cnt = 0;
+ int start_pos, state_len, key_len, chunks, i;
+
+ if (strncmp(key, "$->", 3) == 0)
+ key += 3;
+
+ key_len = strlen(key);
+ chunks = 0;
+ for (i = key_len - 1; i > 0; i--) {
+ if (key[i] == '>' || key[i] == '.')
+ chunks++;
+ if (chunks == 2) {
+ key += (i + 1);
+ key_len = strlen(key);
+ break;
+ }
+ }
+
+ FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
+ state_len = strlen(sm->name);
+ if (state_len < key_len)
+ continue;
+ start_pos = state_len - key_len;
+ if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
+ strcmp(sm->name + start_pos, key) == 0) {
+ cnt++;
+ match = sm;
+ }
+ } END_FOR_EACH_SM(sm);
+
+ if (cnt == 1)
+ return match;
+ return NULL;
+ }
+
static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec)
{
! struct sm_state *start_sm;
struct expression *arg;
char *name;
struct symbol *sym;
+ bool free_at_end = true;
while (expr->type == EXPR_ASSIGNMENT)
expr = strip_expr(expr->right);
if (expr->type != EXPR_CALL)
return;
*** 43,68 ****
name = get_variable_from_key(arg, key, &sym);
if (!name || !sym)
goto free;
! start_state = get_state(my_id, name, sym);
if (inc_dec == ATOMIC_INC) {
! // if (start_state == &inc)
! // sm_error("XXX double increment '%s'", name);
set_state(my_id, name, sym, &inc);
} else {
! // if (start_state == &dec)
! // sm_error("XXX double decrement '%s'", name);
! if (start_state == &inc)
set_state(my_id, name, sym, &orig);
else
set_state(my_id, name, sym, &dec);
}
free:
free_string(name);
}
static void db_inc(struct expression *expr, int param, char *key, char *value)
{
--- 105,143 ----
name = get_variable_from_key(arg, key, &sym);
if (!name || !sym)
goto free;
! start_sm = get_sm_state(my_id, name, sym);
! if (!start_sm && inc_dec == ATOMIC_DEC) {
! start_sm = get_best_match(key);
! if (start_sm) {
! free_string(name);
! free_at_end = false;
! name = (char *)start_sm->name;
! sym = start_sm->sym;
! }
! }
if (inc_dec == ATOMIC_INC) {
! if (!start_sm)
! set_start_state(name, sym, &dec);
! // set_refcount_inc(name, sym);
set_state(my_id, name, sym, &inc);
} else {
! // set_refcount_dec(name, sym);
! if (!start_sm)
! set_start_state(name, sym, &inc);
!
! if (start_sm && start_sm->state == &inc)
set_state(my_id, name, sym, &orig);
else
set_state(my_id, name, sym, &dec);
}
free:
+ if (free_at_end)
free_string(name);
}
static void db_inc(struct expression *expr, int param, char *key, char *value)
{
*** 121,130 ****
--- 196,207 ----
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
if (sm->state != &inc &&
sm->state != &dec)
continue;
+ if (parent_is_gone_var_sym(sm->name, sm->sym))
+ continue;
param = get_param_num_from_sym(sm->sym);
if (param < 0)
continue;
param_name = get_param_name(sm);
if (!param_name)
*** 134,150 ****
param, param_name, "");
} END_FOR_EACH_SM(sm);
}
enum {
! NEGATIVE, ZERO, POSITIVE,
};
static int success_fail_positive(struct range_list *rl)
{
if (!rl)
! return ZERO;
if (sval_is_negative(rl_min(rl)))
return NEGATIVE;
if (rl_min(rl).value == 0)
--- 211,227 ----
param, param_name, "");
} END_FOR_EACH_SM(sm);
}
enum {
! EMPTY, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS
};
static int success_fail_positive(struct range_list *rl)
{
if (!rl)
! return EMPTY;
if (sval_is_negative(rl_min(rl)))
return NEGATIVE;
if (rl_min(rl).value == 0)
*** 155,189 ****
static void check_counter(const char *name, struct symbol *sym)
{
struct range_list *inc_lines = NULL;
struct range_list *dec_lines = NULL;
! int inc_buckets[3] = {};
! struct stree *stree;
struct sm_state *return_sm;
struct sm_state *sm;
sval_t line = sval_type_val(&int_ctype, 0);
FOR_EACH_PTR(get_all_return_strees(), stree) {
! return_sm = get_sm_state_stree(stree, RETURN_ID, "return_ranges", NULL);
if (!return_sm)
! continue;
line.value = return_sm->line;
! sm = get_sm_state_stree(stree, my_id, name, sym);
if (!sm)
! continue;
! if (sm->state != &inc && sm->state != &dec)
! continue;
if (sm->state == &inc) {
add_range(&inc_lines, line, line);
! inc_buckets[success_fail_positive(estate_rl(return_sm->state))] = 1;
}
! if (sm->state == &dec)
add_range(&dec_lines, line, line);
} END_FOR_EACH_PTR(stree);
if (inc_buckets[NEGATIVE] &&
inc_buckets[ZERO]) {
// sm_warning("XXX '%s' not decremented on lines: %s.", name, show_rl(inc_lines));
--- 232,284 ----
static void check_counter(const char *name, struct symbol *sym)
{
struct range_list *inc_lines = NULL;
struct range_list *dec_lines = NULL;
! int inc_buckets[NUM_BUCKETS] = {};
! int dec_buckets[NUM_BUCKETS] = {};
! struct stree *stree, *orig_stree;
struct sm_state *return_sm;
struct sm_state *sm;
sval_t line = sval_type_val(&int_ctype, 0);
+ int bucket;
FOR_EACH_PTR(get_all_return_strees(), stree) {
! orig_stree = __swap_cur_stree(stree);
!
! return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
if (!return_sm)
! goto swap_stree;
line.value = return_sm->line;
! if (get_state_stree(start_states, my_id, name, sym) == &inc)
! goto swap_stree;
!
! if (parent_is_gone_var_sym(name, sym))
! goto swap_stree;
!
! sm = get_sm_state(my_id, name, sym);
if (!sm)
! goto swap_stree;
! if (sm->state != &inc &&
! sm->state != &dec &&
! sm->state != &orig)
! goto swap_stree;
+ bucket = success_fail_positive(estate_rl(return_sm->state));
+
if (sm->state == &inc) {
add_range(&inc_lines, line, line);
! inc_buckets[bucket] = true;
}
! if (sm->state == &dec || sm->state == &orig) {
add_range(&dec_lines, line, line);
+ dec_buckets[bucket] = true;
+ }
+ swap_stree:
+ __swap_cur_stree(orig_stree);
} END_FOR_EACH_PTR(stree);
if (inc_buckets[NEGATIVE] &&
inc_buckets[ZERO]) {
// sm_warning("XXX '%s' not decremented on lines: %s.", name, show_rl(inc_lines));
*** 215,233 ****
--- 310,348 ----
int was_inced(const char *name, struct symbol *sym)
{
return get_state(my_id, name, sym) == &inc;
}
+ static void match_save_states(struct expression *expr)
+ {
+ push_stree(&saved_stack, start_states);
+ start_states = NULL;
+ }
+
+ static void match_restore_states(struct expression *expr)
+ {
+ start_states = pop_stree(&saved_stack);
+ }
+
+ static void match_after_func(struct symbol *sym)
+ {
+ free_stree(&start_states);
+ }
+
void check_atomic_inc_dec(int id)
{
my_id = id;
if (option_project != PROJ_KERNEL)
return;
+ add_unmatched_state_hook(my_id, &unmatched_state);
+
+ add_split_return_callback(match_return_info);
select_return_states_hook(ATOMIC_INC, &db_inc);
select_return_states_hook(ATOMIC_DEC, &db_dec);
+
add_function_hook("atomic_inc_return", &match_atomic_inc, NULL);
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_dec_and_test", &match_atomic_dec, NULL);
*** 235,248 ****
add_function_hook("atomic_dec", &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);
add_function_hook("atomic_sub", &match_atomic_sub, NULL);
- add_split_return_callback(match_return_info);
add_function_hook("refcount_add_not_zero", &refcount_inc, INT_PTR(1));
add_function_hook("refcount_inc_not_zero", &refcount_inc, 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(1));
add_hook(&match_check_missed, END_FUNC_HOOK);
}
--- 350,369 ----
add_function_hook("atomic_dec", &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);
add_function_hook("atomic_sub", &match_atomic_sub, NULL);
+ 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));
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_hook(&match_check_missed, END_FUNC_HOOK);
+
+ add_hook(&match_after_func, AFTER_FUNC_HOOK);
+ add_hook(&match_save_states, INLINE_FN_START);
+ add_hook(&match_restore_states, INLINE_FN_END);
}