signed: allow checks like: if (foo < 0 || foo > x) { for unsigned "foo"
[smatch.git] / check_access_ok_math.c
blob10daee93ba792f010d37e798ecfe0e59d8933779
1 /*
2 * smatch/check_access_ok_math.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
12 static int my_id;
13 extern int check_assigned_expr_id;
15 static struct expression *get_assigned_expr(struct expression *expr)
17 struct smatch_state *state;
19 state = get_state_expr(check_assigned_expr_id, expr);
20 if (!state)
21 return NULL;
22 return (struct expression *)state->data;
25 static int can_overflow(struct expression *expr)
27 long long max;
28 int uncapped = 0;
30 expr = strip_expr(expr);
32 if (expr->type == EXPR_BINOP) {
33 uncapped += can_overflow(expr->left);
34 uncapped += can_overflow(expr->right);
36 if (uncapped &&
37 (expr->op == '+' || expr->op == '*' || expr->op == SPECIAL_LEFTSHIFT))
38 return 1;
40 return 0;
43 if (get_implied_max(expr, &max))
44 return 0;
45 if (get_absolute_max(expr, &max) && max <= 4096)
46 return 0;
47 return 1;
50 static void match_size(struct expression *size_expr)
52 char *name;
54 size_expr = strip_expr(size_expr);
55 if (!size_expr)
56 return;
57 if (size_expr->type != EXPR_BINOP) {
58 size_expr = get_assigned_expr(size_expr);
59 if (!size_expr || size_expr->type != EXPR_BINOP)
60 return;
62 if (!can_overflow(size_expr))
63 return;
65 name = get_variable_from_expr_complex(size_expr, NULL);
66 sm_msg("warn: math in access_ok() is dangerous '%s'", name);
68 free_string(name);
71 static void match_access_ok(const char *fn, struct expression *expr, void *data)
73 struct expression *size_expr;
75 size_expr = get_argument_from_call_expr(expr->args, 1);
76 match_size(size_expr);
79 static void split_asm_constraints(struct expression_list *expr_list)
81 struct expression *expr;
82 int state = 0;
83 int i;
85 i = 0;
86 FOR_EACH_PTR(expr_list, expr) {
88 switch (state) {
89 case 0: /* identifier */
90 case 1: /* constraint */
91 state++;
92 continue;
93 case 2: /* expression */
94 state = 0;
95 if (i == 1)
96 match_size(expr);
97 i++;
98 continue;
100 } END_FOR_EACH_PTR(expr);
103 static void match_asm_stmt(struct statement *stmt)
105 char *name;
107 name = get_macro_name(&stmt->pos);
108 if (!name || strcmp(name, "access_ok") != 0)
109 return;
110 split_asm_constraints(stmt->asm_inputs);
113 void check_access_ok_math(int id)
115 my_id = id;
116 if (option_project != PROJ_KERNEL)
117 return;
118 add_function_hook("__access_ok", &match_access_ok, NULL);
119 add_hook(&match_asm_stmt, ASM_HOOK);