expressions: make assign_expression() take an op argument
[smatch.git] / check_spectre.c
blobe1a1167647c24e396ecaa4453870a33aa730041b
1 /*
2 * Copyright (C) 2018 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include "smatch.h"
19 #include "smatch_extra.h"
21 static int my_id;
23 static int is_write(struct expression *expr)
25 return 0;
28 static int is_read(struct expression *expr)
30 struct expression *parent, *last_parent;
31 struct statement *stmt;
33 if (is_write(expr))
34 return 0;
36 last_parent = expr;
37 while ((parent = expr_get_parent_expr(expr))){
39 last_parent = parent;
41 /* If we pass a value as a parameter that's a read, probably? */
42 // if (parent->type == EXPR_CALL)
43 // return 1;
45 if (parent->type == EXPR_ASSIGNMENT) {
46 if (parent->right == expr)
47 return 1;
48 if (parent->left == expr)
49 return 0;
51 expr = parent;
54 stmt = expr_get_parent_stmt(last_parent);
55 if (stmt && stmt->type == STMT_RETURN)
56 return 1;
58 return 0;
61 static unsigned long long get_max_by_type(struct expression *expr)
63 sval_t max = {
64 .type = &ullong_ctype,
65 .uvalue = -1ULL,
67 struct symbol *type;
68 int cnt = 0;
70 while (true) {
71 expr = strip_parens(expr);
72 type = get_type(expr);
73 if (type && sval_type_max(type).uvalue < max.uvalue)
74 max = sval_type_max(type);
75 if (expr->type == EXPR_PREOP) {
76 expr = expr->unop;
77 } else if (expr->type == EXPR_BINOP) {
78 if (expr->op == '%' || expr->op == '&')
79 expr = expr->right;
80 else
81 return max.uvalue;
82 } else {
83 expr = get_assigned_expr(expr);
84 if (!expr)
85 return max.uvalue;
87 if (cnt++ > 5)
88 return max.uvalue;
91 return max.uvalue;
94 static void array_check(struct expression *expr)
96 struct expression_list *conditions;
97 struct expression *array_expr, *offset;
98 struct range_list *user_rl;
99 // struct bit_info *binfo;
100 int array_size;
101 char *name;
103 expr = strip_expr(expr);
104 if (!is_array(expr))
105 return;
107 if (is_impossible_path())
108 return;
109 if (is_write(expr))
110 return;
111 if (!is_read(expr))
112 return;
114 array_expr = get_array_base(expr);
115 if (is_ignored_expr(my_id, array_expr))
116 return;
118 offset = get_array_offset(expr);
119 if (!get_user_rl(offset, &user_rl))
120 return;
121 if (is_nospec(offset))
122 return;
124 array_size = get_array_size(array_expr);
125 if (array_size > 0 && get_max_by_type(offset) < array_size)
126 return;
127 // binfo = get_bit_info(offset);
128 // if (array_size > 0 && binfo && binfo->possible < array_size)
129 // return;
131 conditions = get_conditions(offset);
133 name = expr_to_str(array_expr);
134 sm_msg("warn: potential spectre issue '%s'%s",
135 name, conditions ? " (local cap)" : "");
136 add_ignore_expr(my_id, array_expr);
137 free_string(name);
140 void check_spectre(int id)
142 my_id = id;
144 if (option_project != PROJ_KERNEL)
145 return;
147 add_hook(&array_check, OP_HOOK);