[PATCH] Add check_all_func_returns

John Levon <[email protected]>
Newsgroups org.kernel.vger.smatch
Message-ID <[email protected]>
This replaces functionality in "lint" that checked every function with a
non-void return is handled.

We cannot use GCC's functionality for this, since a "(void)" cast is not
sufficient to turn it off, and besides, we want this to be the default for
everything.
---
 check_all_func_returns.c | 88 ++++++++++++++++++++++++++++++++++++++++
 check_list.h             |  3 ++
 2 files changed, 91 insertions(+)
 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..f9d77449
--- /dev/null
+++ b/check_all_func_returns.c
@@ -0,0 +1,88 @@
+/*
+ * 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;
+	}
+
+	if (expr->type != EXPR_CALL) {
+		sm_error("func '%s' is not a call site", 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;
+
+	/*
+	 * Closer to a policy here, but there seems very few cases where it's
+	 * useful to check the return value of the standard printf() family
+	 * outputting to stdout or stderr.
+	 */
+	if (strcmp(func, "printf") == 0 || strcmp(func, "vprintf") == 0)
+		return;
+
+	if (strcmp(func, "fprintf") == 0 || strcmp(func, "vfprintf")) {
+		const char *arg0 = expr_to_str(get_argument_from_call_expr(expr->args, 0));
+
+		if (arg0 != NULL &&
+		    (strcmp(arg0, "(&__iob[1])") == 0 ||
+		    strcmp(arg0, "(&__iob[2])") == 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 564bd1c2..cc3ce853 100644
--- a/check_list.h
+++ b/check_list.h
@@ -198,6 +198,9 @@ CK(check_wine_WtoA)
 
 CK(check_arm64_tagged)
 
+/* illumos specific */
+CK(check_all_func_returns)
+
 #include "check_list_local.h"
 
 CK(register_scope)
-- 
2.17.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.