1 /* 2 * Copyright (C) 2012 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 "scope.h" 19 #include "smatch.h" 20 #include "smatch_slist.h" 21 #include "smatch_expression_stacks.h" 22 23 static int my_id; 24 25 static struct string_list *ignored_macros; 26 static struct position old_pos; 27 28 static struct smatch_state *alloc_my_state(struct expression *expr) 29 { 30 struct smatch_state *state; 31 char *name; 32 33 expr = strip_expr(expr); 34 name = expr_to_str(expr); 35 if (!name) 36 return NULL; 37 38 state = __alloc_smatch_state(0); 39 state->name = alloc_sname(name); 40 free_string(name); 41 state->data = expr; 42 return state; 43 } 44 45 static int defined_inside_macro(struct position macro_pos, struct expression *expr) 46 { 47 char *name; 48 struct symbol *sym; 49 int ret = 0; 50 51 name = expr_to_var_sym(expr, &sym); 52 if (!name || !sym) 53 goto free; 54 if (!sym->scope || !sym->scope->token) 55 goto free; 56 if (positions_eq(macro_pos, sym->scope->token->pos)) 57 ret = 1; 58 free: 59 free_string(name); 60 return ret; 61 } 62 63 static int affected_inside_macro_before(struct expression *expr) 64 { 65 struct sm_state *sm; 66 struct sm_state *tmp; 67 struct expression *old_mod; 68 69 sm = get_sm_state_expr(my_id, expr); 70 if (!sm) 71 return 0; 72 73 FOR_EACH_PTR(sm->possible, tmp) { 74 old_mod = tmp->state->data; 75 if (!old_mod) 76 continue; 77 if (positions_eq(old_mod->pos, expr->pos)) 78 return 1; 79 } END_FOR_EACH_PTR(tmp); 80 return 0; 81 } 82 83 static int is_ignored_macro(const char *macro) 84 { 85 char *tmp; 86 87 FOR_EACH_PTR(ignored_macros, tmp) { 88 if (!strcmp(tmp, macro)) 89 return 1; 90 } END_FOR_EACH_PTR(tmp); 91 return 0; 92 } 93 94 static void match_unop(struct expression *raw_expr) 95 { 96 struct expression *expr; 97 char *macro, *name; 98 99 if (raw_expr->op != SPECIAL_INCREMENT && raw_expr->op != SPECIAL_DECREMENT) 100 return; 101 102 macro = get_macro_name(raw_expr->pos); 103 if (!macro) 104 return; 105 106 expr = strip_expr(raw_expr->unop); 107 108 if (defined_inside_macro(expr->pos, expr)) 109 return; 110 111 if (is_ignored_macro(macro)) 112 return; 113 114 if (!affected_inside_macro_before(expr)) { 115 set_state_expr(my_id, expr, alloc_my_state(expr)); 116 old_pos = expr->pos; 117 return; 118 } 119 120 if (!positions_eq(old_pos, expr->pos)) 121 return; 122 123 name = expr_to_str(raw_expr); 124 sm_warning("side effect in macro '%s' doing '%s'", 125 macro, name); 126 free_string(name); 127 } 128 129 static void match_stmt(struct statement *stmt) 130 { 131 if (!positions_eq(old_pos, stmt->pos)) 132 old_pos.line = 0; 133 } 134 135 static void register_ignored_macros(void) 136 { 137 struct token *token; 138 char *macro; 139 char name[256]; 140 141 snprintf(name, 256, "%s.ignore_side_effects", option_project_str); 142 143 token = get_tokens_file(name); 144 if (!token) 145 return; 146 if (token_type(token) != TOKEN_STREAMBEGIN) 147 return; 148 token = token->next; 149 while (token_type(token) != TOKEN_STREAMEND) { 150 if (token_type(token) != TOKEN_IDENT) 151 return; 152 macro = alloc_string(show_ident(token->ident)); 153 add_ptr_list(&ignored_macros, macro); 154 token = token->next; 155 } 156 clear_token_alloc(); 157 } 158 159 void check_macro_side_effects(int id) 160 { 161 my_id = id; 162 163 if (!option_spammy) 164 return; 165 166 set_dynamic_states(my_id); 167 add_hook(&match_unop, OP_HOOK); 168 add_hook(&match_stmt, STMT_HOOK); 169 register_ignored_macros(); 170 } 171