11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright 2018 Joyent, Inc.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon /*
191f5207b7SJohn Levon  * Like lint of old, check that every return value from every function is used.
201f5207b7SJohn Levon  * Casting to (void) will silence this check.
211f5207b7SJohn Levon  */
221f5207b7SJohn Levon 
231f5207b7SJohn Levon #include "smatch.h"
241f5207b7SJohn Levon #include "smatch_slist.h"
251f5207b7SJohn Levon 
check_func_return(struct expression * expr)261f5207b7SJohn Levon static void check_func_return(struct expression *expr)
271f5207b7SJohn Levon {
281f5207b7SJohn Levon 	struct symbol *sym = get_real_base_type(get_type(expr->fn));
291f5207b7SJohn Levon 	const char *func = expr_to_str(expr->fn);
301f5207b7SJohn Levon 	struct statement *stmt;
311f5207b7SJohn Levon 
321f5207b7SJohn Levon 	if (sym == NULL) {
331f5207b7SJohn Levon 		sm_error("unknown type for func '%s'", func);
341f5207b7SJohn Levon 		return;
351f5207b7SJohn Levon 	}
361f5207b7SJohn Levon 
371f5207b7SJohn Levon 	if (expr->type != EXPR_CALL) {
381f5207b7SJohn Levon 		sm_error("func '%s' is not a call site", func);
391f5207b7SJohn Levon 		return;
401f5207b7SJohn Levon 	}
411f5207b7SJohn Levon 
421f5207b7SJohn Levon 	/*
431f5207b7SJohn Levon 	 * There is never any need to check these returns.
441f5207b7SJohn Levon 	 */
451f5207b7SJohn Levon 	if (strcmp(func, "memcpy") == 0 ||
461f5207b7SJohn Levon 	    strcmp(func, "memmove") == 0 ||
471f5207b7SJohn Levon 	    strcmp(func, "memset") == 0)
481f5207b7SJohn Levon 		return;
491f5207b7SJohn Levon 
501f5207b7SJohn Levon 	/*
511f5207b7SJohn Levon 	 * Closer to a policy here, but there seems very few cases where it's
521f5207b7SJohn Levon 	 * useful to check the return value of the standard printf() family
531f5207b7SJohn Levon 	 * outputting to stdout or stderr.
541f5207b7SJohn Levon 	 */
551f5207b7SJohn Levon 	if (strcmp(func, "printf") == 0 || strcmp(func, "vprintf") == 0)
561f5207b7SJohn Levon 		return;
571f5207b7SJohn Levon 
581f5207b7SJohn Levon 	if (strcmp(func, "fprintf") == 0 || strcmp(func, "vfprintf")) {
591f5207b7SJohn Levon 		const char *arg0 = expr_to_str(get_argument_from_call_expr(expr->args, 0));
601f5207b7SJohn Levon 
611f5207b7SJohn Levon 		if (arg0 != NULL &&
621f5207b7SJohn Levon 		    (strcmp(arg0, "(&__iob[1])") == 0 ||
631f5207b7SJohn Levon 		    strcmp(arg0, "(&__iob[2])") == 0))
641f5207b7SJohn Levon 			return;
651f5207b7SJohn Levon 	}
661f5207b7SJohn Levon 
671f5207b7SJohn Levon 	/*
681f5207b7SJohn Levon 	 * Either we got the return type already (direct call),
691f5207b7SJohn Levon 	 * or we need to go one further (function pointer call)
701f5207b7SJohn Levon 	 */
711f5207b7SJohn Levon 	if (sym == &void_ctype || (sym->type == SYM_FN &&
721f5207b7SJohn Levon 		get_real_base_type(sym) == &void_ctype))
731f5207b7SJohn Levon 		return;
741f5207b7SJohn Levon 
751f5207b7SJohn Levon 	stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
761f5207b7SJohn Levon 
77*6523a3aaSJohn Levon 	if (stmt && stmt->type == STMT_EXPRESSION && stmt->expression == expr)
781f5207b7SJohn Levon 		sm_error("unchecked function return '%s'", expr_to_str(expr->fn));
791f5207b7SJohn Levon }
801f5207b7SJohn Levon 
check_all_func_returns(int id)811f5207b7SJohn Levon void check_all_func_returns(int id)
821f5207b7SJohn Levon {
831f5207b7SJohn Levon 	if (option_project != PROJ_ILLUMOS_KERNEL &&
841f5207b7SJohn Levon 	    option_project != PROJ_ILLUMOS_USER)
851f5207b7SJohn Levon 		return;
861f5207b7SJohn Levon 
871f5207b7SJohn Levon 	add_hook(&check_func_return, FUNCTION_CALL_HOOK);
881f5207b7SJohn Levon }
89