Clean up. Fix leak. My problem is that I don't understand pointers
[smatch.git] / check_overflow.c
blob61653e357d62e34843a52fb2ebd78524408aa02d
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_simple(expr->fn, NULL);
37 if (name && !strcmp(name, "kmalloc")) {
38 arg = get_argument_from_call_expr(expr->args, 0);
39 return get_value(arg, NULL);
41 } else if (expr->type == EXPR_STRING && expr->string) {
42 return expr->string->length * 8;
44 return 0;
47 static void match_declaration(struct symbol *sym)
49 struct symbol *base_type;
50 char *name;
51 int size;
53 if (!sym->ident)
54 return;
56 name = sym->ident->name;
57 base_type = get_base_type(sym);
59 if (base_type->type == SYM_ARRAY && base_type->bit_size > 0)
60 set_state(name, my_id, NULL, alloc_state(base_type->bit_size / 8));
61 else {
62 size = malloc_size(sym->initializer);
63 if (size > 0)
64 set_state(name, my_id, NULL, alloc_state(size));
68 static void match_assignment(struct expression *expr)
70 char *name;
71 name = get_variable_from_expr_simple(expr->left, NULL);
72 name = alloc_string(name);
73 if (!name)
74 return;
75 if (malloc_size(expr->right) > 0)
76 set_state(name, my_id, NULL, alloc_state(malloc_size(expr->right)));
79 static void match_fn_call(struct expression *expr)
81 struct expression *dest;
82 struct expression *data;
83 char *fn_name;
84 char *dest_name;
85 char *data_name;
87 fn_name = get_variable_from_expr(expr->fn, NULL);
88 if (!fn_name)
89 return;
91 if (!strcmp(fn_name, "strcpy")) {
92 struct smatch_state *dest_state;
93 struct smatch_state *data_state;
95 dest = get_argument_from_call_expr(expr->args, 0);
96 dest_name = get_variable_from_expr(dest, NULL);
97 dest_name = alloc_string(dest_name);
99 data = get_argument_from_call_expr(expr->args, 1);
100 data_name = get_variable_from_expr(data, NULL);
101 data_name = alloc_string(data_name);
103 dest_state = get_state(dest_name, my_id, NULL);
104 if (!dest_state || !dest_state->data) {
105 return;
107 data_state = get_state(data_name, my_id, NULL);
108 if (!data_state || !data_state->data) {
109 return;
112 if (*(int *)dest_state->data < *(int *)data_state->data)
113 smatch_msg("Error %s too large for %s", data_name,
114 dest_name);
115 } else if (!strcmp(fn_name, "strncpy")) {
116 struct smatch_state *state;
117 int needed;
118 int has;
120 dest = get_argument_from_call_expr(expr->args, 0);
121 dest_name = get_variable_from_expr(dest, NULL);
122 dest_name = alloc_string(dest_name);
124 data = get_argument_from_call_expr(expr->args, 2);
125 needed = get_value(data, NULL);
126 state = get_state(dest_name, my_id, NULL);
127 if (!state || !state->data)
128 return;
129 has = *(int *)state->data;
130 if (has < needed)
131 smatch_msg("Error %s too small for %d bytes.",
132 dest_name, needed);
136 void register_overflow(int id)
138 my_id = id;
139 add_hook(&match_declaration, DECLARATION_HOOK);
140 add_hook(&match_assignment, ASSIGNMENT_HOOK);
141 add_hook(&match_fn_call, FUNCTION_CALL_HOOK);