extra, db: don't use PARAM_VALUE for return states
[smatch.git] / smatch_address.c
blob901cd9bb2c3b87632e666720d5a3cf2b1d61151c
1 /*
2 * Copyright (C) 2015 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
22 static bool is_non_null_array(struct expression *expr)
24 struct symbol *type;
25 struct symbol *sym;
26 struct symbol *tmp;
27 char *name;
28 int i;
30 type = get_type(expr);
31 if (!type || type->type != SYM_ARRAY)
32 return 0;
33 if (expr->type == EXPR_SYMBOL)
34 return 1;
35 if (implied_not_equal(expr, 0))
36 return 1;
38 /* verify that it's not the first member of the struct */
39 if (expr->type != EXPR_DEREF || !expr->member)
40 return 0;
41 name = expr_to_var_sym(expr, &sym);
42 free_string(name);
43 if (!name || !sym)
44 return 0;
45 type = get_real_base_type(sym);
46 if (!type || type->type != SYM_PTR)
47 return 0;
48 type = get_real_base_type(type);
49 if (type->type != SYM_STRUCT)
50 return 0;
52 i = 0;
53 FOR_EACH_PTR(type->symbol_list, tmp) {
54 i++;
55 if (!tmp->ident)
56 continue;
57 if (strcmp(expr->member->name, tmp->ident->name) == 0) {
58 if (i == 1)
59 return 0;
60 return 1;
62 } END_FOR_EACH_PTR(tmp);
64 return 0;
67 static int get_member_offset(struct expression *expr)
69 struct symbol *type, *tmp;
70 struct ident *member;
71 int offset;
73 if (expr->type != EXPR_DEREF) /* hopefully, this doesn't happen */
74 return 0;
76 member = expr->member;
77 if (!member || !member->name)
78 return 0;
80 if (expr->member_offset >= 0)
81 return expr->member_offset;
83 type = get_type(expr->deref);
84 if (!type || type->type != SYM_STRUCT)
85 return 0;
87 offset = 0;
88 FOR_EACH_PTR(type->symbol_list, tmp) {
89 if (tmp->ident && tmp->ident->name &&
90 strcmp(member->name, tmp->ident->name) == 0) {
91 expr->member_offset = offset;
92 return offset;
94 offset += type_bytes(tmp);
95 } END_FOR_EACH_PTR(tmp);
96 return 0;
99 static void add_offset_to_min(struct range_list **rl, int offset)
101 sval_t sval, max;
102 struct range_list *orig = *rl;
103 struct range_list *offset_rl;
104 struct range_list *big_rl;
105 struct range_list *tmp;
108 * I don't know. I guess I want to preserve the upper value because
109 * that has no information. Only the lower value is interesting.
112 if (!orig)
113 return;
114 sval = rl_min(orig); /* get the type */
115 sval.value = offset;
117 offset_rl = alloc_rl(sval, sval);
118 tmp = rl_binop(orig, '+', offset_rl);
120 max = rl_max(orig);
121 /* if we actually "know" the max then preserve it. */
122 if (max.value < 100000) {
123 *rl = tmp;
124 return;
126 sval.value = 0;
127 big_rl = alloc_rl(sval, max);
129 *rl = rl_intersection(tmp, big_rl);
132 static struct range_list *where_allocated_rl(struct symbol *sym)
134 if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)) {
135 if (sym->initializer)
136 return alloc_rl(data_seg_min, data_seg_max);
137 else
138 return alloc_rl(bss_seg_min, bss_seg_max);
140 return alloc_rl(stack_seg_min, stack_seg_max);
143 int get_address_rl(struct expression *expr, struct range_list **rl)
145 expr = strip_expr(expr);
146 if (!expr)
147 return 0;
149 if (expr->type == EXPR_STRING) {
150 *rl = alloc_rl(text_seg_min, text_seg_max);
151 return 1;
154 if (expr->type == EXPR_PREOP && expr->op == '&') {
155 struct expression *unop;
157 unop = strip_expr(expr->unop);
158 if (unop->type == EXPR_SYMBOL) {
159 *rl = where_allocated_rl(unop->symbol);
160 return 1;
163 if (unop->type == EXPR_DEREF) {
164 int offset = get_member_offset(unop);
166 unop = strip_expr(unop->unop);
167 if (unop->type == EXPR_SYMBOL) {
168 *rl = where_allocated_rl(unop->symbol);
169 } else if (unop->type == EXPR_PREOP && unop->op == '*') {
170 unop = strip_expr(unop->unop);
171 get_absolute_rl(unop, rl);
172 } else {
173 return 0;
176 add_offset_to_min(rl, offset);
177 return 1;
180 return 0;
183 if (is_non_null_array(expr)) {
184 *rl = alloc_rl(array_min_sval, array_max_sval);
185 return 1;
188 return 0;