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