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
;
20 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
22 return extra_undefined(estate_type(sm
->state
));
25 int was_modified_sym(struct symbol
*sym
)
29 if (!sym
|| !sym
->ident
)
30 return 1; /* safer to say it was modified? */
31 if (get_state(modify_id
, sym
->ident
->name
, sym
))
36 static int is_local(struct symbol
*sym
)
38 if (!sym
->scope
|| !sym
->scope
->token
)
43 static void check_expr(struct expression
*expr
)
45 struct smatch_state
*state
;
49 name
= get_variable_from_expr_complex(expr
, &sym
);
59 * Pointers are so tricky to handle just bail.
61 if (get_real_base_type(sym
)->type
== SYM_PTR
)
65 * TODO: it should only do this if we modify something that's not on the
68 if (get_param_num_from_sym(sym
) >= 0) {
70 if (!get_state_expr(orig_id
, expr
)) {
71 state
= get_implied_estate(expr
);
72 set_state_expr(orig_id
, expr
, state
);
76 set_state_expr(modify_id
, expr
, &modified
);
81 static void match_assign(struct expression
*expr
)
83 check_expr(expr
->left
);
86 static void unop_expr(struct expression
*expr
)
88 if (expr
->op
!= SPECIAL_DECREMENT
&& expr
->op
!= SPECIAL_INCREMENT
)
91 expr
= strip_expr(expr
->unop
);
95 static int no_effect_func
;
96 static int db_no_effect_func(void *unused
, int argc
, char **argv
, char **azColName
)
102 static int is_no_side_effect_func(struct expression
*fn
)
104 static char sql_filter
[1024];
106 if (fn
->type
!= EXPR_SYMBOL
|| !fn
->symbol
)
109 if (fn
->symbol
->ctype
.modifiers
& MOD_STATIC
) {
110 snprintf(sql_filter
, 1024, "file = '%s' and function = '%s';",
111 get_filename(), fn
->symbol
->ident
->name
);
113 snprintf(sql_filter
, 1024, "function = '%s' and static = 0;",
114 fn
->symbol
->ident
->name
);
118 run_sql(db_no_effect_func
, "select * from no_side_effects where %s", sql_filter
);
120 return no_effect_func
;
123 static void match_call(struct expression
*expr
)
125 struct expression
*arg
, *tmp
;
127 if (!is_no_side_effect_func(expr
->fn
))
130 FOR_EACH_PTR(expr
->args
, arg
) {
131 tmp
= strip_expr(arg
);
132 if (tmp
->type
!= EXPR_PREOP
|| tmp
->op
!= '&')
134 tmp
= strip_expr(tmp
->unop
);
136 } END_FOR_EACH_PTR(arg
);
139 static void asm_expr(struct statement
*stmt
)
142 struct expression
*expr
;
145 FOR_EACH_PTR(stmt
->asm_outputs
, expr
) {
147 case 0: /* identifier */
148 case 1: /* constraint */
151 case 2: /* expression */
156 } END_FOR_EACH_PTR(expr
);
159 struct smatch_state
*get_orig_estate(struct symbol
*sym
)
161 struct smatch_state
*state
;
163 if (!sym
->ident
|| !sym
->ident
->name
)
166 state
= get_state(orig_id
, sym
->ident
->name
, sym
);
170 return get_state(SMATCH_EXTRA
, sym
->ident
->name
, sym
);
173 static void print_return_value_param(int return_id
, char *return_ranges
, struct expression
*expr
, struct state_list
*slist
)
175 struct smatch_state
*state
;
180 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
182 state
= get_orig_estate(tmp
);
185 sm_msg("info: return_limited_param %d %d '%s' '$$' '%s' %s",
186 return_id
, param
, return_ranges
,
187 state
->name
, global_static());
188 } END_FOR_EACH_PTR(tmp
);
191 static void match_end_func(struct symbol
*sym
)
193 if (option_info
&& !side_effects
)
194 sm_msg("info: no_side_effects %s", global_static());
198 void register_param_limit(int id
)
202 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
203 add_hook(&unop_expr
, OP_HOOK
);
204 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
205 add_hook(&asm_expr
, ASM_HOOK
);
206 add_hook(&match_end_func
, END_FUNC_HOOK
);
207 add_returned_state_callback(&print_return_value_param
);
210 void register_param_limit2(int id
)
213 add_merge_hook(orig_id
, &merge_estates
);
214 add_unmatched_state_hook(orig_id
, &unmatched_state
);