Signed-off-by: John Levon <levon@xxxxxxxxxxxxxxxxx> --- check_all_func_returns.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ check_list.h | 3 +++ smatch.c | 7 ++++- smatch.h | 2 ++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 check_all_func_returns.c diff --git a/check_all_func_returns.c b/check_all_func_returns.c new file mode 100644 index 00000000..f4ba58dd --- /dev/null +++ b/check_all_func_returns.c @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Joyent, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt + */ + +/* + * Like lint of old, check that every return value from every function is used. + * Casting to (void) will silence this check. + */ + +#include "smatch.h" +#include "smatch_slist.h" + +static void check_func_return(struct expression *expr) +{ + struct symbol *sym = get_real_base_type(get_type(expr->fn)); + const char *func = expr_to_str(expr->fn); + struct statement *stmt; + + if (sym == NULL) { + sm_error("unknown type for func '%s'", func); + return; + } + + /* + * There is never any need to check these returns. + */ + if (strcmp(func, "memcpy") == 0 || + strcmp(func, "memmove") == 0 || + strcmp(func, "memset") == 0) + return; + + /* + * Either we got the return type already (direct call), + * or we need to go one further (function pointer call) + */ + if (sym == &void_ctype || (sym->type == SYM_FN && + get_real_base_type(sym) == &void_ctype)) + return; + + stmt = last_ptr_list((struct ptr_list *)big_statement_stack); + + if (stmt->type == STMT_EXPRESSION && stmt->expression == expr) + sm_error("unchecked function return '%s'", expr_to_str(expr->fn)); +} + +void check_all_func_returns(int id) +{ + if (option_project != PROJ_ILLUMOS_KERNEL && + option_project != PROJ_ILLUMOS_USER) + return; + + add_hook(&check_func_return, FUNCTION_CALL_HOOK); +} diff --git a/check_list.h b/check_list.h index 055e6304..cbe783d7 100644 --- a/check_list.h +++ b/check_list.h @@ -192,6 +192,9 @@ CK(check_implicit_dependencies) CK(check_wine_filehandles) CK(check_wine_WtoA) +/* illumos specific stuff */ +CK(check_all_func_returns) + #include "check_list_local.h" CK(register_scope) diff --git a/smatch.c b/smatch.c index c00e75d9..c8a6b4e3 100644 --- a/smatch.c +++ b/smatch.c @@ -255,10 +255,15 @@ void parse_args(int *argcp, char ***argvp) if (strcmp(option_project_str, "smatch_generic") != 0) option_project = PROJ_UNKNOWN; + if (strcmp(option_project_str, "kernel") == 0) option_project = PROJ_KERNEL; - if (strcmp(option_project_str, "wine") == 0) + else if (strcmp(option_project_str, "wine") == 0) option_project = PROJ_WINE; + else if (strcmp(option_project_str, "illumos_kernel") == 0) + option_project = PROJ_ILLUMOS_KERNEL; + else if (strcmp(option_project_str, "illumos_user") == 0) + option_project = PROJ_ILLUMOS_USER; } static char *read_bin_filename(void) diff --git a/smatch.h b/smatch.h index db4bb4cf..3e5ebe4f 100644 --- a/smatch.h +++ b/smatch.h @@ -984,6 +984,8 @@ enum project_type { PROJ_NONE, PROJ_KERNEL, PROJ_WINE, + PROJ_ILLUMOS_KERNEL, + PROJ_ILLUMOS_USER, PROJ_UNKNOWN, }; extern enum project_type option_project; -- 2.14.1