1 /*
2  * Copyright 2018 Joyent, Inc.
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  * Like lint of old, check that every return value from every function is used.
20  * Casting to (void) will silence this check.
21  */
22 
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 
check_func_return(struct expression * expr)26 static void check_func_return(struct expression *expr)
27 {
28 	struct symbol *sym = get_real_base_type(get_type(expr->fn));
29 	const char *func = expr_to_str(expr->fn);
30 	struct statement *stmt;
31 
32 	if (sym == NULL) {
33 		sm_error("unknown type for func '%s'", func);
34 		return;
35 	}
36 
37 	if (expr->type != EXPR_CALL) {
38 		sm_error("func '%s' is not a call site", func);
39 		return;
40 	}
41 
42 	/*
43 	 * There is never any need to check these returns.
44 	 */
45 	if (strcmp(func, "memcpy") == 0 ||
46 	    strcmp(func, "memmove") == 0 ||
47 	    strcmp(func, "memset") == 0)
48 		return;
49 
50 	/*
51 	 * Closer to a policy here, but there seems very few cases where it's
52 	 * useful to check the return value of the standard printf() family
53 	 * outputting to stdout or stderr.
54 	 */
55 	if (strcmp(func, "printf") == 0 || strcmp(func, "vprintf") == 0)
56 		return;
57 
58 	if (strcmp(func, "fprintf") == 0 || strcmp(func, "vfprintf")) {
59 		const char *arg0 = expr_to_str(get_argument_from_call_expr(expr->args, 0));
60 
61 		if (arg0 != NULL &&
62 		    (strcmp(arg0, "(&__iob[1])") == 0 ||
63 		    strcmp(arg0, "(&__iob[2])") == 0))
64 			return;
65 	}
66 
67 	/*
68 	 * Either we got the return type already (direct call),
69 	 * or we need to go one further (function pointer call)
70 	 */
71 	if (sym == &void_ctype || (sym->type == SYM_FN &&
72 		get_real_base_type(sym) == &void_ctype))
73 		return;
74 
75 	stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
76 
77 	if (stmt && stmt->type == STMT_EXPRESSION && stmt->expression == expr)
78 		sm_error("unchecked function return '%s'", expr_to_str(expr->fn));
79 }
80 
check_all_func_returns(int id)81 void check_all_func_returns(int id)
82 {
83 	if (option_project != PROJ_ILLUMOS_KERNEL &&
84 	    option_project != PROJ_ILLUMOS_USER)
85 		return;
86 
87 	add_hook(&check_func_return, FUNCTION_CALL_HOOK);
88 }
89