strings: fix crash bug parsing foo = bar ?: baz
[smatch.git] / smatch_strings.c
blob66b69e0af6e6cdb8226ae7116e6a3807f5438e15
1 /*
2 * Copyright (C) 2015 Oracle.
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.
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.
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
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
22 static int my_id;
24 static int get_str(void *_ret, int argc, char **argv, char **azColName)
26 char **ret = _ret;
28 if (*ret)
29 *ret = (void *)-1UL;
30 else
31 *ret = alloc_sname(argv[0]);
33 return 0;
36 static char *get_string_from_mtag(mtag_t tag)
38 char *str = NULL;
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);
44 if ((unsigned long)str == -1UL)
45 return NULL;
46 return str;
49 struct expression *fake_string_from_mtag(mtag_t tag)
51 char *str;
53 if (!tag)
54 return NULL;
55 str = get_string_from_mtag(tag);
56 if (!str)
57 return NULL;
58 return gen_string_expression(str);
61 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
63 struct expression *dest, *src;
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));
72 struct state_list *get_strings(struct expression *expr)
74 struct state_list *ret = NULL;
75 struct smatch_state *state;
76 struct sm_state *sm;
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;
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;
91 if (known_condition_true(expr->conditional)) {
92 if (expr->cond_true)
93 return get_strings(expr->cond_true);
94 return get_strings(expr->conditional);
96 if (known_condition_false(expr->conditional))
97 return get_strings(expr->cond_false);
99 if (expr->cond_true)
100 true_strings = get_strings(expr->cond_true);
101 else
102 true_strings = get_strings(expr->conditional);
103 false_strings = get_strings(expr->cond_false);
104 concat_ptr_list((struct ptr_list *)true_strings, (struct ptr_list **)&false_strings);
105 free_slist(&true_strings);
106 return false_strings;
109 sm = get_sm_state_expr(my_id, expr);
110 if (!sm)
111 return NULL;
113 return clone_slist(sm->possible);
116 static void match_assignment(struct expression *expr)
118 struct state_list *slist;
119 struct sm_state *sm;
121 if (expr->op != '=')
122 return;
124 slist = get_strings(strip_expr(expr->right));
125 if (!slist)
126 return;
128 if (ptr_list_size((struct ptr_list *)slist) == 1) {
129 sm = first_ptr_list((struct ptr_list *)slist);
130 set_state_expr(my_id, expr->left, sm->state);
131 return;
135 static void match_string(struct expression *expr)
137 mtag_t tag;
139 if (expr->type != EXPR_STRING)
140 return;
141 if (expr->string->length > 255)
142 return;
144 if (!get_string_mtag(expr, &tag))
145 return;
147 cache_sql(NULL, NULL, "insert or ignore into mtag_data values (%lld, %d, %d, '%q');",
148 tag, 0, STRING_VALUE, escape_newlines(expr->string->data));
151 void register_strings(int id)
153 my_id = id;
155 add_function_hook("strcpy", &match_strcpy, NULL);
156 add_function_hook("strlcpy", &match_strcpy, NULL);
157 add_function_hook("strncpy", &match_strcpy, NULL);
159 add_hook(&match_assignment, ASSIGNMENT_HOOK);
160 add_hook(&match_string, STRING_HOOK);