overflow: update validation test
[smatch.git] / check_bit_shift.c
blob507358eef814f9330c40875b791d2eac971d3195
1 /*
2 * smatch/check_bit_shift.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
11 #include "smatch_function_hashtable.h"
13 static int my_id;
15 static DEFINE_HASHTABLE_INSERT(insert_struct, char, int);
16 static DEFINE_HASHTABLE_SEARCH(search_struct, char, int);
17 static struct hashtable *shifters;
19 static const char *get_shifter(struct expression *expr)
21 const char *name;
22 long long expr_value;
23 const int *shifter_value;
25 expr = strip_expr(expr);
26 if (expr->type != EXPR_VALUE)
27 return NULL;
28 if (!get_value(expr, &expr_value))
29 return NULL;
30 name = pos_ident(expr->pos);
31 if (!name)
32 return NULL;
33 shifter_value = search_struct(shifters, (char *)name);
34 if (!shifter_value)
35 return NULL;
36 if (*shifter_value != expr_value)
37 return NULL;
38 return name;
41 static void match_assign(struct expression *expr)
43 const char *name;
45 if (expr->op != SPECIAL_OR_ASSIGN)
46 return;
47 if (positions_eq(expr->pos, expr->right->pos))
48 return;
49 name = get_shifter(expr->right);
50 if (!name)
51 return;
53 sm_msg("warn: '%s' is a shifter (not for '%s').",
54 name, show_special(expr->op));
57 static void match_binop(struct expression *expr)
59 const char *name;
61 if (positions_eq(expr->pos, expr->right->pos))
62 return;
63 if (expr->op != '&')
64 return;
65 name = get_shifter(expr->right);
66 if (!name)
67 return;
69 sm_msg("warn: bit shifter '%s' used for logical '%s'",
70 name, show_special(expr->op));
73 static void register_shifters(void)
75 char filename[256];
76 struct token *token;
77 char *name;
78 int *val;
80 snprintf(filename, sizeof(filename), "%s.bit_shifters", option_project_str);
81 token = get_tokens_file(filename);
82 if (!token)
83 return;
84 if (token_type(token) != TOKEN_STREAMBEGIN)
85 return;
86 token = token->next;
87 while (token_type(token) != TOKEN_STREAMEND) {
88 if (token_type(token) != TOKEN_IDENT)
89 return;
90 name = alloc_string(show_ident(token->ident));
91 token = token->next;
92 if (token_type(token) != TOKEN_NUMBER)
93 return;
94 val = malloc(sizeof(int));
95 *val = atoi(token->number);
96 insert_struct(shifters, name, val);
97 token = token->next;
99 clear_token_alloc();
102 static void match_binop_info(struct expression *expr)
104 char *name;
105 long long val;
107 if (positions_eq(expr->pos, expr->right->pos))
108 return;
109 if (expr->op != SPECIAL_LEFTSHIFT)
110 return;
111 if (expr->right->type != EXPR_VALUE)
112 return;
113 name = pos_ident(expr->right->pos);
114 if (!name)
115 return;
116 if (!get_value(expr->right, &val))
117 return;
118 sm_msg("info: bit shifter '%s' '%lld'", name, val);
121 static void match_call(const char *fn, struct expression *expr, void *_arg_no)
123 struct expression *arg_expr;
124 int arg_no = PTR_INT(_arg_no);
125 long long val;
126 char *name;
128 arg_expr = get_argument_from_call_expr(expr->args, arg_no);
129 if (positions_eq(expr->pos, arg_expr->pos))
130 return;
131 name = pos_ident(arg_expr->pos);
132 if (!name)
133 return;
134 if (!get_value(arg_expr, &val))
135 return;
136 sm_msg("info: bit shifter '%s' '%lld'", name, val);
139 void check_bit_shift(int id)
141 my_id = id;
143 shifters = create_function_hashtable(5000);
144 register_shifters();
146 add_hook(&match_assign, ASSIGNMENT_HOOK);
147 add_hook(&match_binop, BINOP_HOOK);
149 if (option_info) {
150 add_hook(&match_binop_info, BINOP_HOOK);
151 if (option_project == PROJ_KERNEL) {
152 add_function_hook("set_bit", &match_call, INT_PTR(0));
153 add_function_hook("test_bit", &match_call, INT_PTR(0));