--- /dev/null	Fri Dec 21 15:00:36 2018
+++ new/usr/src/tools/smatch/src/smatch_strings.c	Fri Dec 21 15:00:36 2018
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015 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
+ */
+
+#include "smatch.h"
+#include "smatch_slist.h"
+#include "smatch_extra.h"
+
+static int my_id;
+
+static int get_str(void *_ret, int argc, char **argv, char **azColName)
+{
+	char **ret = _ret;
+
+	if (*ret)
+		*ret = (void *)-1UL;
+	else
+		*ret = alloc_sname(argv[0]);
+
+	return 0;
+}
+
+static char *get_string_from_mtag(mtag_t tag)
+{
+	char *str = NULL;
+
+	run_sql(get_str, &str,
+		"select value from mtag_data where tag = %lld and offset = 0 and type = %d;",
+		tag, STRING_VALUE);
+
+	if ((unsigned long)str == -1UL)
+		return NULL;
+	return str;
+}
+
+struct expression *fake_string_from_mtag(mtag_t tag)
+{
+	char *str;
+
+	if (!tag)
+		return NULL;
+	str = get_string_from_mtag(tag);
+	if (!str)
+		return NULL;
+	return string_expression(str);
+}
+
+static void match_strcpy(const char *fn, struct expression *expr, void *unused)
+{
+	struct expression *dest, *src;
+
+	dest = get_argument_from_call_expr(expr->args, 0);
+	src = get_argument_from_call_expr(expr->args, 1);
+	src = strip_expr(src);
+	if (src->type == EXPR_STRING)
+		set_state_expr(my_id, dest, alloc_state_str(src->string->data));
+}
+
+struct state_list *get_strings(struct expression *expr)
+{
+	struct state_list *ret = NULL;
+	struct smatch_state *state;
+	struct sm_state *sm;
+
+	expr = strip_expr(expr);
+	if (expr->type == EXPR_STRING) {
+		state = alloc_state_str(expr->string->data);
+		sm = alloc_sm_state(my_id, expr->string->data, NULL, state);
+		add_ptr_list(&ret, sm);
+		return ret;
+	}
+
+	if (expr->type == EXPR_CONDITIONAL ||
+	    expr->type == EXPR_SELECT) {
+		struct state_list *true_strings = NULL;
+		struct state_list *false_strings = NULL;
+
+		if (known_condition_true(expr->conditional))
+			return get_strings(expr->cond_true);
+		if (known_condition_false(expr->conditional))
+			return get_strings(expr->cond_false);
+
+		true_strings = get_strings(expr->cond_true);
+		false_strings = get_strings(expr->cond_false);
+		concat_ptr_list((struct ptr_list *)true_strings, (struct ptr_list **)&false_strings);
+		free_slist(&true_strings);
+		return false_strings;
+	}
+
+	sm = get_sm_state_expr(my_id, expr);
+	if (!sm)
+		return NULL;
+
+	return clone_slist(sm->possible);
+}
+
+static void match_assignment(struct expression *expr)
+{
+	struct state_list *slist;
+	struct sm_state *sm;
+
+	if (expr->op != '=')
+		return;
+
+	slist = get_strings(strip_expr(expr->right));
+	if (!slist)
+		return;
+
+	if (ptr_list_size((struct ptr_list *)slist) == 1) {
+		sm = first_ptr_list((struct ptr_list *)slist);
+		set_state_expr(my_id, expr->left, sm->state);
+		return;
+	}
+}
+
+static void match_string(struct expression *expr)
+{
+	mtag_t tag;
+
+	if (expr->type != EXPR_STRING || !expr->string->data)
+		return;
+	if (expr->string->length > 255)
+		return;
+
+	if (!get_string_mtag(expr, &tag))
+		return;
+
+	cache_sql(NULL, NULL, "insert into mtag_data values (%lld, %d, %d, '%q');",
+		  tag, 0, STRING_VALUE, escape_newlines(expr->string->data));
+}
+
+void register_strings(int id)
+{
+	my_id = id;
+
+	add_function_hook("strcpy", &match_strcpy, NULL);
+	add_function_hook("strlcpy", &match_strcpy, NULL);
+	add_function_hook("strncpy", &match_strcpy, NULL);
+
+	add_hook(&match_assignment, ASSIGNMENT_HOOK);
+	add_hook(&match_string, STRING_HOOK);
+
+}
