changeset 19430:6e69910f8ded

12257 resync smatch to 0.6.1-rc1-il-4 Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Robert Mustacchi <rm@fingolfin.org> Approved by: Dan McDonald <danmcd@joyent.com>
author John Levon <john.levon@joyent.com>
date Wed, 22 Jan 2020 16:05:13 -0800
parents 2377ea847e10
children 5599be23ae32
files usr/src/tools/smatch/Makefile usr/src/tools/smatch/src/Makefile usr/src/tools/smatch/src/check_list.h usr/src/tools/smatch/src/check_locking.c usr/src/tools/smatch/src/lib.c usr/src/tools/smatch/src/lib.h usr/src/tools/smatch/src/machine.h usr/src/tools/smatch/src/pre-process.c usr/src/tools/smatch/src/smatch.h usr/src/tools/smatch/src/smatch_container_of.c usr/src/tools/smatch/src/smatch_db.c usr/src/tools/smatch/src/smatch_fresh_alloc.c usr/src/tools/smatch/src/smatch_math.c usr/src/tools/smatch/src/smatch_mtag.c usr/src/tools/smatch/src/smatch_slist.c usr/src/tools/smatch/src/smatch_type.c usr/src/tools/smatch/src/validation/sm_locking2.c usr/src/tools/smatch/src/validation/sm_locking3.c usr/src/tools/smatch/src/validation/sm_locking4.c usr/src/tools/smatch/src/validation/sm_locking6.c usr/src/tools/smatch/src/validation/sm_locking7.c
diffstat 21 files changed, 353 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/tools/smatch/Makefile	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/Makefile	Wed Jan 22 16:05:13 2020 -0800
@@ -20,7 +20,7 @@
 #
 
 PROG = smatch
-SPARSE_VERSION = 0.6.1-rc1-il-3
+SPARSE_VERSION = 0.6.1-rc1-il-4
 
 include ../Makefile.tools
 
@@ -123,6 +123,7 @@
 SMATCH_OBJS += smatch_extra.o
 SMATCH_OBJS += smatch_files.o
 SMATCH_OBJS += smatch_flow.o
+SMATCH_OBJS += smatch_fresh_alloc.o
 SMATCH_OBJS += smatch_fn_arg_link.o
 SMATCH_OBJS += smatch_function_hooks.o
 SMATCH_OBJS += smatch_function_info.o
--- a/usr/src/tools/smatch/src/Makefile	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/Makefile	Wed Jan 22 16:05:13 2020 -0800
@@ -1,4 +1,4 @@
-VERSION=0.6.1-rc1-il-3
+VERSION=0.6.1-rc1-il-4
 
 ########################################################################
 # The following variables can be overwritten from the command line
@@ -226,6 +226,7 @@
 SMATCH_OBJS += smatch_files.o
 SMATCH_OBJS += smatch_flow.o
 SMATCH_OBJS += smatch_fn_arg_link.o
+SMATCH_OBJS += smatch_fresh_alloc.o
 SMATCH_OBJS += smatch_function_hooks.o
 SMATCH_OBJS += smatch_function_info.o
 SMATCH_OBJS += smatch_function_ptrs.o
--- a/usr/src/tools/smatch/src/check_list.h	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/check_list.h	Wed Jan 22 16:05:13 2020 -0800
@@ -72,6 +72,7 @@
 CK(register_nul_terminator)
 CK(register_nul_terminator_param_set)
 CK(register_statement_count)
+CK(register_fresh_alloc)
 
 CK(register_kernel_user_data)
 CK(register_kernel_user_data2)
--- a/usr/src/tools/smatch/src/check_locking.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/check_locking.c	Wed Jan 22 16:05:13 2020 -0800
@@ -1021,10 +1021,13 @@
 		if (parent_is_gone_var_sym(sm->name, sm->sym))
 			goto swap_stree;
 
-		if (sm->state != &locked && sm->state != &unlocked)
+		if (sm->state != &locked &&
+		    sm->state != &unlocked &&
+		    sm->state != &restore)
 			goto swap_stree;
 
-		if (sm->state == &unlocked && is_EINTR(estate_rl(return_sm->state)))
+		if ((sm->state == &unlocked || sm->state == &restore) &&
+		    is_EINTR(estate_rl(return_sm->state)))
 			goto swap_stree;
 
 		bucket = success_fail_positive(estate_rl(return_sm->state));
@@ -1032,7 +1035,7 @@
 			add_range(&locked_lines, line, line);
 			locked_buckets[bucket] = true;
 		}
-		if (sm->state == &unlocked) {
+		if (sm->state == &unlocked || sm->state == &restore) {
 			add_range(&unlocked_lines, line, line);
 			unlocked_buckets[bucket] = true;
 		}
--- a/usr/src/tools/smatch/src/lib.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/lib.c	Wed Jan 22 16:05:13 2020 -0800
@@ -318,13 +318,7 @@
 
 int preprocess_only;
 
-static enum { STANDARD_C89,
-              STANDARD_C94,
-              STANDARD_C99,
-              STANDARD_C11,
-              STANDARD_GNU11,
-              STANDARD_GNU89,
-              STANDARD_GNU99, } standard = STANDARD_GNU89;
+enum standard standard = STANDARD_GNU89;
 
 int arch_m64 = ARCH_M64_DEFAULT;
 int arch_msize_long = 0;
@@ -1313,6 +1307,8 @@
 	if (optimize_size)
 		predefine("__OPTIMIZE_SIZE__", 0, "1");
 
+	predefine("__PRAGMA_REDEFINE_EXTNAME", 1, "1");
+
 	// Temporary hacks
 	predefine("__extension__", 0, NULL);
 	predefine("__pragma__", 0, NULL);
@@ -1326,7 +1322,6 @@
 		break;
 	case ARCH_LP64:
 		predefine("__LP64__", 1, "1");
-		predefine("__LP64", 1, "1");
 		predefine("_LP64", 1, "1");
 		break;
 	case ARCH_LLP64:
@@ -1389,32 +1384,38 @@
 	case MACH_SPARC32:
 		predefine("__sparc__", 1, "1");
 		predefine("__sparc", 1, "1");
+		predefine_nostd("sparc");
 		break;
 	case MACH_X86_64:
 		if (arch_m64 != ARCH_LP32) {
 			predefine("__x86_64__", 1, "1");
 			predefine("__x86_64", 1, "1");
+			predefine("__amd64__", 1, "1");
+			predefine("__amd64", 1, "1");
 			break;
 		}
 		/* fall-through */
 	case MACH_I386:
 		predefine("__i386__", 1, "1");
 		predefine("__i386", 1, "1");
-		predefine("i386", 1, "1");
+		predefine_nostd("i386");
 		break;
 	}
 
-	predefine("__PRAGMA_REDEFINE_EXTNAME", 1, "1");
-
-#ifdef	__sun
+#if defined(__unix__)
 	predefine("__unix__", 1, "1");
 	predefine("__unix", 1, "1");
-	predefine("unix", 1, "1");
+	predefine_nostd("unix");
+#endif
+
+
+#if defined(__sun__) || defined(__sun)
 	predefine("__sun__", 1, "1");
 	predefine("__sun", 1, "1");
-	predefine("sun", 1, "1");
+	predefine_nostd("sun");
 	predefine("__svr4__", 1, "1");
 #endif
+
 }
 
 static void create_builtin_stream(void)
--- a/usr/src/tools/smatch/src/lib.h	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/lib.h	Wed Jan 22 16:05:13 2020 -0800
@@ -134,6 +134,7 @@
 
 extern void add_pre_buffer(const char *fmt, ...) FORMAT_ATTR(1);
 extern void predefine(const char *name, int weak, const char *fmt, ...) FORMAT_ATTR(3);
+extern void predefine_nostd(const char *name);
 
 extern int preprocess_only;
 
@@ -206,6 +207,20 @@
 extern int arch_big_endian;
 extern int arch_mach;
 
+enum standard {
+	STANDARD_NONE,
+	STANDARD_GNU,
+	STANDARD_C89,
+	STANDARD_GNU89 = STANDARD_C89 | STANDARD_GNU,
+	STANDARD_C94,
+	STANDARD_GNU94 = STANDARD_C94 | STANDARD_GNU,
+	STANDARD_C99,
+	STANDARD_GNU99 = STANDARD_C99 | STANDARD_GNU,
+	STANDARD_C11,
+	STANDARD_GNU11 = STANDARD_C11 | STANDARD_GNU,
+};
+extern enum standard standard;
+
 extern void dump_macro_definitions(void);
 extern struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **files);
 extern struct symbol_list *__sparse(char *filename);
--- a/usr/src/tools/smatch/src/machine.h	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/machine.h	Wed Jan 22 16:05:13 2020 -0800
@@ -62,7 +62,7 @@
 #define	MACH_NATIVE	MACH_RISCV64
 #elif defined(__riscv) && (__riscv_xlen == 32)
 #define	MACH_NATIVE	MACH_RISCV32
-#elif defined(__sparc_v9__)
+#elif defined(__sparc_v9__) || defined(__sparcv9)
 #define	MACH_NATIVE	MACH_SPARC64
 #elif defined(__sparc__) || defined(__sparc)
 #define	MACH_NATIVE	MACH_SPARC32
--- a/usr/src/tools/smatch/src/pre-process.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/pre-process.c	Wed Jan 22 16:05:13 2020 -0800
@@ -1568,6 +1568,14 @@
 	do_define(value->pos, NULL, ident, NULL, value, attr);
 }
 
+///
+// like predefine() but only if one of the non-standard dialect is chosen
+void predefine_nostd(const char *name)
+{
+	if ((standard & STANDARD_GNU) || (standard == STANDARD_NONE))
+		predefine(name, 1, "1");
+}
+
 static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
 {
 	struct token *arglist, *expansion;
--- a/usr/src/tools/smatch/src/smatch.h	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch.h	Wed Jan 22 16:05:13 2020 -0800
@@ -104,6 +104,12 @@
 };
 DECLARE_PTR_LIST(constraint_list, struct constraint);
 
+struct alloc_info {
+	const char *fn;
+	int size_param, nr;
+};
+extern struct alloc_info *alloc_funcs;
+
 struct bit_info {
 	unsigned long long set;
 	unsigned long long possible;
@@ -398,6 +404,7 @@
 int get_const_value(struct expression *expr, sval_t *sval);
 int get_value(struct expression *expr, sval_t *val);
 int get_implied_value(struct expression *expr, sval_t *val);
+int get_implied_value_fast(struct expression *expr, sval_t *sval);
 int get_implied_min(struct expression *expr, sval_t *sval);
 int get_implied_max(struct expression *expr, sval_t *val);
 int get_hard_max(struct expression *expr, sval_t *sval);
@@ -839,6 +846,7 @@
 	NOSPEC_WB	= 1036,
 	STMT_CNT	= 1037,
 	TERMINATED	= 1038,
+	FRESH_ALLOC	= 1044,
 
 	/* put random temporary stuff in the 7000-7999 range for testing */
 	USER_DATA	= 8017,
@@ -1249,6 +1257,7 @@
 char *get_container_name(struct expression *container, struct expression *expr);
 
 /* smatch_mtag.c */
+mtag_t str_to_mtag(const char *str);
 int get_string_mtag(struct expression *expr, mtag_t *tag);
 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag);
 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new);
@@ -1278,6 +1287,8 @@
 /* check_kernel.c  */
 bool is_ignored_kernel_data(const char *name);
 
+bool is_fresh_alloc_var_sym(const char *var, struct symbol *sym);
+bool is_fresh_alloc(struct expression *expr);
 static inline bool type_is_ptr(struct symbol *type)
 {
 	return type &&
--- a/usr/src/tools/smatch/src/smatch_container_of.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch_container_of.c	Wed Jan 22 16:05:13 2020 -0800
@@ -215,17 +215,17 @@
 	return NULL;
 }
 
-char *get_container_name(struct expression *container, struct expression *expr)
+static char *get_container_name_helper(struct expression *container, struct expression *expr)
 {
 	struct symbol *container_sym, *sym;
-	struct expression *tmp;
 	static char buf[64];
 	char *ret, *shared;
 	bool star;
-	int cnt;
 
 	expr = strip_expr(expr);
 	container = strip_expr(container);
+	if (!expr || !container)
+		return NULL;
 
 	ret = get_stored_container_name(container, expr);
 	if (ret)
@@ -233,24 +233,10 @@
 
 	sym = expr_to_sym(expr);
 	container_sym = expr_to_sym(container);
-	if (sym && sym == container_sym)
-		goto found;
-
-	cnt = 0;
-	while ((tmp = get_assigned_expr(container))) {
-		container = strip_expr(tmp);
-		if (cnt++ > 3)
-			break;
-	}
-
-	cnt = 0;
-	while ((tmp = get_assigned_expr(expr))) {
-		expr = strip_expr(tmp);
-		if (cnt++ > 3)
-			break;
-	}
-
-found:
+	if (!sym || !container_sym)
+		return NULL;
+	if (sym != container_sym)
+		return NULL;
 
 	if (container->type == EXPR_DEREF)
 		star = true;
@@ -262,13 +248,6 @@
 	if (expr->type == EXPR_PREOP && expr->op == '&')
 		expr = strip_expr(expr->unop);
 
-	sym = expr_to_sym(expr);
-	if (!sym)
-		return NULL;
-	container_sym = expr_to_sym(container);
-	if (!container_sym || sym != container_sym)
-		return NULL;
-
 	shared = get_shared_str(expr, container);
 	if (!shared)
 		return NULL;
@@ -280,6 +259,30 @@
 	return buf;
 }
 
+char *get_container_name(struct expression *container, struct expression *expr)
+{
+	char *ret;
+
+	ret = get_container_name_helper(container, expr);
+	if (ret)
+		return ret;
+
+	ret = get_container_name_helper(get_assigned_expr(container), expr);
+	if (ret)
+		return ret;
+
+	ret = get_container_name_helper(container, get_assigned_expr(expr));
+	if (ret)
+		return ret;
+
+	ret = get_container_name_helper(get_assigned_expr(container),
+					get_assigned_expr(expr));
+	if (ret)
+		return ret;
+
+	return NULL;
+}
+
 static bool is_fn_ptr(struct expression *expr)
 {
 	struct symbol *type;
--- a/usr/src/tools/smatch/src/smatch_db.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch_db.c	Wed Jan 22 16:05:13 2020 -0800
@@ -768,16 +768,6 @@
 	sql_insert_caller_info(expr, INTERNAL, -1, "%call_marker%", type_to_str(type));
 }
 
-static char *show_offset(int offset)
-{
-	static char buf[64];
-
-	buf[0] = '\0';
-	if (offset != -1)
-		snprintf(buf, sizeof(buf), "(-%d)", offset);
-	return buf;
-}
-
 int is_recursive_member(const char *name)
 {
 	char buf[256];
@@ -860,7 +850,7 @@
 	return ret;
 }
 
-static void print_struct_members(struct expression *call, struct expression *expr, int param, int offset, struct stree *stree,
+static void print_struct_members(struct expression *call, struct expression *expr, int param, struct stree *stree,
 	void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
 {
 	struct sm_state *sm;
@@ -902,23 +892,23 @@
 		// FIXME: simplify?
 		if (!add_star && strcmp(name, sm_name) == 0) {
 			if (is_address)
-				snprintf(printed_name, sizeof(printed_name), "*$%s", show_offset(offset));
+				snprintf(printed_name, sizeof(printed_name), "*$");
 			else /* these are already handled. fixme: handle them here */
 				continue;
 		} else if (add_star && strcmp(name, sm_name) == 0) {
-			snprintf(printed_name, sizeof(printed_name), "%s*$%s",
-				 is_address ? "*" : "", show_offset(offset));
+			snprintf(printed_name, sizeof(printed_name), "%s*$",
+				 is_address ? "*" : "");
 		} else if (strncmp(name, sm_name, len) == 0) {
 			if (sm_name[len] != '.' && sm_name[len] != '-')
 				continue;
 			if (is_address)
 				snprintf(printed_name, sizeof(printed_name),
-					 "%s$%s->%s", add_star ? "*" : "",
-					 show_offset(offset), sm_name + len + 1);
+					 "%s$->%s", add_star ? "*" : "",
+					 sm_name + len + 1);
 			else
 				snprintf(printed_name, sizeof(printed_name),
-					 "%s$%s%s", add_star ? "*" : "",
-					 show_offset(offset), sm_name + len);
+					 "%s$%s", add_star ? "*" : "",
+					 sm_name + len);
 		} else {
 			continue;
 		}
@@ -930,67 +920,6 @@
 	free_string(name);
 }
 
-static int param_used_callback(void *_container, int argc, char **argv, char **azColName)
-{
-	char **container = _container;
-	static char buf[256];
-
-	snprintf(buf, sizeof(buf), "%s", argv[0]);
-	*container = buf;
-	return 0;
-}
-
-static void print_container_struct_members(struct expression *call, struct expression *expr, int param, struct stree *stree,
-	void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
-{
-	struct expression *tmp;
-	char *container = NULL;
-	int offset;
-	int holder_offset;
-	char *p;
-
-	if (!call->fn || call->fn->type != EXPR_SYMBOL || !call->fn->symbol)
-		return;
-
-	/*
-	 * We can't use the in-mem DB because we have to parse the function
-	 * first, then we know if it takes a container, then we know to pass it
-	 * the container data.
-	 *
-	 */
-	run_sql(&param_used_callback, &container,
-		"select key from return_implies where %s and type = %d and key like '%%$(%%' and parameter = %d limit 1;",
-		get_static_filter(call->fn->symbol), CONTAINER, param);
-	if (!container)
-		return;
-
-	p = strchr(container, '-');
-	if (!p)
-		return;
-	offset = atoi(p);
-	p = strchr(p, ')');
-	if (!p)
-		return;
-	p++;
-
-	tmp = get_assigned_expr(expr);
-	if (tmp)
-		expr = tmp;
-
-	if (expr->type != EXPR_PREOP || expr->op != '&')
-		return;
-	expr = strip_expr(expr->unop);
-	holder_offset = get_member_offset_from_deref(expr);
-	if (-holder_offset != offset)
-		return;
-
-	expr = strip_expr(expr->deref);
-	if (expr->type == EXPR_PREOP && expr->op == '*')
-		expr = strip_expr(expr->unop);
-
-	print_struct_members(call, expr, param, holder_offset, stree, callback);
-}
-
 static void match_call_info(struct expression *call)
 {
 	struct member_info_callback *cb;
@@ -1007,8 +936,7 @@
 		stree = get_all_states_stree(cb->owner);
 		i = 0;
 		FOR_EACH_PTR(call->args, arg) {
-			print_struct_members(call, arg, i, -1, stree, cb->callback);
-			print_container_struct_members(call, arg, i, stree, cb->callback);
+			print_struct_members(call, arg, i, stree, cb->callback);
 			i++;
 		} END_FOR_EACH_PTR(arg);
 		free_stree(&stree);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/smatch_fresh_alloc.c	Wed Jan 22 16:05:13 2020 -0800
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 Oracle.
+ *
+ * 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
+ */
+
+/*
+ * There are a bunch of allocation functions where we allocate some memory,
+ * set up some struct members and then return the allocated memory.  One
+ * nice thing about this is that we just one pointer to the allocated memory
+ * so what we can do is we can generate a mtag alias for it in the caller.
+ */
+
+#include "smatch.h"
+#include "smatch_slist.h"
+
+static int my_id;
+
+STATE(fresh);
+
+struct alloc_info *alloc_funcs;
+
+struct alloc_info kernel_allocation_funcs[] = {
+	{"kmalloc", 0},
+	{"kmalloc_node", 0},
+	{"kzalloc", 0},
+	{"kzalloc_node", 0},
+	{"vmalloc", 0},
+	{"__vmalloc", 0},
+	{"kvmalloc", 0},
+	{"kcalloc", 0, 1},
+	{"kmalloc_array", 0, 1},
+	{"sock_kmalloc", 1},
+	{"kmemdup", 1},
+	{"kmemdup_user", 1},
+	{"dma_alloc_attrs", 1},
+	{"pci_alloc_consistent", 1},
+	{"pci_alloc_coherent", 1},
+	{"devm_kmalloc", 1},
+	{"devm_kzalloc", 1},
+	{"krealloc", 1},
+	{"__alloc_bootmem", 0},
+	{"alloc_bootmem", 0},
+	{"dma_alloc_contiguous", 1},
+	{"dma_alloc_coherent", 1},
+	{},
+};
+
+struct alloc_info general_allocation_funcs[] = {
+	{"malloc", 0},
+	{"calloc", 0, 1},
+	{"memdup", 1},
+	{"realloc", 1},
+	{},
+};
+
+static int fresh_callback(void *fresh, int argc, char **argv, char **azColName)
+{
+	*(int *)fresh = 1;
+	return 0;
+}
+
+static int fresh_from_db(struct expression *call)
+{
+	int fresh = 0;
+
+	/* for function pointers assume everything is used */
+	if (call->fn->type != EXPR_SYMBOL)
+		return 0;
+
+	run_sql(&fresh_callback, &fresh,
+		"select * from return_states where %s and type = %d and parameter = -1 and key = '$' limit 1;",
+		get_static_filter(call->fn->symbol), FRESH_ALLOC);
+	return fresh;
+}
+
+bool is_fresh_alloc_var_sym(const char *var, struct symbol *sym)
+{
+	return get_state(my_id, var, sym) == &fresh;
+}
+
+bool is_fresh_alloc(struct expression *expr)
+{
+	sval_t sval;
+	int i;
+
+	if (!expr)
+		return false;
+
+	if (get_implied_value_fast(expr, &sval) && sval.value == 0)
+		return false;
+
+	if (get_state_expr(my_id, expr) == &fresh)
+		return true;
+
+	if (expr->type != EXPR_CALL)
+		return false;
+	if (fresh_from_db(expr))
+		return true;
+	i = -1;
+	while (alloc_funcs[++i].fn) {
+		if (sym_name_is(kernel_allocation_funcs[i].fn, expr->fn))
+			return true;
+	}
+	return false;
+}
+
+static void record_alloc_func(int return_id, char *return_ranges, struct expression *expr)
+{
+	if (!is_fresh_alloc(expr))
+		return;
+	sql_insert_return_states(return_id, return_ranges, FRESH_ALLOC, -1, "$", "");
+}
+
+static void set_unfresh(struct expression *expr)
+{
+	struct sm_state *sm;
+
+	sm = get_sm_state_expr(my_id, expr);
+	if (!sm)
+		return;
+	if (!slist_has_state(sm->possible, &fresh))
+		return;
+	// TODO call unfresh hooks
+	set_state_expr(my_id, expr, &undefined);
+}
+
+static void match_assign(struct expression *expr)
+{
+	set_unfresh(expr->right);
+}
+
+static void match_call(struct expression *expr)
+{
+	struct expression *arg;
+
+	FOR_EACH_PTR(expr->args, arg) {
+		set_unfresh(arg);
+	} END_FOR_EACH_PTR(arg);
+}
+
+static void set_fresh(struct expression *expr)
+{
+	expr = strip_expr(expr);
+	if (expr->type != EXPR_SYMBOL)
+		return;
+	set_state_expr(my_id, expr, &fresh);
+}
+
+static void returns_fresh_alloc(struct expression *expr, int param, char *key, char *value)
+{
+	if (param != -1 || !key || strcmp(key, "$") != 0)
+		return;
+	if (expr->type != EXPR_ASSIGNMENT)
+		return;
+
+	set_fresh(expr->left);
+}
+
+static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
+{
+	set_fresh(expr->left);
+}
+
+void register_fresh_alloc(int id)
+{
+	int i;
+
+	my_id = id;
+
+	if (option_project == PROJ_KERNEL)
+		alloc_funcs = kernel_allocation_funcs;
+	else
+		alloc_funcs = general_allocation_funcs;
+
+	i = -1;
+	while (alloc_funcs[++i].fn)
+		add_function_assign_hook(alloc_funcs[i].fn, &match_alloc, 0);
+
+	add_split_return_callback(&record_alloc_func);
+	select_return_states_hook(FRESH_ALLOC, &returns_fresh_alloc);
+	add_hook(&match_assign, ASSIGNMENT_HOOK);
+	add_hook(&match_call, FUNCTION_CALL_HOOK);
+}
--- a/usr/src/tools/smatch/src/smatch_math.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch_math.c	Wed Jan 22 16:05:13 2020 -0800
@@ -1606,6 +1606,26 @@
 	return 1;
 }
 
+int get_implied_value_fast(struct expression *expr, sval_t *sval)
+{
+	struct range_list *rl;
+	static int recurse;
+	int ret = 0;
+
+	if (recurse)
+		return 0;
+
+	recurse = 1;
+	set_fast_math_only();
+	if (get_rl_helper(expr, RL_IMPLIED, &rl) &&
+	    rl_to_sval(rl, sval))
+		ret = 1;
+	clear_fast_math_only();
+	recurse = 0;
+
+	return ret;
+}
+
 int get_implied_min(struct expression *expr, sval_t *sval)
 {
 	struct range_list *rl;
--- a/usr/src/tools/smatch/src/smatch_mtag.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch_mtag.c	Wed Jan 22 16:05:13 2020 -0800
@@ -50,7 +50,7 @@
 
 static int my_id;
 
-static mtag_t str_to_tag(const char *str)
+mtag_t str_to_mtag(const char *str)
 {
 	unsigned char c[MD5_DIGEST_LENGTH];
 	unsigned long long *tag = (unsigned long long *)&c;
@@ -132,7 +132,7 @@
 
 	snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
 		 left_name, right_name);
-	tag = str_to_tag(buf);
+	tag = str_to_mtag(buf);
 	tag_sval.type = estate_type(state);
 	tag_sval.uvalue = tag;
 
@@ -156,8 +156,8 @@
 		return 0;
 
 	/* I was worried about collisions so I added a xor */
-	xor = str_to_tag("__smatch string");
-	*tag = str_to_tag(expr->string->data);
+	xor = str_to_mtag("__smatch string");
+	*tag = str_to_mtag(expr->string->data);
 	*tag = *tag ^ xor;
 
 	return 1;
@@ -177,7 +177,7 @@
 	snprintf(buf, sizeof(buf), "%s %s",
 		 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
 		 sym->ident->name);
-	*tag = str_to_tag(buf);
+	*tag = str_to_mtag(buf);
 	return 1;
 }
 
@@ -196,7 +196,7 @@
 
 	snprintf(buf, sizeof(buf), "%s %s %s",
 		 get_filename(), get_function(), sym->ident->name);
-	*tag = str_to_tag(buf);
+	*tag = str_to_mtag(buf);
 	return true;
 }
 
@@ -258,7 +258,7 @@
 	name = expr_to_str(expr);
 	snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
 	free_string(name);
-	tag = str_to_tag(buf);
+	tag = str_to_mtag(buf);
 	sval.value = tag;
 	return alloc_rl(sval, sval);
 }
@@ -284,7 +284,7 @@
 	snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
 	free_string(str);
 
-	*new = str_to_tag(buf);
+	*new = str_to_mtag(buf);
 	sql_insert_mtag_alias(tag, *new);
 
 	return 1;
--- a/usr/src/tools/smatch/src/smatch_slist.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch_slist.c	Wed Jan 22 16:05:13 2020 -0800
@@ -78,11 +78,13 @@
 {
 	struct sm_state *sm;
 
-	printf("dumping stree at %d [%ld states]\n", get_lineno(), stree_count(stree));
+	option_debug++;
+	sm_msg("dumping stree [%ld states]", stree_count(stree));
 	FOR_EACH_SM(stree, sm) {
-		printf("%s\n", show_sm(sm));
+		sm_printf("%s\n", show_sm(sm));
 	} END_FOR_EACH_SM(sm);
-	printf("---\n");
+	sm_printf("---\n");
+	option_debug--;
 }
 
 /* NULL states go at the end to simplify merge_slist */
--- a/usr/src/tools/smatch/src/smatch_type.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/smatch_type.c	Wed Jan 22 16:05:13 2020 -0800
@@ -789,7 +789,7 @@
 	int n;
 
 	if (!type)
-		return snprintf(buf, size, "<unknown>");
+		return snprintf(buf, size, "<null type>");
 
 	if (type->type == SYM_BASETYPE) {
 		return snprintf(buf, size, "%s", base_type_str(type));
--- a/usr/src/tools/smatch/src/validation/sm_locking2.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/validation/sm_locking2.c	Wed Jan 22 16:05:13 2020 -0800
@@ -30,10 +30,9 @@
  * check-command: smatch --project=kernel sm_locking2.c
  *
  * check-output-start
-sm_locking2.c:21 func() error: double unlock 'spin_lock:mylock'
-sm_locking2.c:26 func() warn: inconsistent returns 'spin_lock:mylock3'.
-  Locked on:   line 26
-  Unlocked on: line 14
-               line 25
+sm_locking2.c:21 func() error: double unlocked 'mylock' (orig line 17)
+sm_locking2.c:26 func() warn: inconsistent returns 'mylock3'.
+  Locked on  : 26
+  Unlocked on: 25
  * check-output-end
  */
--- a/usr/src/tools/smatch/src/validation/sm_locking3.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/validation/sm_locking3.c	Wed Jan 22 16:05:13 2020 -0800
@@ -24,10 +24,9 @@
  * check-command: smatch --project=kernel sm_locking3.c
  *
  * check-output-start
-sm_locking3.c:18 func() error: double unlock 'spin_lock:mylock'
-sm_locking3.c:20 func() warn: inconsistent returns 'spin_lock:mylock'.
-  Locked on:   line 16
-  Unlocked on: line 10
-               line 20
+sm_locking3.c:18 func() error: double unlocked 'mylock' (orig line 15)
+sm_locking3.c:20 func() warn: inconsistent returns 'mylock'.
+  Locked on  : 16
+  Unlocked on: 10,20
  * check-output-end
  */
--- a/usr/src/tools/smatch/src/validation/sm_locking4.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/validation/sm_locking4.c	Wed Jan 22 16:05:13 2020 -0800
@@ -28,9 +28,8 @@
  * check-command: smatch --project=kernel sm_locking4.c
  *
  * check-output-start
-sm_locking4.c:23 func() warn: inconsistent returns 'spin_lock:mylock'.
-  Locked on:   line 22
-               line 23
-  Unlocked on: line 16
+sm_locking4.c:23 func() warn: inconsistent returns 'mylock'.
+  Locked on  : 22-23
+  Unlocked on: 16
  * check-output-end
  */
--- a/usr/src/tools/smatch/src/validation/sm_locking6.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/validation/sm_locking6.c	Wed Jan 22 16:05:13 2020 -0800
@@ -31,15 +31,11 @@
  * check-command: smatch -p=kernel sm_locking6.c
  *
  * check-output-start
-sm_locking6.c:27 func() warn: inconsistent returns 'irqsave:flags'.
-  Locked on:   line 26
-  Unlocked on: line 21
-               line 24
-               line 27
-sm_locking6.c:27 func() warn: inconsistent returns 'spin_lock:lock'.
-  Locked on:   line 26
-  Unlocked on: line 21
-               line 24
-               line 27
+sm_locking6.c:27 func() warn: inconsistent returns 'flags'.
+  Locked on  : 26
+  Unlocked on: 21,24,27
+sm_locking6.c:27 func() warn: inconsistent returns 'lock'.
+  Locked on  : 26
+  Unlocked on: 21,24,27
  * check-output-end
  */
--- a/usr/src/tools/smatch/src/validation/sm_locking7.c	Thu Jan 23 17:12:56 2020 -0600
+++ b/usr/src/tools/smatch/src/validation/sm_locking7.c	Wed Jan 22 16:05:13 2020 -0800
@@ -27,11 +27,11 @@
  * check-command: smatch -p=kernel -I.. sm_locking7.c
  *
  * check-output-start
-sm_locking7.c:22 func() warn: inconsistent returns 'irqsave:flags'.
-  Locked on:   line 21
-  Unlocked on: line 22
-sm_locking7.c:22 func() warn: inconsistent returns 'spin_lock:&lock'.
-  Locked on:   line 21
-  Unlocked on: line 22
+sm_locking7.c:22 func() warn: inconsistent returns 'flags'.
+  Locked on  : 21
+  Unlocked on: 22
+sm_locking7.c:22 func() warn: inconsistent returns 'lock'.
+  Locked on  : 21
+  Unlocked on: 22
  * check-output-end
  */