2 * sparse/smatch_param_limit.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
12 #include "smatch_extra.h"
16 static int side_effects
;
18 static struct smatch_state
*orig_states
[16];
22 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
24 return extra_undefined(estate_type(sm
->state
));
27 int was_modified_sym(struct symbol
*sym
)
31 if (!sym
|| !sym
->ident
)
32 return 1; /* safer to say it was modified? */
33 if (get_state(modify_id
, sym
->ident
->name
, sym
))
38 static int is_local(struct symbol
*sym
)
40 if (!sym
->scope
|| !sym
->scope
->token
)
45 static void check_expr(struct expression
*expr
)
47 struct smatch_state
*state
;
51 name
= get_variable_from_expr_complex(expr
, &sym
);
61 * Pointers are so tricky to handle just bail.
63 if (get_real_base_type(sym
)->type
== SYM_PTR
)
67 * TODO: it should only do this if we modify something that's not on the
70 if (get_param_num_from_sym(sym
) >= 0) {
72 if (!get_state_expr(orig_id
, expr
)) {
73 state
= get_implied_estate(expr
);
74 set_state_expr(orig_id
, expr
, state
);
78 set_state_expr(modify_id
, expr
, &modified
);
83 static void match_assign(struct expression
*expr
)
85 check_expr(expr
->left
);
88 static void unop_expr(struct expression
*expr
)
90 if (expr
->op
!= SPECIAL_DECREMENT
&& expr
->op
!= SPECIAL_INCREMENT
)
93 expr
= strip_expr(expr
->unop
);
97 static int no_effect_func
;
98 static int db_no_effect_func(void *unused
, int argc
, char **argv
, char **azColName
)
104 static int is_no_side_effect_func(struct expression
*fn
)
106 static char sql_filter
[1024];
108 if (fn
->type
!= EXPR_SYMBOL
|| !fn
->symbol
)
111 if (fn
->symbol
->ctype
.modifiers
& MOD_STATIC
) {
112 snprintf(sql_filter
, 1024, "file = '%s' and function = '%s';",
113 get_filename(), fn
->symbol
->ident
->name
);
115 snprintf(sql_filter
, 1024, "function = '%s' and static = 0;",
116 fn
->symbol
->ident
->name
);
120 run_sql(db_no_effect_func
, "select * from no_side_effects where %s", sql_filter
);
122 return no_effect_func
;
125 static void match_call(struct expression
*expr
)
127 struct expression
*arg
, *tmp
;
129 if (!is_no_side_effect_func(expr
->fn
))
132 FOR_EACH_PTR(expr
->args
, arg
) {
133 tmp
= strip_expr(arg
);
134 if (tmp
->type
!= EXPR_PREOP
|| tmp
->op
!= '&')
136 tmp
= strip_expr(tmp
->unop
);
138 } END_FOR_EACH_PTR(arg
);
141 static void asm_expr(struct statement
*stmt
)
144 struct expression
*expr
;
147 FOR_EACH_PTR(stmt
->asm_outputs
, expr
) {
149 case 0: /* identifier */
150 case 1: /* constraint */
153 case 2: /* expression */
158 } END_FOR_EACH_PTR(expr
);
161 struct smatch_state
*get_orig_estate(struct symbol
*sym
)
163 struct smatch_state
*state
;
165 if (!sym
->ident
|| !sym
->ident
->name
)
168 state
= get_state(orig_id
, sym
->ident
->name
, sym
);
172 return get_state(SMATCH_EXTRA
, sym
->ident
->name
, sym
);
175 static void match_after_def(struct symbol
*sym
)
177 struct smatch_state
*state
;
182 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
187 orig_states
[param
] = NULL
;
188 state
= get_orig_estate(tmp
);
191 orig_states
[param
] = state
;
192 } END_FOR_EACH_PTR(tmp
);
195 static void print_return_value_param(int return_id
, char *return_ranges
, struct expression
*expr
, struct state_list
*slist
)
197 struct smatch_state
*state
;
202 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
204 state
= get_orig_estate(tmp
);
207 if (range_lists_equiv(estate_ranges(orig_states
[param
]), estate_ranges(state
)))
209 sm_msg("info: return_limited_param %d %d '%s' '$$' '%s' %s",
210 return_id
, param
, return_ranges
,
211 state
->name
, global_static());
212 } END_FOR_EACH_PTR(tmp
);
215 static void match_end_func(struct symbol
*sym
)
217 if (option_info
&& !side_effects
)
218 sm_msg("info: no_side_effects %s", global_static());
222 void register_param_limit(int id
)
226 add_hook(&match_after_def
, AFTER_DEF_HOOK
);
227 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
228 add_hook(&unop_expr
, OP_HOOK
);
229 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
230 add_hook(&asm_expr
, ASM_HOOK
);
231 add_hook(&match_end_func
, END_FUNC_HOOK
);
232 add_returned_state_callback(&print_return_value_param
);
235 void register_param_limit2(int id
)
238 add_merge_hook(orig_id
, &merge_estates
);
239 add_unmatched_state_hook(orig_id
, &unmatched_state
);