1 /* 2 * Copyright (C) 2016 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 20 static struct statement_list *stmt_list; 21 end_of_function(struct statement * stmt)22static int end_of_function(struct statement *stmt) 23 { 24 struct symbol *fn = get_base_type(cur_func_sym); 25 26 /* err on the conservative side of things */ 27 if (!fn) 28 return 1; 29 if (stmt == fn->stmt || stmt == fn->inline_stmt) 30 return 1; 31 return 0; 32 } 33 34 /* 35 * We're wasting a lot of time worrying about out of scope variables. 36 * When we come to the end of a scope then just delete them all the out of 37 * scope states. 38 */ match_end_of_block(struct statement * stmt)39static void match_end_of_block(struct statement *stmt) 40 { 41 struct statement *tmp; 42 struct symbol *sym; 43 44 if (end_of_function(stmt)) 45 return; 46 47 FOR_EACH_PTR(stmt->stmts, tmp) { 48 if (tmp->type != STMT_DECLARATION) 49 return; 50 51 FOR_EACH_PTR(tmp->declaration, sym) { 52 if (!sym->ident) 53 continue; 54 __delete_all_states_sym(sym); 55 } END_FOR_EACH_PTR(sym); 56 } END_FOR_EACH_PTR(tmp); 57 } 58 is_outer_stmt(struct statement * stmt)59static int is_outer_stmt(struct statement *stmt) 60 { 61 struct symbol *fn; 62 63 if (!cur_func_sym) 64 return 0; 65 fn = get_base_type(cur_func_sym); 66 if (!fn) 67 return 0; 68 /* 69 * There are times when ->parent is not set but it's set for 70 * the outer statement so ignoring NULLs works as a work-around. 71 */ 72 if (!stmt->parent) 73 return 0; 74 if (stmt->parent == fn->stmt || 75 stmt->parent == fn->inline_stmt) 76 return 1; 77 return 0; 78 } 79 match_stmt(struct statement * stmt)80static void match_stmt(struct statement *stmt) 81 { 82 struct statement *tmp; 83 84 if (__inline_fn) 85 return; 86 87 if (stmt->type == STMT_COMPOUND) 88 add_ptr_list(&stmt_list, stmt); 89 90 if (!is_outer_stmt(stmt)) 91 return; 92 93 FOR_EACH_PTR(stmt_list, tmp) { 94 match_end_of_block(tmp); 95 } END_FOR_EACH_PTR(tmp); 96 free_ptr_list(&stmt_list); 97 } 98 match_end_func(struct symbol * sym)99static void match_end_func(struct symbol *sym) 100 { 101 if (__inline_fn) 102 return; 103 free_ptr_list(&stmt_list); 104 } 105 register_scope(int id)106void register_scope(int id) 107 { 108 add_hook(&match_stmt, STMT_HOOK_AFTER); 109 add_hook(&match_end_func, AFTER_FUNC_HOOK); 110 } 111