1 /* 2 * Copyright (C) 2015 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 /* 19 * If you have code like: 20 * do { 21 * if (xxx) 22 * continue; 23 * while (0); 24 * 25 * Then the continue is equivalent of a break. So what was really intended? 26 */ 27 28 #include "smatch.h" 29 #include "smatch_slist.h" 30 31 static int my_id; 32 33 static struct statement_list *iterator_stack; 34 35 static int is_do_while_zero(struct statement *stmt) 36 { 37 if (!stmt->iterator_post_condition) 38 return 0; 39 if (!expr_is_zero(stmt->iterator_post_condition)) 40 return 0; 41 return 1; 42 } 43 44 static void push_statement(struct statement_list **stack, struct statement *stmt) 45 { 46 add_ptr_list(stack, stmt); 47 } 48 49 static void pop_statement(struct statement_list **stack) 50 { 51 delete_ptr_list_last((struct ptr_list **)stack); 52 } 53 54 static int inside_do_while_zero(void) 55 { 56 struct statement *stmt; 57 58 stmt = last_ptr_list((struct ptr_list *)iterator_stack); 59 return !!stmt; 60 } 61 62 static int loop_is_macro(void) 63 { 64 struct statement *stmt; 65 66 stmt = last_ptr_list((struct ptr_list *)iterator_stack); 67 if (!stmt) 68 return 0; 69 if (get_macro_name(stmt->iterator_post_condition->pos)) 70 return 1; 71 return 0; 72 } 73 74 static void match_stmt(struct statement *stmt) 75 { 76 if (stmt->type != STMT_ITERATOR) 77 return; 78 79 if (is_do_while_zero(stmt)) { 80 push_statement(&iterator_stack, stmt); 81 } else 82 push_statement(&iterator_stack, NULL); 83 } 84 85 static void match_stmt_after(struct statement *stmt) 86 { 87 if (stmt->type != STMT_ITERATOR) 88 return; 89 90 pop_statement(&iterator_stack); 91 } 92 93 static void match_inline_start(struct expression *expr) 94 { 95 push_statement(&iterator_stack, NULL); 96 } 97 98 static void match_inline_end(struct expression *expr) 99 { 100 pop_statement(&iterator_stack); 101 } 102 103 static void match_continue(struct statement *stmt) 104 { 105 if (stmt->type != STMT_GOTO) 106 return; 107 108 if (!stmt->goto_label || stmt->goto_label->type != SYM_NODE) 109 return; 110 if (strcmp(stmt->goto_label->ident->name, "continue") != 0) 111 return; 112 if (!inside_do_while_zero()) 113 return; 114 if (loop_is_macro()) 115 return; 116 sm_warning("continue to end of do { ... } while(0); loop"); 117 } 118 119 void check_continue_vs_break(int id) 120 { 121 my_id = id; 122 add_hook(&match_stmt, STMT_HOOK); 123 add_hook(&match_stmt_after, STMT_HOOK_AFTER); 124 add_hook(&match_inline_start, INLINE_FN_START); 125 add_hook(&match_inline_end, INLINE_FN_END); 126 127 add_hook(&match_continue, STMT_HOOK); 128 } 129