1 /* 2 * Copyright (C) 2012 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 /* 19 * This works together with smatch_clear_buffer.c. This one is only for 20 * tracking the information and smatch_clear_buffer.c changes SMATCH_EXTRA. 21 * 22 * This tracks functions like memset() which clear out a chunk of memory. 23 * It fills in a gap that smatch_param_set.c can't handle. It only handles 24 * void pointers because smatch_param_set.c should handle the rest. Oh. And 25 * also it handles arrays because Smatch sucks at handling arrays. 26 */ 27 28 #include "scope.h" 29 #include "smatch.h" 30 #include "smatch_slist.h" 31 #include "smatch_extra.h" 32 33 static int my_id; 34 35 STATE(cleared); 36 STATE(zeroed); 37 38 static void db_param_cleared(struct expression *expr, int param, char *key, char *value) 39 { 40 struct expression *arg; 41 char *name; 42 struct symbol *sym; 43 44 while (expr->type == EXPR_ASSIGNMENT) 45 expr = strip_expr(expr->right); 46 if (expr->type != EXPR_CALL) 47 return; 48 49 arg = get_argument_from_call_expr(expr->args, param); 50 arg = strip_expr(arg); 51 name = get_variable_from_key(arg, key, &sym); 52 if (!name || !sym) 53 goto free; 54 55 if (strcmp(value, "0") == 0) 56 set_state(my_id, name, sym, &zeroed); 57 else 58 set_state(my_id, name, sym, &cleared); 59 free: 60 free_string(name); 61 } 62 63 static void match_memset(const char *fn, struct expression *expr, void *arg) 64 { 65 db_param_cleared(expr, PTR_INT(arg), (char *)"$", (char *)"0"); 66 } 67 68 static void match_memcpy(const char *fn, struct expression *expr, void *arg) 69 { 70 db_param_cleared(expr, PTR_INT(arg), (char *)"$", (char *)""); 71 } 72 73 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr) 74 { 75 struct stree *stree; 76 struct sm_state *sm; 77 int param; 78 const char *param_name; 79 80 stree = __get_cur_stree(); 81 82 FOR_EACH_MY_SM(my_id, stree, sm) { 83 param = get_param_num_from_sym(sm->sym); 84 if (param < 0) 85 continue; 86 87 param_name = get_param_name(sm); 88 if (!param_name) 89 continue; 90 91 if (sm->state == &zeroed) { 92 sql_insert_return_states(return_id, return_ranges, 93 PARAM_CLEARED, param, param_name, "0"); 94 } 95 96 if (sm->state == &cleared) { 97 sql_insert_return_states(return_id, return_ranges, 98 PARAM_CLEARED, param, param_name, ""); 99 } 100 } END_FOR_EACH_SM(sm); 101 } 102 103 static void register_clears_param(void) 104 { 105 struct token *token; 106 char name[256]; 107 const char *function; 108 int param; 109 110 if (option_project == PROJ_NONE) 111 return; 112 113 snprintf(name, 256, "%s.clears_argument", option_project_str); 114 115 token = get_tokens_file(name); 116 if (!token) 117 return; 118 if (token_type(token) != TOKEN_STREAMBEGIN) 119 return; 120 token = token->next; 121 while (token_type(token) != TOKEN_STREAMEND) { 122 if (token_type(token) != TOKEN_IDENT) 123 return; 124 function = show_ident(token->ident); 125 token = token->next; 126 if (token_type(token) != TOKEN_NUMBER) 127 return; 128 param = atoi(token->number); 129 add_function_hook(function, &match_memcpy, INT_PTR(param)); 130 token = token->next; 131 } 132 clear_token_alloc(); 133 } 134 135 #define USB_DIR_IN 0x80 136 static void match_usb_control_msg(const char *fn, struct expression *expr, void *_size_arg) 137 { 138 struct expression *inout; 139 sval_t sval; 140 141 inout = get_argument_from_call_expr(expr->args, 3); 142 143 if (get_value(inout, &sval) && !(sval.uvalue & USB_DIR_IN)) 144 return; 145 146 db_param_cleared(expr, 6, (char *)"$", (char *)""); 147 } 148 149 static void match_assign(struct expression *expr) 150 { 151 struct symbol *type; 152 153 /* 154 * If we have struct foo x, y; and we say that x = y; then it 155 * initializes the struct holes. So we record that here. 156 */ 157 type = get_type(expr->left); 158 if (!type || type->type != SYM_STRUCT) 159 return; 160 set_state_expr(my_id, expr->left, &cleared); 161 } 162 163 static void match_array_assign(struct expression *expr) 164 { 165 struct expression *array_expr; 166 167 if (!is_array(expr->left)) 168 return; 169 170 array_expr = get_array_base(expr->left); 171 set_state_expr(my_id, array_expr, &cleared); 172 } 173 174 void register_param_cleared(int id) 175 { 176 my_id = id; 177 178 add_function_hook("memset", &match_memset, INT_PTR(0)); 179 add_function_hook("memzero", &match_memset, INT_PTR(0)); 180 add_function_hook("__memset", &match_memset, INT_PTR(0)); 181 add_function_hook("__memzero", &match_memset, INT_PTR(0)); 182 183 add_function_hook("memcpy", &match_memcpy, INT_PTR(0)); 184 add_function_hook("memmove", &match_memcpy, INT_PTR(0)); 185 add_function_hook("__memcpy", &match_memcpy, INT_PTR(0)); 186 add_function_hook("__memmove", &match_memcpy, INT_PTR(0)); 187 add_function_hook("strcpy", &match_memcpy, INT_PTR(0)); 188 add_function_hook("strncpy", &match_memcpy, INT_PTR(0)); 189 add_function_hook("sprintf", &match_memcpy, INT_PTR(0)); 190 add_function_hook("snprintf", &match_memcpy, INT_PTR(0)); 191 192 add_hook(&match_assign, ASSIGNMENT_HOOK); 193 add_hook(&match_array_assign, ASSIGNMENT_HOOK); 194 195 register_clears_param(); 196 197 select_return_states_hook(PARAM_CLEARED, &db_param_cleared); 198 add_split_return_callback(&print_return_value_param); 199 200 if (option_project == PROJ_KERNEL) { 201 add_function_hook("usb_control_msg", &match_usb_control_msg, NULL); 202 } 203 204 } 205 206