Improve how the debug info for merging states gets printed out.
[smatch.git] / check_overflow.c
blobd3a2a085184f17c3cf7627d0f5a0e0fe703fa716
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 int get_value(struct expression *expr, int *discard)
18 int dis = 0;
19 int ret = 0;
21 if (!expr)
22 return 0;
23 if (!discard)
24 discard = &dis;
25 if (*discard)
26 return 0;
28 switch (expr->type){
29 case EXPR_VALUE:
30 ret = expr->value;
31 break;
32 case EXPR_BINOP:
33 if (show_special(expr->op) &&
34 !strcmp("*", show_special(expr->op)))
35 ret = get_value(expr->left, discard)
36 * get_value(expr->right, discard);
37 break;
38 case EXPR_SIZEOF:
39 if (expr->cast_type && get_base_type(expr->cast_type))
40 ret = (get_base_type(expr->cast_type))->bit_size / 8;
41 if (expr->cast_expression)
42 ;//printf("debugs %d\n", expr->cast_expression->type);
43 break;
44 default:
45 //printf("ouchies-->%d\n", expr->type);
46 *discard = 1;
48 if (*discard)
49 return 0;
50 return ret;
53 static int malloc_size(struct expression *expr)
55 char *name;
56 struct expression *arg;
58 if (!expr)
59 return 0;
61 if (expr->type == EXPR_CALL) {
62 name = get_variable_from_expr_simple(expr->fn, NULL);
63 if (name && !strcmp(name, "kmalloc")) {
64 arg = get_argument_from_call_expr(expr->args, 0);
65 return get_value(arg, NULL);
67 } else if (expr->type == EXPR_STRING && expr->string) {
68 return expr->string->length * 8;
70 return 0;
73 static void match_declaration(struct symbol *sym)
75 struct symbol *base_type;
76 char *name;
77 int size;
79 if (!sym->ident)
80 return;
82 name = sym->ident->name;
83 base_type = get_base_type(sym);
85 if (base_type->type == SYM_ARRAY && base_type->bit_size > 0)
86 set_state(name, my_id, NULL, base_type->bit_size / 8);
87 else {
88 size = malloc_size(sym->initializer);
89 if (size)
90 set_state(name, my_id, NULL, size);
94 static void match_assignment(struct expression *expr)
96 char *name;
97 name = get_variable_from_expr_simple(expr->left, NULL);
98 name = alloc_string(name);
99 if (!name)
100 return;
101 if (malloc_size(expr->right))
102 set_state(name, my_id, NULL, malloc_size(expr->right));
105 static void match_fn_call(struct expression *expr)
107 struct expression *dest;
108 struct expression *data;
109 char *fn_name;
110 char *dest_name;
111 char *data_name;
113 fn_name = get_variable_from_expr(expr->fn, NULL);
114 if (!fn_name)
115 return;
117 if (!strcmp(fn_name, "strcpy")) {
118 dest = get_argument_from_call_expr(expr->args, 0);
119 dest_name = get_variable_from_expr(dest, NULL);
120 dest_name = alloc_string(dest_name);
122 data = get_argument_from_call_expr(expr->args, 1);
123 data_name = get_variable_from_expr(data, NULL);
124 data_name = alloc_string(data_name);
126 if (get_state(dest_name, my_id, NULL) < 0)
127 return;
128 if (get_state(dest_name, my_id, NULL)
129 < get_state(data_name, my_id, NULL))
130 smatch_msg("Error %s too large for %s", data_name,
131 dest_name);
132 } else if (!strcmp(fn_name, "strncpy")) {
133 int needed;
134 int has;
136 dest = get_argument_from_call_expr(expr->args, 0);
137 dest_name = get_variable_from_expr(dest, NULL);
138 dest_name = alloc_string(dest_name);
140 data = get_argument_from_call_expr(expr->args, 2);
141 needed = get_value(data, NULL);
142 has = get_state(dest_name, my_id, NULL);
143 if (has > 0 && has < needed)
144 smatch_msg("Error %s too small for %d bytes.",
145 dest_name, needed);
149 void register_overflow(int id)
151 my_id = id;
152 add_hook(&match_declaration, DECLARATION_HOOK);
153 add_hook(&match_assignment, ASSIGNMENT_HOOK);
154 add_hook(&match_fn_call, FUNCTION_CALL_HOOK);