[PATCH] avoid a crash on bad asm statement
[smatch.git] / check.c
blob089833d65c5e8cee45f9fcd47edc2ba1c1d6c402
1 /*
2 * Example trivial client program that uses the sparse library
3 * to tokenize, pre-process and parse a C file, and prints out
4 * the results.
6 * Copyright (C) 2003 Transmeta Corp.
7 * 2003-2004 Linus Torvalds
9 * Licensed under the Open Software License version 1.1
11 #include <stdarg.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <unistd.h>
17 #include <fcntl.h>
19 #include "lib.h"
20 #include "allocate.h"
21 #include "token.h"
22 #include "parse.h"
23 #include "symbol.h"
24 #include "expression.h"
25 #include "linearize.h"
27 static int context_increase(struct basic_block *bb, int entry)
29 int sum = 0;
30 struct instruction *insn;
32 FOR_EACH_PTR(bb->insns, insn) {
33 int val;
34 if (insn->opcode != OP_CONTEXT)
35 continue;
36 val = insn->increment;
37 if (insn->check) {
38 int current = sum + entry;
39 if (!val) {
40 if (!current)
41 continue;
42 } else if (current >= val)
43 continue;
44 warning(insn->pos, "context check failure");
45 continue;
47 sum += val;
48 } END_FOR_EACH_PTR(insn);
49 return sum;
52 static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
54 if (Wcontext) {
55 struct symbol *sym = ep->name;
56 warning(bb->pos, "context imbalance in '%s' - %s", show_ident(sym->ident), why);
58 return -1;
61 static int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit);
63 static int check_children(struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
65 struct instruction *insn;
66 struct basic_block *child;
68 insn = last_instruction(bb->insns);
69 if (!insn)
70 return 0;
71 if (insn->opcode == OP_RET)
72 return entry != exit ? imbalance(ep, bb, entry, exit, "wrong count at exit") : 0;
74 FOR_EACH_PTR(bb->children, child) {
75 if (check_bb_context(ep, child, entry, exit))
76 return -1;
77 } END_FOR_EACH_PTR(child);
78 return 0;
81 static int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
83 if (!bb)
84 return 0;
85 if (bb->context == entry)
86 return 0;
88 /* Now that's not good.. */
89 if (bb->context >= 0)
90 return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block");
92 bb->context = entry;
93 entry += context_increase(bb, entry);
94 if (entry < 0)
95 return imbalance(ep, bb, entry, exit, "unexpected unlock");
97 return check_children(ep, bb, entry, exit);
100 static void check_cast_instruction(struct instruction *insn)
102 struct symbol *orig_type = insn->orig_type;
103 if (orig_type) {
104 int old = orig_type->bit_size;
105 int new = insn->size;
106 int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
107 int newsigned = insn->opcode == OP_SCAST;
109 if (new > old) {
110 if (oldsigned == newsigned)
111 return;
112 if (newsigned)
113 return;
114 warning(insn->pos, "cast loses sign");
115 return;
117 if (new < old) {
118 warning(insn->pos, "cast drops bits");
119 return;
121 if (oldsigned == newsigned) {
122 warning(insn->pos, "cast wasn't removed");
123 return;
125 warning(insn->pos, "cast changes sign");
129 static void check_range_instruction(struct instruction *insn)
131 warning(insn->pos, "value out of range");
134 static void check_byte_count(struct instruction *insn, pseudo_t count)
136 if (count->type == PSEUDO_VAL) {
137 long long val = count->value;
138 if (val <= 0 || val > 100000)
139 warning(insn->pos, "%s with byte count of %lld",
140 show_ident(insn->func->sym->ident), val);
141 return;
143 /* Ok, we could try to do the range analysis here */
146 static pseudo_t argument(struct instruction *call, unsigned int argno)
148 pseudo_t args[8];
149 struct ptr_list *arg_list = (struct ptr_list *) call->arguments;
151 argno--;
152 if (linearize_ptr_list(arg_list, (void *)args, 8) > argno)
153 return args[argno];
154 return NULL;
157 static void check_memset(struct instruction *insn)
159 check_byte_count(insn, argument(insn, 3));
162 #define check_memcpy check_memset
163 #define check_ctu check_memset
164 #define check_cfu check_memset
166 struct checkfn {
167 struct ident *id;
168 void (*check)(struct instruction *insn);
171 static void check_call_instruction(struct instruction *insn)
173 pseudo_t fn = insn->func;
174 struct ident *ident;
175 static const struct checkfn check_fn[] = {
176 { &memset_ident, check_memset },
177 { &memcpy_ident, check_memcpy },
178 { &copy_to_user_ident, check_ctu },
179 { &copy_from_user_ident, check_cfu },
181 int i;
183 if (fn->type != PSEUDO_SYM)
184 return;
185 ident = fn->sym->ident;
186 if (!ident)
187 return;
188 for (i = 0; i < sizeof(check_fn)/sizeof(struct checkfn) ; i++) {
189 if (check_fn[i].id != ident)
190 continue;
191 check_fn[i].check(insn);
192 break;
196 static void check_one_instruction(struct instruction *insn)
198 switch (insn->opcode) {
199 case OP_CAST: case OP_SCAST:
200 if (verbose)
201 check_cast_instruction(insn);
202 break;
203 case OP_RANGE:
204 check_range_instruction(insn);
205 break;
206 case OP_CALL:
207 check_call_instruction(insn);
208 break;
209 default:
210 break;
214 static void check_bb_instructions(struct basic_block *bb)
216 struct instruction *insn;
217 FOR_EACH_PTR(bb->insns, insn) {
218 if (!insn->bb)
219 continue;
220 check_one_instruction(insn);
221 } END_FOR_EACH_PTR(insn);
224 static void check_instructions(struct entrypoint *ep)
226 struct basic_block *bb;
227 FOR_EACH_PTR(ep->bbs, bb) {
228 check_bb_instructions(bb);
229 } END_FOR_EACH_PTR(bb);
232 static void check_context(struct entrypoint *ep)
234 struct symbol *sym = ep->name;
236 if (verbose && ep->entry->bb->needs) {
237 pseudo_t pseudo;
238 FOR_EACH_PTR(ep->entry->bb->needs, pseudo) {
239 if (pseudo->type != PSEUDO_ARG)
240 warning(sym->pos, "%s: possible uninitialized variable (%s)",
241 show_ident(sym->ident), show_pseudo(pseudo));
242 } END_FOR_EACH_PTR(pseudo);
245 check_instructions(ep);
247 check_bb_context(ep, ep->entry->bb, sym->ctype.in_context, sym->ctype.out_context);
250 static void check_symbols(struct symbol_list *list)
252 struct symbol *sym;
254 FOR_EACH_PTR(list, sym) {
255 struct entrypoint *ep;
257 expand_symbol(sym);
258 ep = linearize_symbol(sym);
259 if (ep)
260 check_context(ep);
261 } END_FOR_EACH_PTR(sym);
264 int main(int argc, char **argv)
266 // Expand, linearize and show it.
267 check_symbols(sparse(argc, argv));
268 return 0;