1*1f5207b7SJohn Levon /* 2*1f5207b7SJohn Levon * Copyright (C) 2012 Oracle. 3*1f5207b7SJohn Levon * 4*1f5207b7SJohn Levon * This program is free software; you can redistribute it and/or 5*1f5207b7SJohn Levon * modify it under the terms of the GNU General Public License 6*1f5207b7SJohn Levon * as published by the Free Software Foundation; either version 2 7*1f5207b7SJohn Levon * of the License, or (at your option) any later version. 8*1f5207b7SJohn Levon * 9*1f5207b7SJohn Levon * This program is distributed in the hope that it will be useful, 10*1f5207b7SJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*1f5207b7SJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*1f5207b7SJohn Levon * GNU General Public License for more details. 13*1f5207b7SJohn Levon * 14*1f5207b7SJohn Levon * You should have received a copy of the GNU General Public License 15*1f5207b7SJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 16*1f5207b7SJohn Levon */ 17*1f5207b7SJohn Levon 18*1f5207b7SJohn Levon /* 19*1f5207b7SJohn Levon * The point here is to store that a buffer has x bytes even if we don't know 20*1f5207b7SJohn Levon * the value of x. 21*1f5207b7SJohn Levon * 22*1f5207b7SJohn Levon */ 23*1f5207b7SJohn Levon 24*1f5207b7SJohn Levon #include "smatch.h" 25*1f5207b7SJohn Levon #include "smatch_extra.h" 26*1f5207b7SJohn Levon #include "smatch_slist.h" 27*1f5207b7SJohn Levon 28*1f5207b7SJohn Levon static int size_id; 29*1f5207b7SJohn Levon static int link_id; 30*1f5207b7SJohn Levon 31*1f5207b7SJohn Levon /* 32*1f5207b7SJohn Levon * We need this for code which does: 33*1f5207b7SJohn Levon * 34*1f5207b7SJohn Levon * if (size) 35*1f5207b7SJohn Levon * foo = malloc(size); 36*1f5207b7SJohn Levon * 37*1f5207b7SJohn Levon * We want to record that the size of "foo" is "size" even after the merge. 38*1f5207b7SJohn Levon * 39*1f5207b7SJohn Levon */ 40*1f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm) 41*1f5207b7SJohn Levon { 42*1f5207b7SJohn Levon struct expression *size_expr; 43*1f5207b7SJohn Levon sval_t sval; 44*1f5207b7SJohn Levon 45*1f5207b7SJohn Levon if (!sm->state->data) 46*1f5207b7SJohn Levon return &undefined; 47*1f5207b7SJohn Levon size_expr = sm->state->data; 48*1f5207b7SJohn Levon if (!get_implied_value(size_expr, &sval) || sval.value != 0) 49*1f5207b7SJohn Levon return &undefined; 50*1f5207b7SJohn Levon return sm->state; 51*1f5207b7SJohn Levon } 52*1f5207b7SJohn Levon 53*1f5207b7SJohn Levon static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2) 54*1f5207b7SJohn Levon { 55*1f5207b7SJohn Levon struct expression *expr1, *expr2; 56*1f5207b7SJohn Levon 57*1f5207b7SJohn Levon expr1 = s1->data; 58*1f5207b7SJohn Levon expr2 = s2->data; 59*1f5207b7SJohn Levon 60*1f5207b7SJohn Levon if (expr1 && expr2 && expr_equiv(expr1, expr2)) 61*1f5207b7SJohn Levon return s1; 62*1f5207b7SJohn Levon return &merged; 63*1f5207b7SJohn Levon } 64*1f5207b7SJohn Levon 65*1f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr) 66*1f5207b7SJohn Levon { 67*1f5207b7SJohn Levon struct expression *expr; 68*1f5207b7SJohn Levon struct sm_state *tmp; 69*1f5207b7SJohn Levon 70*1f5207b7SJohn Levon expr = sm->state->data; 71*1f5207b7SJohn Levon if (expr) { 72*1f5207b7SJohn Levon set_state_expr(size_id, expr, &undefined); 73*1f5207b7SJohn Levon set_state(link_id, sm->name, sm->sym, &undefined); 74*1f5207b7SJohn Levon return; 75*1f5207b7SJohn Levon } 76*1f5207b7SJohn Levon 77*1f5207b7SJohn Levon FOR_EACH_PTR(sm->possible, tmp) { 78*1f5207b7SJohn Levon expr = tmp->state->data; 79*1f5207b7SJohn Levon if (expr) 80*1f5207b7SJohn Levon set_state_expr(size_id, expr, &undefined); 81*1f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 82*1f5207b7SJohn Levon set_state(link_id, sm->name, sm->sym, &undefined); 83*1f5207b7SJohn Levon } 84*1f5207b7SJohn Levon 85*1f5207b7SJohn Levon static struct smatch_state *alloc_expr_state(struct expression *expr) 86*1f5207b7SJohn Levon { 87*1f5207b7SJohn Levon struct smatch_state *state; 88*1f5207b7SJohn Levon char *name; 89*1f5207b7SJohn Levon 90*1f5207b7SJohn Levon state = __alloc_smatch_state(0); 91*1f5207b7SJohn Levon expr = strip_expr(expr); 92*1f5207b7SJohn Levon name = expr_to_str(expr); 93*1f5207b7SJohn Levon state->name = alloc_sname(name); 94*1f5207b7SJohn Levon free_string(name); 95*1f5207b7SJohn Levon state->data = expr; 96*1f5207b7SJohn Levon return state; 97*1f5207b7SJohn Levon } 98*1f5207b7SJohn Levon 99*1f5207b7SJohn Levon static int bytes_per_element(struct expression *expr) 100*1f5207b7SJohn Levon { 101*1f5207b7SJohn Levon struct symbol *type; 102*1f5207b7SJohn Levon 103*1f5207b7SJohn Levon type = get_type(expr); 104*1f5207b7SJohn Levon if (!type) 105*1f5207b7SJohn Levon return 0; 106*1f5207b7SJohn Levon 107*1f5207b7SJohn Levon if (type->type != SYM_PTR && type->type != SYM_ARRAY) 108*1f5207b7SJohn Levon return 0; 109*1f5207b7SJohn Levon 110*1f5207b7SJohn Levon type = get_base_type(type); 111*1f5207b7SJohn Levon return type_bytes(type); 112*1f5207b7SJohn Levon } 113*1f5207b7SJohn Levon 114*1f5207b7SJohn Levon static void db_save_type_links(struct expression *array, struct expression *size) 115*1f5207b7SJohn Levon { 116*1f5207b7SJohn Levon const char *array_name; 117*1f5207b7SJohn Levon 118*1f5207b7SJohn Levon array_name = get_data_info_name(array); 119*1f5207b7SJohn Levon if (!array_name) 120*1f5207b7SJohn Levon array_name = ""; 121*1f5207b7SJohn Levon sql_insert_data_info(size, ARRAY_LEN, array_name); 122*1f5207b7SJohn Levon } 123*1f5207b7SJohn Levon 124*1f5207b7SJohn Levon static void match_alloc_helper(struct expression *pointer, struct expression *size) 125*1f5207b7SJohn Levon { 126*1f5207b7SJohn Levon struct expression *tmp; 127*1f5207b7SJohn Levon struct sm_state *sm; 128*1f5207b7SJohn Levon sval_t sval; 129*1f5207b7SJohn Levon int cnt = 0; 130*1f5207b7SJohn Levon 131*1f5207b7SJohn Levon pointer = strip_expr(pointer); 132*1f5207b7SJohn Levon size = strip_expr(size); 133*1f5207b7SJohn Levon if (!size || !pointer) 134*1f5207b7SJohn Levon return; 135*1f5207b7SJohn Levon 136*1f5207b7SJohn Levon while ((tmp = get_assigned_expr(size))) { 137*1f5207b7SJohn Levon size = strip_expr(tmp); 138*1f5207b7SJohn Levon if (cnt++ > 5) 139*1f5207b7SJohn Levon break; 140*1f5207b7SJohn Levon } 141*1f5207b7SJohn Levon 142*1f5207b7SJohn Levon if (size->type == EXPR_BINOP && size->op == '*') { 143*1f5207b7SJohn Levon struct expression *mult_left, *mult_right; 144*1f5207b7SJohn Levon 145*1f5207b7SJohn Levon mult_left = strip_expr(size->left); 146*1f5207b7SJohn Levon mult_right = strip_expr(size->right); 147*1f5207b7SJohn Levon 148*1f5207b7SJohn Levon if (get_implied_value(mult_left, &sval) && 149*1f5207b7SJohn Levon sval.value == bytes_per_element(pointer)) 150*1f5207b7SJohn Levon size = mult_right; 151*1f5207b7SJohn Levon else if (get_implied_value(mult_right, &sval) && 152*1f5207b7SJohn Levon sval.value == bytes_per_element(pointer)) 153*1f5207b7SJohn Levon size = mult_left; 154*1f5207b7SJohn Levon else 155*1f5207b7SJohn Levon return; 156*1f5207b7SJohn Levon } 157*1f5207b7SJohn Levon 158*1f5207b7SJohn Levon /* Only save links to variables, not fixed sizes */ 159*1f5207b7SJohn Levon if (get_value(size, &sval)) 160*1f5207b7SJohn Levon return; 161*1f5207b7SJohn Levon 162*1f5207b7SJohn Levon db_save_type_links(pointer, size); 163*1f5207b7SJohn Levon sm = set_state_expr(size_id, pointer, alloc_expr_state(size)); 164*1f5207b7SJohn Levon if (!sm) 165*1f5207b7SJohn Levon return; 166*1f5207b7SJohn Levon set_state_expr(link_id, size, alloc_expr_state(pointer)); 167*1f5207b7SJohn Levon } 168*1f5207b7SJohn Levon 169*1f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg) 170*1f5207b7SJohn Levon { 171*1f5207b7SJohn Levon int size_arg = PTR_INT(_size_arg); 172*1f5207b7SJohn Levon struct expression *pointer, *call, *arg; 173*1f5207b7SJohn Levon 174*1f5207b7SJohn Levon pointer = strip_expr(expr->left); 175*1f5207b7SJohn Levon call = strip_expr(expr->right); 176*1f5207b7SJohn Levon arg = get_argument_from_call_expr(call->args, size_arg); 177*1f5207b7SJohn Levon match_alloc_helper(pointer, arg); 178*1f5207b7SJohn Levon } 179*1f5207b7SJohn Levon 180*1f5207b7SJohn Levon static void match_calloc(const char *fn, struct expression *expr, void *_start_arg) 181*1f5207b7SJohn Levon { 182*1f5207b7SJohn Levon int start_arg = PTR_INT(_start_arg); 183*1f5207b7SJohn Levon struct expression *pointer, *call, *arg; 184*1f5207b7SJohn Levon struct sm_state *tmp; 185*1f5207b7SJohn Levon sval_t sval; 186*1f5207b7SJohn Levon 187*1f5207b7SJohn Levon pointer = strip_expr(expr->left); 188*1f5207b7SJohn Levon call = strip_expr(expr->right); 189*1f5207b7SJohn Levon arg = get_argument_from_call_expr(call->args, start_arg); 190*1f5207b7SJohn Levon if (get_implied_value(arg, &sval) && 191*1f5207b7SJohn Levon sval.value == bytes_per_element(pointer)) 192*1f5207b7SJohn Levon arg = get_argument_from_call_expr(call->args, start_arg + 1); 193*1f5207b7SJohn Levon 194*1f5207b7SJohn Levon db_save_type_links(pointer, arg); 195*1f5207b7SJohn Levon tmp = set_state_expr(size_id, pointer, alloc_expr_state(arg)); 196*1f5207b7SJohn Levon if (!tmp) 197*1f5207b7SJohn Levon return; 198*1f5207b7SJohn Levon set_state_expr(link_id, arg, alloc_expr_state(pointer)); 199*1f5207b7SJohn Levon } 200*1f5207b7SJohn Levon 201*1f5207b7SJohn Levon struct expression *get_size_variable(struct expression *buf) 202*1f5207b7SJohn Levon { 203*1f5207b7SJohn Levon struct smatch_state *state; 204*1f5207b7SJohn Levon 205*1f5207b7SJohn Levon state = get_state_expr(size_id, buf); 206*1f5207b7SJohn Levon if (state) 207*1f5207b7SJohn Levon return state->data; 208*1f5207b7SJohn Levon return NULL; 209*1f5207b7SJohn Levon } 210*1f5207b7SJohn Levon 211*1f5207b7SJohn Levon struct expression *get_array_variable(struct expression *size) 212*1f5207b7SJohn Levon { 213*1f5207b7SJohn Levon struct smatch_state *state; 214*1f5207b7SJohn Levon 215*1f5207b7SJohn Levon state = get_state_expr(link_id, size); 216*1f5207b7SJohn Levon if (state) 217*1f5207b7SJohn Levon return state->data; 218*1f5207b7SJohn Levon return NULL; 219*1f5207b7SJohn Levon } 220*1f5207b7SJohn Levon 221*1f5207b7SJohn Levon static void array_check(struct expression *expr) 222*1f5207b7SJohn Levon { 223*1f5207b7SJohn Levon struct expression *array; 224*1f5207b7SJohn Levon struct expression *size; 225*1f5207b7SJohn Levon struct expression *offset; 226*1f5207b7SJohn Levon char *array_str, *offset_str; 227*1f5207b7SJohn Levon 228*1f5207b7SJohn Levon expr = strip_expr(expr); 229*1f5207b7SJohn Levon if (!is_array(expr)) 230*1f5207b7SJohn Levon return; 231*1f5207b7SJohn Levon 232*1f5207b7SJohn Levon array = get_array_base(expr); 233*1f5207b7SJohn Levon size = get_size_variable(array); 234*1f5207b7SJohn Levon if (!size) 235*1f5207b7SJohn Levon return; 236*1f5207b7SJohn Levon offset = get_array_offset(expr); 237*1f5207b7SJohn Levon if (!possible_comparison(size, SPECIAL_EQUAL, offset)) 238*1f5207b7SJohn Levon return; 239*1f5207b7SJohn Levon 240*1f5207b7SJohn Levon array_str = expr_to_str(array); 241*1f5207b7SJohn Levon offset_str = expr_to_str(offset); 242*1f5207b7SJohn Levon sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str); 243*1f5207b7SJohn Levon free_string(array_str); 244*1f5207b7SJohn Levon free_string(offset_str); 245*1f5207b7SJohn Levon } 246*1f5207b7SJohn Levon 247*1f5207b7SJohn Levon struct db_info { 248*1f5207b7SJohn Levon char *name; 249*1f5207b7SJohn Levon int ret; 250*1f5207b7SJohn Levon }; 251*1f5207b7SJohn Levon 252*1f5207b7SJohn Levon static int db_limitter_callback(void *_info, int argc, char **argv, char **azColName) 253*1f5207b7SJohn Levon { 254*1f5207b7SJohn Levon struct db_info *info = _info; 255*1f5207b7SJohn Levon 256*1f5207b7SJohn Levon /* 257*1f5207b7SJohn Levon * If possible the limitters are tied to the struct they limit. If we 258*1f5207b7SJohn Levon * aren't sure which struct they limit then we use them as limitters for 259*1f5207b7SJohn Levon * everything. 260*1f5207b7SJohn Levon */ 261*1f5207b7SJohn Levon if (!info->name || argv[0][0] == '\0' || strcmp(info->name, argv[0]) == 0) 262*1f5207b7SJohn Levon info->ret = 1; 263*1f5207b7SJohn Levon return 0; 264*1f5207b7SJohn Levon } 265*1f5207b7SJohn Levon 266*1f5207b7SJohn Levon static char *vsl_to_data_info_name(const char *name, struct var_sym_list *vsl) 267*1f5207b7SJohn Levon { 268*1f5207b7SJohn Levon struct var_sym *vs; 269*1f5207b7SJohn Levon struct symbol *type; 270*1f5207b7SJohn Levon static char buf[80]; 271*1f5207b7SJohn Levon const char *p; 272*1f5207b7SJohn Levon 273*1f5207b7SJohn Levon if (ptr_list_size((struct ptr_list *)vsl) != 1) 274*1f5207b7SJohn Levon return NULL; 275*1f5207b7SJohn Levon vs = first_ptr_list((struct ptr_list *)vsl); 276*1f5207b7SJohn Levon 277*1f5207b7SJohn Levon type = get_real_base_type(vs->sym); 278*1f5207b7SJohn Levon if (!type || type->type != SYM_PTR) 279*1f5207b7SJohn Levon goto top_level_name; 280*1f5207b7SJohn Levon type = get_real_base_type(type); 281*1f5207b7SJohn Levon if (!type || type->type != SYM_STRUCT) 282*1f5207b7SJohn Levon goto top_level_name; 283*1f5207b7SJohn Levon if (!type->ident) 284*1f5207b7SJohn Levon goto top_level_name; 285*1f5207b7SJohn Levon 286*1f5207b7SJohn Levon p = name; 287*1f5207b7SJohn Levon while ((name = strstr(p, "->"))) 288*1f5207b7SJohn Levon p = name + 2; 289*1f5207b7SJohn Levon 290*1f5207b7SJohn Levon snprintf(buf, sizeof(buf),"(struct %s)->%s", type->ident->name, p); 291*1f5207b7SJohn Levon return alloc_sname(buf); 292*1f5207b7SJohn Levon 293*1f5207b7SJohn Levon top_level_name: 294*1f5207b7SJohn Levon if (!(vs->sym->ctype.modifiers & MOD_TOPLEVEL)) 295*1f5207b7SJohn Levon return NULL; 296*1f5207b7SJohn Levon if (vs->sym->ctype.modifiers & MOD_STATIC) 297*1f5207b7SJohn Levon snprintf(buf, sizeof(buf),"static %s", name); 298*1f5207b7SJohn Levon else 299*1f5207b7SJohn Levon snprintf(buf, sizeof(buf),"global %s", name); 300*1f5207b7SJohn Levon return alloc_sname(buf); 301*1f5207b7SJohn Levon } 302*1f5207b7SJohn Levon 303*1f5207b7SJohn Levon int db_var_is_array_limit(struct expression *array, const char *name, struct var_sym_list *vsl) 304*1f5207b7SJohn Levon { 305*1f5207b7SJohn Levon char *size_name; 306*1f5207b7SJohn Levon char *array_name = get_data_info_name(array); 307*1f5207b7SJohn Levon struct db_info db_info = {.name = array_name,}; 308*1f5207b7SJohn Levon 309*1f5207b7SJohn Levon size_name = vsl_to_data_info_name(name, vsl); 310*1f5207b7SJohn Levon if (!size_name) 311*1f5207b7SJohn Levon return 0; 312*1f5207b7SJohn Levon 313*1f5207b7SJohn Levon run_sql(db_limitter_callback, &db_info, 314*1f5207b7SJohn Levon "select value from data_info where type = %d and data = '%s';", 315*1f5207b7SJohn Levon ARRAY_LEN, size_name); 316*1f5207b7SJohn Levon 317*1f5207b7SJohn Levon return db_info.ret; 318*1f5207b7SJohn Levon } 319*1f5207b7SJohn Levon 320*1f5207b7SJohn Levon static int known_access_ok_comparison(struct expression *expr) 321*1f5207b7SJohn Levon { 322*1f5207b7SJohn Levon struct expression *array; 323*1f5207b7SJohn Levon struct expression *size; 324*1f5207b7SJohn Levon struct expression *offset; 325*1f5207b7SJohn Levon int comparison; 326*1f5207b7SJohn Levon 327*1f5207b7SJohn Levon array = get_array_base(expr); 328*1f5207b7SJohn Levon size = get_size_variable(array); 329*1f5207b7SJohn Levon if (!size) 330*1f5207b7SJohn Levon return 0; 331*1f5207b7SJohn Levon offset = get_array_offset(expr); 332*1f5207b7SJohn Levon comparison = get_comparison(size, offset); 333*1f5207b7SJohn Levon if (comparison == '>' || comparison == SPECIAL_UNSIGNED_GT) 334*1f5207b7SJohn Levon return 1; 335*1f5207b7SJohn Levon 336*1f5207b7SJohn Levon return 0; 337*1f5207b7SJohn Levon } 338*1f5207b7SJohn Levon 339*1f5207b7SJohn Levon static int known_access_ok_numbers(struct expression *expr) 340*1f5207b7SJohn Levon { 341*1f5207b7SJohn Levon struct expression *array; 342*1f5207b7SJohn Levon struct expression *offset; 343*1f5207b7SJohn Levon sval_t max; 344*1f5207b7SJohn Levon int size; 345*1f5207b7SJohn Levon 346*1f5207b7SJohn Levon array = get_array_base(expr); 347*1f5207b7SJohn Levon offset = get_array_offset(expr); 348*1f5207b7SJohn Levon 349*1f5207b7SJohn Levon size = get_array_size(array); 350*1f5207b7SJohn Levon if (size <= 0) 351*1f5207b7SJohn Levon return 0; 352*1f5207b7SJohn Levon 353*1f5207b7SJohn Levon get_absolute_max(offset, &max); 354*1f5207b7SJohn Levon if (max.uvalue < size) 355*1f5207b7SJohn Levon return 1; 356*1f5207b7SJohn Levon return 0; 357*1f5207b7SJohn Levon } 358*1f5207b7SJohn Levon 359*1f5207b7SJohn Levon static void array_check_data_info(struct expression *expr) 360*1f5207b7SJohn Levon { 361*1f5207b7SJohn Levon struct expression *array; 362*1f5207b7SJohn Levon struct expression *offset; 363*1f5207b7SJohn Levon struct state_list *slist; 364*1f5207b7SJohn Levon struct sm_state *sm; 365*1f5207b7SJohn Levon struct compare_data *comp; 366*1f5207b7SJohn Levon char *offset_name; 367*1f5207b7SJohn Levon const char *equal_name = NULL; 368*1f5207b7SJohn Levon 369*1f5207b7SJohn Levon expr = strip_expr(expr); 370*1f5207b7SJohn Levon if (!is_array(expr)) 371*1f5207b7SJohn Levon return; 372*1f5207b7SJohn Levon 373*1f5207b7SJohn Levon if (known_access_ok_numbers(expr)) 374*1f5207b7SJohn Levon return; 375*1f5207b7SJohn Levon if (known_access_ok_comparison(expr)) 376*1f5207b7SJohn Levon return; 377*1f5207b7SJohn Levon 378*1f5207b7SJohn Levon array = get_array_base(expr); 379*1f5207b7SJohn Levon offset = get_array_offset(expr); 380*1f5207b7SJohn Levon offset_name = expr_to_var(offset); 381*1f5207b7SJohn Levon if (!offset_name) 382*1f5207b7SJohn Levon return; 383*1f5207b7SJohn Levon slist = get_all_possible_equal_comparisons(offset); 384*1f5207b7SJohn Levon if (!slist) 385*1f5207b7SJohn Levon goto free; 386*1f5207b7SJohn Levon 387*1f5207b7SJohn Levon FOR_EACH_PTR(slist, sm) { 388*1f5207b7SJohn Levon comp = sm->state->data; 389*1f5207b7SJohn Levon if (strcmp(comp->left_var, offset_name) == 0) { 390*1f5207b7SJohn Levon if (db_var_is_array_limit(array, comp->right_var, comp->right_vsl)) { 391*1f5207b7SJohn Levon equal_name = comp->right_var; 392*1f5207b7SJohn Levon break; 393*1f5207b7SJohn Levon } 394*1f5207b7SJohn Levon } else if (strcmp(comp->right_var, offset_name) == 0) { 395*1f5207b7SJohn Levon if (db_var_is_array_limit(array, comp->left_var, comp->left_vsl)) { 396*1f5207b7SJohn Levon equal_name = comp->left_var; 397*1f5207b7SJohn Levon break; 398*1f5207b7SJohn Levon } 399*1f5207b7SJohn Levon } 400*1f5207b7SJohn Levon } END_FOR_EACH_PTR(sm); 401*1f5207b7SJohn Levon 402*1f5207b7SJohn Levon if (equal_name) { 403*1f5207b7SJohn Levon char *array_name = expr_to_str(array); 404*1f5207b7SJohn Levon 405*1f5207b7SJohn Levon sm_warning("potential off by one '%s[]' limit '%s'", array_name, equal_name); 406*1f5207b7SJohn Levon free_string(array_name); 407*1f5207b7SJohn Levon } 408*1f5207b7SJohn Levon 409*1f5207b7SJohn Levon free: 410*1f5207b7SJohn Levon free_slist(&slist); 411*1f5207b7SJohn Levon free_string(offset_name); 412*1f5207b7SJohn Levon } 413*1f5207b7SJohn Levon 414*1f5207b7SJohn Levon static void add_allocation_function(const char *func, void *call_back, int param) 415*1f5207b7SJohn Levon { 416*1f5207b7SJohn Levon add_function_assign_hook(func, call_back, INT_PTR(param)); 417*1f5207b7SJohn Levon } 418*1f5207b7SJohn Levon 419*1f5207b7SJohn Levon static char *buf_size_param_comparison(struct expression *array, struct expression_list *args) 420*1f5207b7SJohn Levon { 421*1f5207b7SJohn Levon struct expression *arg; 422*1f5207b7SJohn Levon struct expression *size; 423*1f5207b7SJohn Levon static char buf[32]; 424*1f5207b7SJohn Levon int i; 425*1f5207b7SJohn Levon 426*1f5207b7SJohn Levon size = get_size_variable(array); 427*1f5207b7SJohn Levon if (!size) 428*1f5207b7SJohn Levon return NULL; 429*1f5207b7SJohn Levon 430*1f5207b7SJohn Levon i = -1; 431*1f5207b7SJohn Levon FOR_EACH_PTR(args, arg) { 432*1f5207b7SJohn Levon i++; 433*1f5207b7SJohn Levon if (arg == array) 434*1f5207b7SJohn Levon continue; 435*1f5207b7SJohn Levon if (!expr_equiv(arg, size)) 436*1f5207b7SJohn Levon continue; 437*1f5207b7SJohn Levon snprintf(buf, sizeof(buf), "==$%d", i); 438*1f5207b7SJohn Levon return buf; 439*1f5207b7SJohn Levon } END_FOR_EACH_PTR(arg); 440*1f5207b7SJohn Levon 441*1f5207b7SJohn Levon return NULL; 442*1f5207b7SJohn Levon } 443*1f5207b7SJohn Levon 444*1f5207b7SJohn Levon static void match_call(struct expression *call) 445*1f5207b7SJohn Levon { 446*1f5207b7SJohn Levon struct expression *arg; 447*1f5207b7SJohn Levon char *compare; 448*1f5207b7SJohn Levon int param; 449*1f5207b7SJohn Levon 450*1f5207b7SJohn Levon param = -1; 451*1f5207b7SJohn Levon FOR_EACH_PTR(call->args, arg) { 452*1f5207b7SJohn Levon param++; 453*1f5207b7SJohn Levon if (!is_pointer(arg)) 454*1f5207b7SJohn Levon continue; 455*1f5207b7SJohn Levon compare = buf_size_param_comparison(arg, call->args); 456*1f5207b7SJohn Levon if (!compare) 457*1f5207b7SJohn Levon continue; 458*1f5207b7SJohn Levon sql_insert_caller_info(call, ARRAY_LEN, param, "$", compare); 459*1f5207b7SJohn Levon } END_FOR_EACH_PTR(arg); 460*1f5207b7SJohn Levon } 461*1f5207b7SJohn Levon 462*1f5207b7SJohn Levon static int get_param(int param, char **name, struct symbol **sym) 463*1f5207b7SJohn Levon { 464*1f5207b7SJohn Levon struct symbol *arg; 465*1f5207b7SJohn Levon int i; 466*1f5207b7SJohn Levon 467*1f5207b7SJohn Levon i = 0; 468*1f5207b7SJohn Levon FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { 469*1f5207b7SJohn Levon /* 470*1f5207b7SJohn Levon * this is a temporary hack to work around a bug (I think in sparse?) 471*1f5207b7SJohn Levon * 2.6.37-rc1:fs/reiserfs/journal.o 472*1f5207b7SJohn Levon * If there is a function definition without parameter name found 473*1f5207b7SJohn Levon * after a function implementation then it causes a crash. 474*1f5207b7SJohn Levon * int foo() {} 475*1f5207b7SJohn Levon * int bar(char *); 476*1f5207b7SJohn Levon */ 477*1f5207b7SJohn Levon if (arg->ident->name < (char *)100) 478*1f5207b7SJohn Levon continue; 479*1f5207b7SJohn Levon if (i == param) { 480*1f5207b7SJohn Levon *name = arg->ident->name; 481*1f5207b7SJohn Levon *sym = arg; 482*1f5207b7SJohn Levon return TRUE; 483*1f5207b7SJohn Levon } 484*1f5207b7SJohn Levon i++; 485*1f5207b7SJohn Levon } END_FOR_EACH_PTR(arg); 486*1f5207b7SJohn Levon 487*1f5207b7SJohn Levon return FALSE; 488*1f5207b7SJohn Levon } 489*1f5207b7SJohn Levon 490*1f5207b7SJohn Levon static void set_param_compare(const char *array_name, struct symbol *array_sym, char *key, char *value) 491*1f5207b7SJohn Levon { 492*1f5207b7SJohn Levon struct expression *array_expr; 493*1f5207b7SJohn Levon struct expression *size_expr; 494*1f5207b7SJohn Levon struct symbol *size_sym; 495*1f5207b7SJohn Levon char *size_name; 496*1f5207b7SJohn Levon long param; 497*1f5207b7SJohn Levon struct sm_state *tmp; 498*1f5207b7SJohn Levon 499*1f5207b7SJohn Levon if (strncmp(value, "==$", 3) != 0) 500*1f5207b7SJohn Levon return; 501*1f5207b7SJohn Levon param = strtol(value + 3, NULL, 10); 502*1f5207b7SJohn Levon if (!get_param(param, &size_name, &size_sym)) 503*1f5207b7SJohn Levon return; 504*1f5207b7SJohn Levon array_expr = symbol_expression(array_sym); 505*1f5207b7SJohn Levon size_expr = symbol_expression(size_sym); 506*1f5207b7SJohn Levon 507*1f5207b7SJohn Levon tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr)); 508*1f5207b7SJohn Levon if (!tmp) 509*1f5207b7SJohn Levon return; 510*1f5207b7SJohn Levon set_state_expr(link_id, size_expr, alloc_expr_state(array_expr)); 511*1f5207b7SJohn Levon } 512*1f5207b7SJohn Levon 513*1f5207b7SJohn Levon static void set_arraysize_arg(const char *array_name, struct symbol *array_sym, char *key, char *value) 514*1f5207b7SJohn Levon { 515*1f5207b7SJohn Levon struct expression *array_expr; 516*1f5207b7SJohn Levon struct expression *size_expr; 517*1f5207b7SJohn Levon struct symbol *size_sym; 518*1f5207b7SJohn Levon char *size_name; 519*1f5207b7SJohn Levon long param; 520*1f5207b7SJohn Levon struct sm_state *tmp; 521*1f5207b7SJohn Levon 522*1f5207b7SJohn Levon param = strtol(key, NULL, 10); 523*1f5207b7SJohn Levon if (!get_param(param, &size_name, &size_sym)) 524*1f5207b7SJohn Levon return; 525*1f5207b7SJohn Levon array_expr = symbol_expression(array_sym); 526*1f5207b7SJohn Levon size_expr = symbol_expression(size_sym); 527*1f5207b7SJohn Levon 528*1f5207b7SJohn Levon tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr)); 529*1f5207b7SJohn Levon if (!tmp) 530*1f5207b7SJohn Levon return; 531*1f5207b7SJohn Levon set_state_expr(link_id, size_expr, alloc_expr_state(array_expr)); 532*1f5207b7SJohn Levon } 533*1f5207b7SJohn Levon 534*1f5207b7SJohn Levon static void munge_start_states(struct statement *stmt) 535*1f5207b7SJohn Levon { 536*1f5207b7SJohn Levon struct state_list *slist = NULL; 537*1f5207b7SJohn Levon struct sm_state *sm; 538*1f5207b7SJohn Levon struct sm_state *poss; 539*1f5207b7SJohn Levon 540*1f5207b7SJohn Levon FOR_EACH_MY_SM(size_id, __get_cur_stree(), sm) { 541*1f5207b7SJohn Levon if (sm->state != &merged) 542*1f5207b7SJohn Levon continue; 543*1f5207b7SJohn Levon /* 544*1f5207b7SJohn Levon * screw it. let's just assume that if one caller passes the 545*1f5207b7SJohn Levon * size then they all do. 546*1f5207b7SJohn Levon */ 547*1f5207b7SJohn Levon FOR_EACH_PTR(sm->possible, poss) { 548*1f5207b7SJohn Levon if (poss->state != &merged && 549*1f5207b7SJohn Levon poss->state != &undefined) { 550*1f5207b7SJohn Levon add_ptr_list(&slist, poss); 551*1f5207b7SJohn Levon break; 552*1f5207b7SJohn Levon } 553*1f5207b7SJohn Levon } END_FOR_EACH_PTR(poss); 554*1f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 555*1f5207b7SJohn Levon 556*1f5207b7SJohn Levon FOR_EACH_PTR(slist, sm) { 557*1f5207b7SJohn Levon set_state(size_id, sm->name, sm->sym, sm->state); 558*1f5207b7SJohn Levon } END_FOR_EACH_PTR(sm); 559*1f5207b7SJohn Levon 560*1f5207b7SJohn Levon free_slist(&slist); 561*1f5207b7SJohn Levon } 562*1f5207b7SJohn Levon 563*1f5207b7SJohn Levon void register_buf_comparison(int id) 564*1f5207b7SJohn Levon { 565*1f5207b7SJohn Levon size_id = id; 566*1f5207b7SJohn Levon 567*1f5207b7SJohn Levon add_unmatched_state_hook(size_id, &unmatched_state); 568*1f5207b7SJohn Levon 569*1f5207b7SJohn Levon add_allocation_function("malloc", &match_alloc, 0); 570*1f5207b7SJohn Levon add_allocation_function("memdup", &match_alloc, 1); 571*1f5207b7SJohn Levon add_allocation_function("realloc", &match_alloc, 1); 572*1f5207b7SJohn Levon if (option_project == PROJ_KERNEL) { 573*1f5207b7SJohn Levon add_allocation_function("kmalloc", &match_alloc, 0); 574*1f5207b7SJohn Levon add_allocation_function("kzalloc", &match_alloc, 0); 575*1f5207b7SJohn Levon add_allocation_function("vmalloc", &match_alloc, 0); 576*1f5207b7SJohn Levon add_allocation_function("__vmalloc", &match_alloc, 0); 577*1f5207b7SJohn Levon add_allocation_function("sock_kmalloc", &match_alloc, 1); 578*1f5207b7SJohn Levon add_allocation_function("kmemdup", &match_alloc, 1); 579*1f5207b7SJohn Levon add_allocation_function("kmemdup_user", &match_alloc, 1); 580*1f5207b7SJohn Levon add_allocation_function("dma_alloc_attrs", &match_alloc, 1); 581*1f5207b7SJohn Levon add_allocation_function("pci_alloc_consistent", &match_alloc, 1); 582*1f5207b7SJohn Levon add_allocation_function("pci_alloc_coherent", &match_alloc, 1); 583*1f5207b7SJohn Levon add_allocation_function("devm_kmalloc", &match_alloc, 1); 584*1f5207b7SJohn Levon add_allocation_function("devm_kzalloc", &match_alloc, 1); 585*1f5207b7SJohn Levon add_allocation_function("kcalloc", &match_calloc, 0); 586*1f5207b7SJohn Levon add_allocation_function("devm_kcalloc", &match_calloc, 1); 587*1f5207b7SJohn Levon add_allocation_function("kmalloc_array", &match_calloc, 0); 588*1f5207b7SJohn Levon add_allocation_function("krealloc", &match_alloc, 1); 589*1f5207b7SJohn Levon } 590*1f5207b7SJohn Levon 591*1f5207b7SJohn Levon add_hook(&array_check, OP_HOOK); 592*1f5207b7SJohn Levon add_hook(&array_check_data_info, OP_HOOK); 593*1f5207b7SJohn Levon 594*1f5207b7SJohn Levon add_hook(&match_call, FUNCTION_CALL_HOOK); 595*1f5207b7SJohn Levon select_caller_info_hook(set_param_compare, ARRAY_LEN); 596*1f5207b7SJohn Levon select_caller_info_hook(set_arraysize_arg, ARRAYSIZE_ARG); 597*1f5207b7SJohn Levon add_hook(&munge_start_states, AFTER_DEF_HOOK); 598*1f5207b7SJohn Levon } 599*1f5207b7SJohn Levon 600*1f5207b7SJohn Levon void register_buf_comparison_links(int id) 601*1f5207b7SJohn Levon { 602*1f5207b7SJohn Levon link_id = id; 603*1f5207b7SJohn Levon add_merge_hook(link_id, &merge_links); 604*1f5207b7SJohn Levon add_modification_hook(link_id, &match_link_modify); 605*1f5207b7SJohn Levon } 606