check_overflow: test copy_to/from_user as well.
[smatch.git] / check_overflow.c
blob2287bc69c8a0a78ef708b4739e796e0e37944c32
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;
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));
71 static void match_assignment(struct expression *expr)
73 char *name;
74 name = get_variable_from_expr(expr->left, NULL);
75 if (!name)
76 return;
77 if (malloc_size(expr->right) > 0)
78 set_state(name, my_id, NULL, alloc_state(malloc_size(expr->right)));
79 free_string(name);
82 static void match_strcpy(struct expression *expr, void *unused)
84 struct expression *dest;
85 struct expression *data;
86 char *dest_name = NULL;
87 char *data_name = NULL;
88 struct smatch_state *dest_state;
89 struct smatch_state *data_state;
91 dest = get_argument_from_call_expr(expr->args, 0);
92 dest_name = get_variable_from_expr(dest, NULL);
94 data = get_argument_from_call_expr(expr->args, 1);
95 data_name = get_variable_from_expr(data, NULL);
97 dest_state = get_state(dest_name, my_id, NULL);
98 if (!dest_state || !dest_state->data)
99 goto free;
101 data_state = get_state(data_name, my_id, NULL);
102 if (!data_state || !data_state->data)
103 goto free;
105 if (*(int *)dest_state->data < *(int *)data_state->data)
106 smatch_msg("error: %s (%d) too large for %s (%d)", data_name,
107 *(int *)data_state->data,
108 dest_name, *(int *)dest_state->data);
109 free:
110 free_string(dest_name);
111 free_string(data_name);
114 static void match_limitted(struct expression *expr, void *limit_arg)
116 struct expression *dest;
117 struct expression *data;
118 char *dest_name = NULL;
119 struct smatch_state *state;
120 int needed;
121 int has;
123 dest = get_argument_from_call_expr(expr->args, 0);
124 dest_name = get_variable_from_expr(dest, NULL);
126 data = get_argument_from_call_expr(expr->args, (int)limit_arg);
127 needed = get_value(data);
128 state = get_state(dest_name, my_id, NULL);
129 if (!state || !state->data)
130 goto free;
131 has = *(int *)state->data;
132 if (has < needed)
133 smatch_msg("error: %s too small for %d bytes.", dest_name,
134 needed);
135 free:
136 free_string(dest_name);
139 void check_overflow(int id)
141 my_id = id;
142 add_hook(&match_declaration, DECLARATION_HOOK);
143 add_hook(&match_assignment, ASSIGNMENT_HOOK);
144 add_function_hook("strcpy", &match_strcpy, NULL);
145 add_function_hook("strncpy", &match_limitted, (void *)2);
146 add_function_hook("copy_to_user", &match_limitted, (void *)2);
147 add_function_hook("copy_from_user", &match_limitted, (void *)2);