1 /* 2 * Copyright (C) 2018 Oracle. 3 * 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. 8 * 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. 13 * 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 16 */ 17 18 #include "smatch.h" 19 #include "smatch_extra.h" 20 #include "smatch_slist.h" 21 22 /* New chips will probably be able to speculate further ahead */ 23 #define MAX_SPEC_STMT 200 24 25 static int my_id; 26 27 struct stree *first_halfs; 28 29 struct expression *recently_set; 30 31 void set_spectre_first_half(struct expression *expr) 32 { 33 char buf[64]; 34 char *name; 35 36 name = expr_to_str(expr); 37 snprintf(buf, sizeof(buf), "%p %s", expr, name); 38 free_string(name); 39 40 set_state_stree(&first_halfs, my_id, buf, NULL, alloc_state_num(get_stmt_cnt())); 41 } 42 43 void clear_spectre_second_halfs(void) 44 { 45 struct sm_state *sm; 46 47 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { 48 set_state(my_id, sm->name, sm->sym, alloc_state_num(-MAX_SPEC_STMT)); 49 } END_FOR_EACH_SM(sm); 50 } 51 52 static struct smatch_state *get_spectre_first_half(struct expression *expr) 53 { 54 char buf[64]; 55 char *name; 56 57 name = expr_to_str(expr); 58 snprintf(buf, sizeof(buf), "%p %s", expr, name); 59 free_string(name); 60 61 return get_state_stree(first_halfs, my_id, buf, NULL); 62 } 63 64 static void match_assign(struct expression *expr) 65 { 66 struct smatch_state *state; 67 68 if (expr->op == SPECIAL_AND_ASSIGN) 69 return; 70 71 state = get_spectre_first_half(expr->right); 72 if (state) { 73 set_state_expr(my_id, expr->left, state); 74 recently_set = expr->left; 75 return; 76 } 77 state = get_state_expr(my_id, expr->right); 78 if (!state) 79 return; 80 set_state_expr(my_id, expr->left, state); 81 recently_set = expr->left; 82 } 83 84 static void match_done(struct expression *expr) 85 { 86 struct smatch_state *state; 87 char *name; 88 89 if (expr == recently_set) 90 return; 91 92 state = get_state_expr(my_id, expr); 93 if (!state) 94 return; 95 96 if (get_stmt_cnt() - (long)state->data > MAX_SPEC_STMT) 97 return; 98 99 name = expr_to_str(expr); 100 sm_msg("warn: possible spectre second half. '%s'", name); 101 free_string(name); 102 103 set_state_expr(my_id, expr, alloc_state_num(-MAX_SPEC_STMT)); 104 } 105 106 static void match_end_func(struct symbol *sym) 107 { 108 if (__inline_fn) 109 return; 110 free_stree(&first_halfs); 111 } 112 113 void check_spectre_second_half(int id) 114 { 115 my_id = id; 116 117 if (option_project != PROJ_KERNEL) 118 return; 119 set_dynamic_states(my_id); 120 add_hook(&match_assign, ASSIGNMENT_HOOK); 121 add_hook(&match_done, SYM_HOOK); 122 add_hook(&match_done, DEREF_HOOK); 123 124 add_hook(&match_end_func, END_FUNC_HOOK); 125 } 126