Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/sparse.c
+++ new/usr/src/tools/smatch/src/sparse.c
1 1 /*
2 2 * Example trivial client program that uses the sparse library
3 3 * to tokenize, preprocess and parse a C file, and prints out
4 4 * the results.
5 5 *
6 6 * Copyright (C) 2003 Transmeta Corp.
7 7 * 2003-2004 Linus Torvalds
8 8 *
9 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 10 * of this software and associated documentation files (the "Software"), to deal
11 11 * in the Software without restriction, including without limitation the rights
12 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 13 * copies of the Software, and to permit persons to whom the Software is
14 14 * furnished to do so, subject to the following conditions:
15 15 *
16 16 * The above copyright notice and this permission notice shall be included in
17 17 * all copies or substantial portions of the Software.
18 18 *
19 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 25 * THE SOFTWARE.
26 26 */
27 27 #include <stdarg.h>
28 28 #include <stdlib.h>
29 29 #include <stdio.h>
30 30 #include <string.h>
31 31 #include <ctype.h>
32 32 #include <unistd.h>
33 33 #include <fcntl.h>
34 34
35 35 #include "lib.h"
36 36 #include "allocate.h"
37 37 #include "token.h"
38 38 #include "parse.h"
39 39 #include "symbol.h"
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
40 40 #include "expression.h"
41 41 #include "linearize.h"
42 42
43 43 static int context_increase(struct basic_block *bb, int entry)
44 44 {
45 45 int sum = 0;
46 46 struct instruction *insn;
47 47
48 48 FOR_EACH_PTR(bb->insns, insn) {
49 49 int val;
50 + if (!insn->bb)
51 + continue;
50 52 if (insn->opcode != OP_CONTEXT)
51 53 continue;
52 54 val = insn->increment;
53 55 if (insn->check) {
54 56 int current = sum + entry;
55 57 if (!val) {
56 58 if (!current)
57 59 continue;
58 60 } else if (current >= val)
59 61 continue;
60 62 warning(insn->pos, "context check failure");
61 63 continue;
62 64 }
63 65 sum += val;
64 66 } END_FOR_EACH_PTR(insn);
65 67 return sum;
66 68 }
67 69
68 70 static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
69 71 {
70 72 if (Wcontext) {
71 73 struct symbol *sym = ep->name;
72 74 warning(bb->pos, "context imbalance in '%s' - %s", show_ident(sym->ident), why);
73 75 }
74 76 return -1;
75 77 }
76 78
77 79 static int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit);
78 80
79 81 static int check_children(struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
80 82 {
81 83 struct instruction *insn;
82 84 struct basic_block *child;
83 85
84 86 insn = last_instruction(bb->insns);
85 87 if (!insn)
86 88 return 0;
87 89 if (insn->opcode == OP_RET)
88 90 return entry != exit ? imbalance(ep, bb, entry, exit, "wrong count at exit") : 0;
89 91
90 92 FOR_EACH_PTR(bb->children, child) {
91 93 if (check_bb_context(ep, child, entry, exit))
92 94 return -1;
93 95 } END_FOR_EACH_PTR(child);
94 96 return 0;
95 97 }
96 98
97 99 static int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
98 100 {
99 101 if (!bb)
100 102 return 0;
101 103 if (bb->context == entry)
102 104 return 0;
103 105
104 106 /* Now that's not good.. */
105 107 if (bb->context >= 0)
106 108 return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block");
107 109
108 110 bb->context = entry;
109 111 entry += context_increase(bb, entry);
110 112 if (entry < 0)
111 113 return imbalance(ep, bb, entry, exit, "unexpected unlock");
112 114
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
113 115 return check_children(ep, bb, entry, exit);
114 116 }
115 117
116 118 static void check_cast_instruction(struct instruction *insn)
117 119 {
118 120 struct symbol *orig_type = insn->orig_type;
119 121 if (orig_type) {
120 122 int old = orig_type->bit_size;
121 123 int new = insn->size;
122 124 int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
123 - int newsigned = insn->opcode == OP_SCAST;
125 + int newsigned = insn->opcode == OP_SEXT;
124 126
125 127 if (new > old) {
126 128 if (oldsigned == newsigned)
127 129 return;
128 130 if (newsigned)
129 131 return;
130 132 warning(insn->pos, "cast loses sign");
131 133 return;
132 134 }
133 135 if (new < old) {
134 136 warning(insn->pos, "cast drops bits");
135 137 return;
136 138 }
137 139 if (oldsigned == newsigned) {
138 140 warning(insn->pos, "cast wasn't removed");
139 141 return;
140 142 }
141 143 warning(insn->pos, "cast changes sign");
142 144 }
143 145 }
144 146
145 147 static void check_range_instruction(struct instruction *insn)
146 148 {
147 149 warning(insn->pos, "value out of range");
148 150 }
149 151
150 152 static void check_byte_count(struct instruction *insn, pseudo_t count)
151 153 {
152 154 if (!count)
153 155 return;
154 156 if (count->type == PSEUDO_VAL) {
155 157 unsigned long long val = count->value;
156 158 if (Wmemcpy_max_count && val > fmemcpy_max_count)
157 159 warning(insn->pos, "%s with byte count of %llu",
158 160 show_ident(insn->func->sym->ident), val);
159 161 return;
160 162 }
161 163 /* OK, we could try to do the range analysis here */
162 164 }
163 165
164 166 static pseudo_t argument(struct instruction *call, unsigned int argno)
165 167 {
166 168 pseudo_t args[8];
167 169 struct ptr_list *arg_list = (struct ptr_list *) call->arguments;
168 170
169 171 argno--;
170 172 if (linearize_ptr_list(arg_list, (void *)args, 8) > argno)
171 173 return args[argno];
172 174 return NULL;
173 175 }
174 176
175 177 static void check_memset(struct instruction *insn)
176 178 {
177 179 check_byte_count(insn, argument(insn, 3));
178 180 }
179 181
180 182 #define check_memcpy check_memset
181 183 #define check_ctu check_memset
182 184 #define check_cfu check_memset
183 185
184 186 struct checkfn {
185 187 struct ident *id;
186 188 void (*check)(struct instruction *insn);
187 189 };
188 190
189 191 static void check_call_instruction(struct instruction *insn)
190 192 {
191 193 pseudo_t fn = insn->func;
192 194 struct ident *ident;
193 195 static const struct checkfn check_fn[] = {
194 196 { &memset_ident, check_memset },
195 197 { &memcpy_ident, check_memcpy },
196 198 { ©_to_user_ident, check_ctu },
197 199 { ©_from_user_ident, check_cfu },
198 200 };
199 201 int i;
200 202
201 203 if (fn->type != PSEUDO_SYM)
202 204 return;
203 205 ident = fn->sym->ident;
204 206 if (!ident)
205 207 return;
206 208 for (i = 0; i < ARRAY_SIZE(check_fn); i++) {
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
207 209 if (check_fn[i].id != ident)
208 210 continue;
209 211 check_fn[i].check(insn);
210 212 break;
211 213 }
212 214 }
213 215
214 216 static void check_one_instruction(struct instruction *insn)
215 217 {
216 218 switch (insn->opcode) {
217 - case OP_CAST: case OP_SCAST:
219 + case OP_SEXT: case OP_ZEXT:
220 + case OP_TRUNC:
218 221 if (verbose)
219 222 check_cast_instruction(insn);
220 223 break;
221 224 case OP_RANGE:
222 225 check_range_instruction(insn);
223 226 break;
224 227 case OP_CALL:
225 228 check_call_instruction(insn);
226 229 break;
227 230 default:
228 231 break;
229 232 }
230 233 }
231 234
232 235 static void check_bb_instructions(struct basic_block *bb)
233 236 {
234 237 struct instruction *insn;
235 238 FOR_EACH_PTR(bb->insns, insn) {
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
236 239 if (!insn->bb)
237 240 continue;
238 241 check_one_instruction(insn);
239 242 } END_FOR_EACH_PTR(insn);
240 243 }
241 244
242 245 static void check_instructions(struct entrypoint *ep)
243 246 {
244 247 struct basic_block *bb;
245 248 FOR_EACH_PTR(ep->bbs, bb) {
249 + bb->context = -1;
246 250 check_bb_instructions(bb);
247 251 } END_FOR_EACH_PTR(bb);
248 252 }
249 253
250 254 static void check_context(struct entrypoint *ep)
251 255 {
252 256 struct symbol *sym = ep->name;
253 257 struct context *context;
254 258 unsigned int in_context = 0, out_context = 0;
255 259
256 260 if (Wuninitialized && verbose && ep->entry->bb->needs) {
257 261 pseudo_t pseudo;
258 262 FOR_EACH_PTR(ep->entry->bb->needs, pseudo) {
259 263 if (pseudo->type != PSEUDO_ARG)
260 264 warning(sym->pos, "%s: possible uninitialized variable (%s)",
261 265 show_ident(sym->ident), show_pseudo(pseudo));
262 266 } END_FOR_EACH_PTR(pseudo);
263 267 }
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
264 268
265 269 check_instructions(ep);
266 270
267 271 FOR_EACH_PTR(sym->ctype.contexts, context) {
268 272 in_context += context->in;
269 273 out_context += context->out;
270 274 } END_FOR_EACH_PTR(context);
271 275 check_bb_context(ep, ep->entry->bb, in_context, out_context);
272 276 }
273 277
278 +/* list_compound_symbol - symbol info for arrays, structures, unions */
279 +static void list_compound_symbol(struct symbol *sym)
280 +{
281 + struct symbol *base;
282 +
283 + /* Only show symbols that have a positive size */
284 + if (sym->bit_size <= 0)
285 + return;
286 + if (!sym->ctype.base_type)
287 + return;
288 + /* Don't show unnamed types */
289 + if (!sym->ident)
290 + return;
291 +
292 + if (sym->type == SYM_NODE)
293 + base = sym->ctype.base_type;
294 + else
295 + base = sym;
296 + switch (base->type) {
297 + case SYM_STRUCT: case SYM_UNION: case SYM_ARRAY:
298 + break;
299 + default:
300 + return;
301 + }
302 +
303 + info(sym->pos, "%s: compound size %u, alignment %lu",
304 + show_typename(sym),
305 + bits_to_bytes(sym->bit_size),
306 + sym->ctype.alignment);
307 +}
308 +
274 309 static void check_symbols(struct symbol_list *list)
275 310 {
276 311 struct symbol *sym;
277 312
278 313 FOR_EACH_PTR(list, sym) {
279 314 struct entrypoint *ep;
280 315
281 316 expand_symbol(sym);
282 317 ep = linearize_symbol(sym);
283 - if (ep) {
318 + if (ep && ep->entry) {
284 319 if (dbg_entry)
285 320 show_entry(ep);
286 321
287 322 check_context(ep);
288 323 }
324 + if (dbg_compound)
325 + list_compound_symbol(sym);
289 326 } END_FOR_EACH_PTR(sym);
290 327
291 328 if (Wsparse_error && die_if_error)
292 329 exit(1);
293 330 }
294 331
295 332 int main(int argc, char **argv)
296 333 {
297 334 struct string_list *filelist = NULL;
298 335 char *file;
299 336
337 + // by default ignore -o <file>
338 + do_output = 0;
339 +
300 340 // Expand, linearize and show it.
301 341 check_symbols(sparse_initialize(argc, argv, &filelist));
302 - FOR_EACH_PTR_NOTAG(filelist, file) {
342 + FOR_EACH_PTR(filelist, file) {
303 343 check_symbols(sparse(file));
304 - } END_FOR_EACH_PTR_NOTAG(file);
344 + } END_FOR_EACH_PTR(file);
305 345
306 346 report_stats();
307 347 return 0;
308 348 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX