#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);
}