Warn on double lock/unlocks.
[smatch.git] / check_overflow.c
blob617219463b1145581f9e8f83d9823cf3d97a030d
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 return get_value(arg);
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(expr->left, NULL);
72 if (!name)
73 return;
74 if (malloc_size(expr->right) > 0)
75 set_state(name, my_id, NULL, alloc_state(malloc_size(expr->right)));
78 static void match_fn_call(struct expression *expr)
80 struct expression *dest;
81 struct expression *data;
82 char *fn_name;
83 char *dest_name;
84 char *data_name;
86 fn_name = get_variable_from_expr(expr->fn, NULL);
87 if (!fn_name)
88 return;
90 if (!strcmp(fn_name, "strcpy")) {
91 struct smatch_state *dest_state;
92 struct smatch_state *data_state;
94 dest = get_argument_from_call_expr(expr->args, 0);
95 dest_name = get_variable_from_expr(dest, NULL);
97 data = get_argument_from_call_expr(expr->args, 1);
98 data_name = get_variable_from_expr(data, NULL);
100 dest_state = get_state(dest_name, my_id, NULL);
101 if (!dest_state || !dest_state->data) {
102 return;
104 data_state = get_state(data_name, my_id, NULL);
105 if (!data_state || !data_state->data) {
106 return;
109 if (*(int *)dest_state->data < *(int *)data_state->data)
110 smatch_msg("Error %s too large for %s", data_name,
111 dest_name);
112 } else if (!strcmp(fn_name, "strncpy")) {
113 struct smatch_state *state;
114 int needed;
115 int has;
117 dest = get_argument_from_call_expr(expr->args, 0);
118 dest_name = get_variable_from_expr(dest, NULL);
120 data = get_argument_from_call_expr(expr->args, 2);
121 needed = get_value(data);
122 state = get_state(dest_name, my_id, NULL);
123 if (!state || !state->data)
124 return;
125 has = *(int *)state->data;
126 if (has < needed)
127 smatch_msg("Error %s too small for %d bytes.",
128 dest_name, needed);
132 void register_overflow(int id)
134 my_id = id;
135 add_hook(&match_declaration, DECLARATION_HOOK);
136 add_hook(&match_assignment, ASSIGNMENT_HOOK);
137 add_hook(&match_fn_call, FUNCTION_CALL_HOOK);