--- old/usr/src/tools/smatch/src/smatch_function_hooks.c	Tue May 19 02:50:33 2020
+++ new/usr/src/tools/smatch/src/smatch_function_hooks.c	Tue May 19 02:50:33 2020
@@ -357,6 +357,7 @@
 	struct range_list *rl;
 	int left;
 	struct stree *stree;
+	struct stree *implied;
 	struct db_implies_list *callbacks;
 	int prev_return_id;
 	int cull;
@@ -367,6 +368,17 @@
 	int handled;
 };
 
+static void set_implied_states(struct db_callback_info *db_info)
+{
+	struct sm_state *sm;
+
+	FOR_EACH_SM(db_info->implied, sm) {
+		__set_sm(sm);
+	} END_FOR_EACH_SM(sm);
+
+	free_stree(&db_info->implied);
+}
+
 static void store_return_state(struct db_callback_info *db_info, const char *ret_str, struct smatch_state *state)
 {
 	db_info->ret_str = alloc_sname(ret_str),
@@ -460,6 +472,26 @@
 	return true;
 }
 
+static void set_fresh_mtag_returns(struct db_callback_info *db_info)
+{
+	struct expression *expr = db_info->expr->left;
+	struct smatch_state *state;
+
+	if (!db_info->ret_state)
+		return;
+
+	state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
+	state = get_mtag_return(db_info->expr, state);
+	if (!state)
+		return;
+
+	set_real_absolute(expr, state);
+	set_extra_expr_mod(expr, state);
+
+	db_info->ret_state = NULL;
+	db_info->ret_str = NULL;
+}
+
 static void set_return_assign_state(struct db_callback_info *db_info)
 {
 	struct expression *expr = db_info->expr->left;
@@ -635,8 +667,8 @@
 	db_info->has_states = 1;
 	if (db_info->prev_return_id != -1 && type == INTERNAL) {
 		set_other_side_state(db_info);
+		set_implied_states(db_info);
 		stree = __pop_fake_cur_stree();
-
 		if (!db_info->cull)
 			merge_fake_stree(&db_info->stree, stree);
 		free_stree(&stree);
@@ -672,7 +704,7 @@
 		if (!possibly_true_rl(var_rl, comparison, ret_range))
 			return 0;
 		if (type == PARAM_LIMIT)
-			param_limit_implications(db_info->expr, param, key, value);
+			param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
 		filter_by_comparison(&var_rl, comparison, ret_range);
 		filter_by_comparison(&ret_range, flip_comparison(comparison), var_rl);
 	} else {
@@ -679,7 +711,7 @@
 		if (!possibly_false_rl(var_rl, comparison, ret_range))
 			return 0;
 		if (type == PARAM_LIMIT)
-			param_limit_implications(db_info->expr, param, key, value);
+			param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
 		filter_by_comparison(&var_rl, negate_comparison(comparison), ret_range);
 		filter_by_comparison(&ret_range, flip_comparison(negate_comparison(comparison)), var_rl);
 	}
@@ -744,6 +776,7 @@
 	sql_select_return_states("return_id, return, type, parameter, key, value",
 				 call_expr, db_compare_callback, &db_info);
 	set_other_side_state(&db_info);
+	set_implied_states(&db_info);
 	stree = __pop_fake_cur_stree();
 	if (!db_info.cull)
 		merge_fake_stree(&db_info.stree, stree);
@@ -769,6 +802,7 @@
 	sql_select_return_states("return_id, return, type, parameter, key, value", call_expr,
 			db_compare_callback, &db_info);
 	set_other_side_state(&db_info);
+	set_implied_states(&db_info);
 	stree = __pop_fake_cur_stree();
 	if (!db_info.cull)
 		merge_fake_stree(&db_info.stree, stree);
@@ -893,6 +927,7 @@
 	if (db_info->prev_return_id != -1 && type == INTERNAL) {
 		call_ranged_return_hooks(db_info);
 		set_return_assign_state(db_info);
+		set_implied_states(db_info);
 		stree = __pop_fake_cur_stree();
 		if (!db_info->cull)
 			merge_fake_stree(&db_info->stree, stree);
@@ -916,7 +951,7 @@
 	}
 
 	if (type == PARAM_LIMIT)
-		param_limit_implications(db_info->expr, param, key, value);
+		param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
 
 	db_info->handled = 1;
 	call_results_to_rl(db_info->expr->right, get_type(strip_expr(db_info->expr->right)), ret_str, &ret_range);
@@ -930,6 +965,7 @@
 		__add_comparison_info(db_info->expr->left, strip_expr(db_info->expr->right), ret_str);
 		__add_return_to_param_mapping(db_info->expr, ret_str);
 		store_return_state(db_info, ret_str, alloc_estate_rl(ret_range));
+		set_fresh_mtag_returns(db_info);
 	}
 
 	FOR_EACH_PTR(db_return_states_list, tmp) {
@@ -968,6 +1004,7 @@
 	if (db_info.handled)
 		call_ranged_return_hooks(&db_info);
 	set_return_assign_state(&db_info);
+	set_implied_states(&db_info);
 	stree = __pop_fake_cur_stree();
 	if (!db_info.cull)
 		merge_fake_stree(&db_info.stree, stree);
@@ -1079,6 +1116,7 @@
 
 	if (db_info->prev_return_id != -1 && type == INTERNAL) {
 		call_ranged_return_hooks(db_info);
+		set_implied_states(db_info);
 		stree = __pop_fake_cur_stree();
 		if (!db_info->cull)
 			merge_fake_stree(&db_info->stree, stree);
@@ -1103,7 +1141,7 @@
 	}
 
 	if (type == PARAM_LIMIT)
-		param_limit_implications(db_info->expr, param, key, value);
+		param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
 
 	call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
 	ret_range = cast_rl(get_type(db_info->expr), ret_range);
@@ -1154,6 +1192,7 @@
 	sql_select_return_states("return_id, return, type, parameter, key, value",
 			expr, db_return_states_callback, &db_info);
 	call_ranged_return_hooks(&db_info);
+	set_implied_states(&db_info);
 	stree = __pop_fake_cur_stree();
 	if (!db_info.cull)
 		merge_fake_stree(&db_info.stree, stree);
