1 /*
2  * Copyright (C) 2015 Oracle.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16  */
17 
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
21 
22 static int my_id;
23 
get_str(void * _ret,int argc,char ** argv,char ** azColName)24 static int get_str(void *_ret, int argc, char **argv, char **azColName)
25 {
26 	char **ret = _ret;
27 
28 	if (*ret)
29 		*ret = (void *)-1UL;
30 	else
31 		*ret = alloc_sname(argv[0]);
32 
33 	return 0;
34 }
35 
get_string_from_mtag(mtag_t tag)36 static char *get_string_from_mtag(mtag_t tag)
37 {
38 	char *str = NULL;
39 
40 	run_sql(get_str, &str,
41 		"select value from mtag_data where tag = %lld and offset = 0 and type = %d;",
42 		tag, STRING_VALUE);
43 
44 	if ((unsigned long)str == -1UL)
45 		return NULL;
46 	return str;
47 }
48 
fake_string_from_mtag(mtag_t tag)49 struct expression *fake_string_from_mtag(mtag_t tag)
50 {
51 	char *str;
52 
53 	if (!tag)
54 		return NULL;
55 	str = get_string_from_mtag(tag);
56 	if (!str)
57 		return NULL;
58 	return string_expression(str);
59 }
60 
match_strcpy(const char * fn,struct expression * expr,void * unused)61 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
62 {
63 	struct expression *dest, *src;
64 
65 	dest = get_argument_from_call_expr(expr->args, 0);
66 	src = get_argument_from_call_expr(expr->args, 1);
67 	src = strip_expr(src);
68 	if (src->type == EXPR_STRING)
69 		set_state_expr(my_id, dest, alloc_state_str(src->string->data));
70 }
71 
get_strings(struct expression * expr)72 struct state_list *get_strings(struct expression *expr)
73 {
74 	struct state_list *ret = NULL;
75 	struct smatch_state *state;
76 	struct sm_state *sm;
77 
78 	expr = strip_expr(expr);
79 	if (expr->type == EXPR_STRING) {
80 		state = alloc_state_str(expr->string->data);
81 		sm = alloc_sm_state(my_id, expr->string->data, NULL, state);
82 		add_ptr_list(&ret, sm);
83 		return ret;
84 	}
85 
86 	if (expr->type == EXPR_CONDITIONAL ||
87 	    expr->type == EXPR_SELECT) {
88 		struct state_list *true_strings = NULL;
89 		struct state_list *false_strings = NULL;
90 
91 		if (known_condition_true(expr->conditional))
92 			return get_strings(expr->cond_true);
93 		if (known_condition_false(expr->conditional))
94 			return get_strings(expr->cond_false);
95 
96 		true_strings = get_strings(expr->cond_true);
97 		false_strings = get_strings(expr->cond_false);
98 		concat_ptr_list((struct ptr_list *)true_strings, (struct ptr_list **)&false_strings);
99 		free_slist(&true_strings);
100 		return false_strings;
101 	}
102 
103 	sm = get_sm_state_expr(my_id, expr);
104 	if (!sm)
105 		return NULL;
106 
107 	return clone_slist(sm->possible);
108 }
109 
match_assignment(struct expression * expr)110 static void match_assignment(struct expression *expr)
111 {
112 	struct state_list *slist;
113 	struct sm_state *sm;
114 
115 	if (expr->op != '=')
116 		return;
117 
118 	slist = get_strings(strip_expr(expr->right));
119 	if (!slist)
120 		return;
121 
122 	if (ptr_list_size((struct ptr_list *)slist) == 1) {
123 		sm = first_ptr_list((struct ptr_list *)slist);
124 		set_state_expr(my_id, expr->left, sm->state);
125 		return;
126 	}
127 }
128 
match_string(struct expression * expr)129 static void match_string(struct expression *expr)
130 {
131 	mtag_t tag;
132 
133 	if (expr->type != EXPR_STRING || !expr->string->data)
134 		return;
135 	if (expr->string->length > 255)
136 		return;
137 
138 	if (!get_string_mtag(expr, &tag))
139 		return;
140 
141 	cache_sql(NULL, NULL, "insert into mtag_data values (%lld, %d, %d, '%q');",
142 		  tag, 0, STRING_VALUE, escape_newlines(expr->string->data));
143 }
144 
register_strings(int id)145 void register_strings(int id)
146 {
147 	my_id = id;
148 
149 	add_function_hook("strcpy", &match_strcpy, NULL);
150 	add_function_hook("strlcpy", &match_strcpy, NULL);
151 	add_function_hook("strncpy", &match_strcpy, NULL);
152 
153 	add_hook(&match_assignment, ASSIGNMENT_HOOK);
154 	add_hook(&match_string, STRING_HOOK);
155 
156 }
157