From 3bc671b6e7acbc82f7b111ba31209d90405e44ef Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 31 Aug 2018 23:49:08 +0300 Subject: [PATCH] mtag: add string information This code isn't totally perfect, but if I don't commit it now, then I'm going to just end up forgetting what's involved... Basically we store a string in mtag_data and we have an mtag which points to it. This is only used to calculate strlen() for known strings, but eventually it will be used more often. Signed-off-by: Dan Carpenter --- smatch.h | 6 +++++- smatch_db.c | 32 ++++++++++++++++++++++++++++++- smatch_expressions.c | 20 ++++++++++++++++++++ smatch_extra.h | 1 + smatch_math.c | 19 +++++++++++++++---- smatch_mtag.c | 30 ++++++++++++++++++++++++++--- smatch_strings.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 152 insertions(+), 9 deletions(-) diff --git a/smatch.h b/smatch.h index 828cac36..e59ac470 100644 --- a/smatch.h +++ b/smatch.h @@ -763,6 +763,7 @@ enum info_type { SIZEOF_ARG = 8034, MEMORY_TAG = 8036, MTAG_ASSIGN = 8035, + STRING_VALUE = 8041, }; extern struct sqlite3 *smatch_db; @@ -789,13 +790,14 @@ const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym); const char *get_mtag_name_expr(struct expression *expr); char *get_data_info_name(struct expression *expr); +char *escape_newlines(char *str); void sql_exec(struct sqlite3 *db, int (*callback)(void*, int, char**, char**), void *data, const char *sql); #define sql_helper(db, call_back, data, sql...) \ do { \ char sql_txt[1024]; \ \ - snprintf(sql_txt, sizeof(sql_txt), sql); \ + sqlite3_snprintf(sizeof(sql_txt), sql_txt, sql); \ sm_debug("debug: %s\n", sql_txt); \ debug_sql(db, sql_txt); \ sql_exec(db, call_back, data, sql_txt); \ @@ -1090,6 +1092,7 @@ void mark_all_params_untracked(int return_id, char *return_ranges, struct expres /* smatch_strings.c */ struct state_list *get_strings(struct expression *expr); +struct expression *fake_string_from_mtag(mtag_t tag); /* smatch_estate.c */ int estate_get_single_value(struct smatch_state *state, sval_t *sval); @@ -1121,6 +1124,7 @@ int get_param_from_container_of(struct expression *expr); int get_offset_from_container_of(struct expression *expr); /* smatch_mtag.c */ +int get_string_mtag(struct expression *expr, mtag_t *tag); int get_toplevel_mtag(struct symbol *sym, mtag_t *tag); int get_mtag(struct expression *expr, mtag_t *tag); int get_mtag_offset(struct expression *expr, mtag_t *tag, int *offset); diff --git a/smatch_db.c b/smatch_db.c index be81f6e6..002a8c9d 100644 --- a/smatch_db.c +++ b/smatch_db.c @@ -71,6 +71,32 @@ DECLARE_PTR_LIST(db_implies_cb_list, struct db_implies_callback); static struct db_implies_cb_list *return_implies_cb_list; static struct db_implies_cb_list *call_implies_cb_list; +char *escape_newlines(char *str) +{ + char buf[1024]; + bool found = false; + int i; + + for (i = 0; i < sizeof(buf); i++) { + if (str[i] == '\n') { + found = true; + buf[i++] = '\\'; + buf[i] = 'n'; + continue; + } + buf[i] = str[i]; + if (!str[i]) + break; + } + + if (!found) + return str; + + if (buf[i] == sizeof(buf)) + buf[i - 1] = '\0'; + return alloc_sname(buf); +} + void sql_exec(struct sqlite3 *db, int (*callback)(void*, int, char**, char**), void *data, const char *sql) { char *err = NULL; @@ -2127,6 +2153,7 @@ static void init_cachedb(void) "db/call_implies.schema", "db/return_implies.schema", "db/type_info.schema", + "db/mtag_data.schema", }; static char buf[4096]; int fd; @@ -2168,6 +2195,7 @@ static void init_cachedb(void) static int save_cache_data(void *_table, int argc, char **argv, char **azColName) { static char buf[4096]; + char tmp[256]; char *p = buf; char *table = _table; int i; @@ -2177,7 +2205,8 @@ static int save_cache_data(void *_table, int argc, char **argv, char **azColName for (i = 0; i < argc; i++) { if (i) p += snprintf(p, 4096 - (p - buf), ", "); - p += snprintf(p, 4096 - (p - buf), "'%s'", argv[i]); + sqlite3_snprintf(sizeof(tmp), tmp, "%q", argv[i]); + p += snprintf(p, 4096 - (p - buf), "'%s'", tmp); } p += snprintf(p, 4096 - (p - buf), ");"); @@ -2195,6 +2224,7 @@ static void dump_cache(struct symbol_list *sym_list) cache_sql(&save_cache_data, (char *)"type_info", "select * from type_info;"); cache_sql(&save_cache_data, (char *)"return_implies", "select * from return_implies;"); cache_sql(&save_cache_data, (char *)"call_implies", "select * from call_implies;"); + cache_sql(&save_cache_data, (char *)"mtag_data", "select * from mtag_data;"); } void open_smatch_db(char *db_file) diff --git a/smatch_expressions.c b/smatch_expressions.c index 613a7f1c..f9c5e275 100644 --- a/smatch_expressions.c +++ b/smatch_expressions.c @@ -1,6 +1,7 @@ #include "smatch.h" #include "smatch_extra.h" +DECLARE_ALLOCATOR(sname); __ALLOCATOR(struct expression, "temporary expr", tmp_expression); static struct position get_cur_pos(void) @@ -139,6 +140,25 @@ struct expression *compare_expression(struct expression *left, int op, struct ex return expr; } +struct expression *string_expression(char *str) +{ + struct expression *ret; + struct string *string; + int len; + + len = strlen(str) + 1; + string = (void *)__alloc_sname(4 + len); + string->length = len; + string->immutable = 0; + memcpy(string->data, str, len); + + ret = alloc_tmp_expression(get_cur_pos(), EXPR_STRING); + ret->wide = 0; + ret->string = string; + + return ret; +} + struct expression *gen_expression_from_key(struct expression *arg, const char *key) { struct expression *ret; diff --git a/smatch_extra.h b/smatch_extra.h index cfe76fbc..bde89090 100644 --- a/smatch_extra.h +++ b/smatch_extra.h @@ -201,6 +201,7 @@ struct expression *assign_expression(struct expression *left, int op, struct exp struct expression *binop_expression(struct expression *left, int op, struct expression *right); struct expression *array_element_expression(struct expression *array, struct expression *offset); struct expression *symbol_expression(struct symbol *sym); +struct expression *string_expression(char *str); struct expression *compare_expression(struct expression *left, int op, struct expression *right); struct expression *unknown_value_expression(struct expression *expr); int is_fake_call(struct expression *expr); diff --git a/smatch_math.c b/smatch_math.c index de9f6c0a..e581e522 100644 --- a/smatch_math.c +++ b/smatch_math.c @@ -1020,8 +1020,9 @@ static sval_t handle_sizeof(struct expression *expr) static struct range_list *handle_strlen(struct expression *expr, int implied, int *recurse_cnt) { struct range_list *rl; - struct expression *arg; - sval_t sval = { .type = &ulong_ctype }; + struct expression *arg, *tmp; + sval_t tag; + sval_t ret = { .type = &ulong_ctype }; if (implied == RL_EXACT) return NULL; @@ -1030,8 +1031,13 @@ static struct range_list *handle_strlen(struct expression *expr, int implied, in if (!arg) return NULL; if (arg->type == EXPR_STRING) { - sval.value = arg->string->length - 1; - return alloc_rl(sval, sval); + ret.value = arg->string->length - 1; + return alloc_rl(ret, ret); + } + if (get_implied_value(arg, &tag) && + (tmp = fake_string_from_mtag(tag.uvalue))) { + ret.value = tmp->string->length - 1; + return alloc_rl(ret, ret); } if (implied == RL_HARD || implied == RL_FUZZY) @@ -1184,6 +1190,11 @@ static struct range_list *_get_rl(struct expression *expr, int implied, int *rec case EXPR_CALL: rl = handle_call_rl(expr, implied, recurse_cnt); break; + case EXPR_STRING: + rl = NULL; + if (get_mtag_sval(expr, &sval)) + rl = alloc_rl(sval, sval); + break; default: rl = handle_variable(expr, implied, recurse_cnt); } diff --git a/smatch_mtag.c b/smatch_mtag.c index 0d00cc1d..73065bd2 100644 --- a/smatch_mtag.c +++ b/smatch_mtag.c @@ -113,6 +113,21 @@ static void alloc_assign(const char *fn, struct expression *expr, void *unused) free_string(right_name); } +int get_string_mtag(struct expression *expr, mtag_t *tag) +{ + mtag_t xor; + + if (expr->type != EXPR_STRING || !expr->string) + return 0; + + /* I was worried about collisions so I added a xor */ + xor = str_to_tag("__smatch string"); + *tag = str_to_tag(expr->string->data); + *tag = *tag ^ xor; + + return 1; +} + int get_toplevel_mtag(struct symbol *sym, mtag_t *tag) { char buf[256]; @@ -310,6 +325,12 @@ int get_mtag(struct expression *expr, mtag_t *tag) get_mtag_cnt++; switch (expr->type) { + case EXPR_STRING: + if (get_string_mtag(expr, tag)) { + ret = 1; + goto dec_cnt; + } + break; case EXPR_SYMBOL: if (get_toplevel_mtag(expr->symbol, tag)) { ret = 1; @@ -397,9 +418,6 @@ int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) if (!expr) return 0; - if (get_implied_mtag_offset(expr, tag, offset)) - return 1; - if (is_array(expr)) return get_array_mtag_offset(expr, tag, offset); @@ -410,6 +428,9 @@ int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) return get_mtag(expr->deref, tag); } + if (get_implied_mtag_offset(expr, tag, offset)) + return 1; + return get_mtag(expr, tag); } @@ -439,6 +460,9 @@ int get_mtag_sval(struct expression *expr, sval_t *sval) * */ + if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag)) + goto found; + if (type->type == SYM_ARRAY && get_toplevel_mtag(expr->symbol, &tag)) goto found; diff --git a/smatch_strings.c b/smatch_strings.c index f4ee5233..12357adb 100644 --- a/smatch_strings.c +++ b/smatch_strings.c @@ -17,9 +17,47 @@ #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; @@ -88,6 +126,20 @@ static void match_assignment(struct expression *expr) } } +static void match_string(struct expression *expr) +{ + mtag_t tag; + + if (expr->type != EXPR_STRING || !expr->string->data) + 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; @@ -97,5 +149,6 @@ void register_strings(int id) add_function_hook("strncpy", &match_strcpy, NULL); add_hook(&match_assignment, ASSIGNMENT_HOOK); + add_hook(&match_string, STRING_HOOK); } -- 2.11.4.GIT