implied: handle &undefined better
[smatch.git] / check_overflow.c
blob6d6891950c610d8f888cbb292ad5834c6b8a87c7
1 /*
2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include "parse.h"
12 #include "smatch.h"
14 static int my_id;
16 static struct smatch_state *alloc_state(int val)
18 struct smatch_state *state;
20 state = malloc(sizeof(*state));
21 state->name = "value";
22 state->data = malloc(sizeof(int));
23 *(int *)state->data = val;
24 return state;
27 static int malloc_size(struct expression *expr)
29 char *name;
30 struct expression *arg;
32 if (!expr)
33 return 0;
35 if (expr->type == EXPR_CALL) {
36 name = get_variable_from_expr(expr->fn, NULL);
37 if (name && !strcmp(name, "kmalloc")) {
38 arg = get_argument_from_call_expr(expr->args, 0);
39 free_string(name);
40 return get_value(arg);
42 free_string(name);
43 } else if (expr->type == EXPR_STRING && expr->string) {
44 return expr->string->length * 8;
46 return 0;
49 static void match_declaration(struct symbol *sym)
51 struct symbol *base_type;
52 char *name;
53 int size;
55 if (!sym->ident)
56 return;
58 name = sym->ident->name;
59 base_type = get_base_type(sym);
61 if (base_type->type == SYM_ARRAY && base_type->bit_size > 0)
62 set_state(name, my_id, NULL, alloc_state(base_type->bit_size / 8));
63 else {
64 size = malloc_size(sym->initializer);
65 if (size > 0)
66 set_state(name, my_id, NULL, alloc_state(size));
70 static void match_assignment(struct expression *expr)
72 char *name;
73 name = get_variable_from_expr(expr->left, NULL);
74 if (!name)
75 return;
76 if (malloc_size(expr->right) > 0)
77 set_state(name, my_id, NULL, alloc_state(malloc_size(expr->right)));
78 free_string(name);
81 static void match_fn_call(struct expression *expr)
83 struct expression *dest;
84 struct expression *data;
85 char *fn_name;
86 char *dest_name;
87 char *data_name;
89 fn_name = get_variable_from_expr(expr->fn, NULL);
90 if (!fn_name)
91 return;
93 if (!strcmp(fn_name, "strcpy")) {
94 struct smatch_state *dest_state;
95 struct smatch_state *data_state;
97 dest = get_argument_from_call_expr(expr->args, 0);
98 dest_name = get_variable_from_expr(dest, NULL);
100 data = get_argument_from_call_expr(expr->args, 1);
101 data_name = get_variable_from_expr(data, NULL);
103 dest_state = get_state(dest_name, my_id, NULL);
104 if (!dest_state || !dest_state->data) {
105 free_string(dest_name);
106 free_string(data_name);
107 return;
109 data_state = get_state(data_name, my_id, NULL);
110 if (!data_state || !data_state->data) {
111 free_string(dest_name);
112 free_string(data_name);
113 return;
116 if (*(int *)dest_state->data < *(int *)data_state->data)
117 smatch_msg("error: %s too large for %s", data_name,
118 dest_name);
119 free_string(dest_name);
120 free_string(data_name);
121 } else if (!strcmp(fn_name, "strncpy")) {
122 struct smatch_state *state;
123 int needed;
124 int has;
126 dest = get_argument_from_call_expr(expr->args, 0);
127 dest_name = get_variable_from_expr(dest, NULL);
129 data = get_argument_from_call_expr(expr->args, 2);
130 needed = get_value(data);
131 state = get_state(dest_name, my_id, NULL);
132 if (!state || !state->data)
133 return;
134 has = *(int *)state->data;
135 if (has < needed)
136 smatch_msg("error: %s too small for %d bytes.",
137 dest_name, needed);
138 free_string(dest_name);
140 free_string(fn_name);
143 void register_overflow(int id)
145 my_id = id;
146 add_hook(&match_declaration, DECLARATION_HOOK);
147 add_hook(&match_assignment, ASSIGNMENT_HOOK);
148 add_hook(&match_fn_call, FUNCTION_CALL_HOOK);