unreachable: ignore unreachable code after BUG()
[smatch.git] / check_unreachable.c
blob6f848eff6ab56a5f398b1ccb41af392e5ce723ff
1 /*
2 * Copyright (C) 2014 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"
20 static int my_id;
22 static int print_unreached = 1;
23 static struct string_list *turn_off_names;
25 static int empty_statement(struct statement *stmt)
27 if (!stmt)
28 return 0;
29 if (stmt->type == STMT_EXPRESSION && !stmt->expression)
30 return 1;
31 return 0;
34 static int is_last_stmt(struct statement *cur_stmt)
36 struct symbol *fn = get_base_type(cur_func_sym);
37 struct statement *stmt;
39 if (!fn)
40 return 0;
41 stmt = fn->stmt;
42 if (!stmt)
43 stmt = fn->inline_stmt;
44 if (!stmt || stmt->type != STMT_COMPOUND)
45 return 0;
46 stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
47 if (stmt == cur_stmt)
48 return 1;
49 return 0;
52 static void print_unreached_initializers(struct symbol_list *sym_list)
54 struct symbol *sym;
56 FOR_EACH_PTR(sym_list, sym) {
57 if (sym->initializer)
58 sm_msg("info: '%s' is not actually initialized (unreached code).",
59 (sym->ident ? sym->ident->name : "this variable"));
60 } END_FOR_EACH_PTR(sym);
63 static void unreachable_stmt(struct statement *stmt)
66 if (__inline_fn)
67 return;
69 if (!__path_is_null()) {
70 print_unreached = 1;
71 return;
73 if (!print_unreached)
74 return;
76 switch (stmt->type) {
77 case STMT_COMPOUND: /* after a switch before a case stmt */
78 case STMT_RANGE:
79 case STMT_CASE:
80 case STMT_LABEL:
81 return;
82 case STMT_DECLARATION: /* switch (x) { int a; case foo: ... */
83 print_unreached_initializers(stmt->declaration);
84 return;
85 case STMT_RETURN: /* gcc complains if you don't have a return statement */
86 if (is_last_stmt(stmt))
87 return;
88 break;
89 case STMT_GOTO:
90 /* people put extra breaks inside switch statements */
91 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE &&
92 strcmp(stmt->goto_label->ident->name, "break") == 0)
93 return;
94 break;
95 default:
96 break;
98 if (empty_statement(stmt))
99 return;
100 if (!option_spammy)
101 return;
102 sm_msg("info: ignoring unreachable code.");
103 print_unreached = 0;
106 static int is_turn_off(char *name)
108 char *tmp;
110 if (!name)
111 return 0;
113 FOR_EACH_PTR(turn_off_names, tmp) {
114 if (strcmp(tmp, name) == 0)
115 return 1;
116 } END_FOR_EACH_PTR(tmp);
118 return 0;
121 static char *get_function_name(struct statement *stmt)
123 struct expression *expr;
125 if (stmt->type != STMT_EXPRESSION)
126 return NULL;
127 expr = stmt->expression;
128 if (!expr || expr->type != EXPR_CALL)
129 return NULL;
130 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol_name)
131 return NULL;
132 return expr->fn->symbol_name->name;
135 static void turn_off_unreachable(struct statement *stmt)
137 char *name;
139 name = get_macro_name(stmt->pos);
140 if (is_turn_off(name)) {
141 print_unreached = 0;
142 return;
145 if (stmt->type == STMT_IF &&
146 known_condition_true(stmt->if_conditional)) {
147 name = get_macro_name(stmt->if_conditional->pos);
148 if (is_turn_off(name))
149 print_unreached = 0;
150 return;
153 name = get_function_name(stmt);
154 if (is_turn_off(name))
155 print_unreached = 0;
158 static void register_turn_off_macros(void)
160 struct token *token;
161 char *macro;
162 char name[256];
164 if (option_project == PROJ_NONE)
165 strcpy(name, "unreachable.turn_off");
166 else
167 snprintf(name, 256, "%s.unreachable.turn_off", option_project_str);
169 token = get_tokens_file(name);
170 if (!token)
171 return;
172 if (token_type(token) != TOKEN_STREAMBEGIN)
173 return;
174 token = token->next;
175 while (token_type(token) != TOKEN_STREAMEND) {
176 if (token_type(token) != TOKEN_IDENT)
177 return;
178 macro = alloc_string(show_ident(token->ident));
179 add_ptr_list(&turn_off_names, macro);
180 token = token->next;
182 clear_token_alloc();
185 void check_unreachable(int id)
187 my_id = id;
189 add_hook(&unreachable_stmt, STMT_HOOK);
190 register_turn_off_macros();
191 add_hook(&turn_off_unreachable, STMT_HOOK_AFTER);