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 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 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 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 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 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 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 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 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