1 /*
   2  * Copyright (C) 2014 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 file started out by saying that if you have:
  20  *
  21  *      struct foo one, two;
  22  *      ...
  23  *      one = two;
  24  *
  25  * That's equivalent to saying:
  26  *
  27  *      one.x = two.x;
  28  *      one.y = two.y;
  29  *
  30  * Turning an assignment like that into a bunch of small fake assignments is
  31  * really useful.
  32  *
  33  * The call to memcpy(&one, &two, sizeof(foo)); is the same as "one = two;" so
  34  * we can re-use the code.  And we may as well use it for memset() too.
  35  * Assigning pointers is almost the same:
  36  *
  37  *      p1 = p2;
  38  *
  39  * Is the same as:
  40  *
  41  *      p1->x = p2->x;
  42  *      p1->y = p2->y;
  43  *
  44  * The problem is that you can go a bit crazy with pointers to pointers.
  45  *
  46  *      p1->x->y->z->one->two->three = p2->x->y->z->one->two->three;
  47  *
  48  * I don't have a proper solution for this problem right now.  I just copy one
  49  * level and don't nest.  It should handle limitted nesting but intelligently.
  50  *
  51  * The other thing is that you end up with a lot of garbage assignments where
  52  * we record "x could be anything. x->y could be anything. x->y->z->a->b->c
  53  * could *also* be anything!".  There should be a better way to filter this
  54  * useless information.
  55  *
  56  */
  57 
  58 #include "scope.h"
  59 #include "smatch.h"
  60 #include "smatch_slist.h"
  61 #include "smatch_extra.h"
  62 
  63 enum {
  64         COPY_NORMAL,
  65         COPY_MEMCPY,
  66         COPY_MEMSET,
  67 };
  68 
  69 static struct symbol *get_struct_type(struct expression *expr)
  70 {
  71         struct symbol *type;
  72 
  73         type = get_type(expr);
  74         if (!type)
  75                 return NULL;
  76         if (type->type == SYM_PTR) {
  77                 type = get_real_base_type(type);
  78                 if (!type)
  79                         return NULL;
  80         }
  81         if (type->type == SYM_STRUCT)
  82                 return type;
  83         if (type->type == SYM_UNION)
  84                 return type;
  85         return NULL;
  86 }
  87 
  88 static struct expression *get_right_base_expr(struct symbol *left_type, struct expression *right)
  89 {
  90         struct symbol *struct_type;
  91 
  92         if (!right)
  93                 return NULL;
  94 
  95         struct_type = get_struct_type(right);
  96         if (!struct_type)
  97                 return NULL;
  98         if (struct_type != left_type)
  99                 return NULL;
 100 
 101         if (right->type == EXPR_PREOP && right->op == '&')
 102                 right = strip_expr(right->unop);
 103 
 104         if (right->type == EXPR_CALL)
 105                 return NULL;
 106 
 107         if (is_pointer(right))
 108                 right = deref_expression(right);
 109 
 110         return right;
 111 }
 112 
 113 static struct expression *remove_addr(struct expression *expr)
 114 {
 115         struct symbol *type;
 116 
 117         expr = strip_expr(expr);
 118         if (!expr)
 119                 return NULL;
 120 
 121         if (expr->type == EXPR_PREOP && expr->op == '&')
 122                 return strip_expr(expr->unop);
 123         type = get_type(expr);
 124         if (!type)
 125                 return expr;
 126         if (type->type != SYM_PTR && type->type != SYM_ARRAY)
 127                 return expr;
 128 
 129         return deref_expression(expr);
 130 }
 131 
 132 static struct expression *faked_expression;
 133 struct expression *get_faked_expression(void)
 134 {
 135         if (!__in_fake_assign)
 136                 return NULL;
 137         return faked_expression;
 138 }
 139 
 140 static void split_fake_expr(struct expression *expr)
 141 {
 142         __in_fake_assign++;
 143         __in_fake_struct_assign++;
 144         __split_expr(expr);
 145         __in_fake_struct_assign--;
 146         __in_fake_assign--;
 147 }
 148 
 149 static void handle_non_struct_assignments(struct expression *left, struct expression *right)
 150 {
 151         struct symbol *type;
 152         struct expression *assign;
 153 
 154         while (right && right->type == EXPR_ASSIGNMENT)
 155                 right = strip_parens(right->left);
 156 
 157         type = get_type(left);
 158         if (!type)
 159                 return;
 160         if (type->type == SYM_PTR) {
 161                 left = deref_expression(left);
 162                 if (right)
 163                         right = deref_expression(right);
 164                 else
 165                         right = unknown_value_expression(left);
 166                 assign = assign_expression(left, '=', right);
 167                 split_fake_expr(assign);
 168                 return;
 169         }
 170         if (type->type != SYM_BASETYPE)
 171                 return;
 172         right = strip_expr(right);
 173         type = get_type(right);
 174         if (!right || !type || type->type == SYM_ARRAY)
 175                 right = unknown_value_expression(left);
 176         assign = assign_expression(left, '=', right);
 177         split_fake_expr(assign);
 178 }
 179 
 180 static void set_inner_struct_members(int mode, struct expression *faked, struct expression *left, struct expression *right, struct symbol *member)
 181 {
 182         struct expression *left_member;
 183         struct expression *right_member = NULL;  /* silence GCC */
 184         struct expression *assign;
 185         struct symbol *base = get_real_base_type(member);
 186         struct symbol *tmp;
 187 
 188         if (member->ident) {
 189                 left = member_expression(left, '.', member->ident);
 190                 if (mode != COPY_MEMSET && right)
 191                         right = member_expression(right, '.', member->ident);
 192         }
 193 
 194         FOR_EACH_PTR(base->symbol_list, tmp) {
 195                 struct symbol *type;
 196 
 197                 type = get_real_base_type(tmp);
 198                 if (!type)
 199                         continue;
 200 
 201                 if (type->type == SYM_ARRAY)
 202                         continue;
 203                 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
 204                         set_inner_struct_members(mode, faked, left, right, tmp);
 205                         continue;
 206                 }
 207                 if (!tmp->ident)
 208                         continue;
 209 
 210                 left_member = member_expression(left, '.', tmp->ident);
 211 
 212                 switch (mode) {
 213                 case COPY_NORMAL:
 214                 case COPY_MEMCPY:
 215                         if (right)
 216                                 right_member = member_expression(right, '.', tmp->ident);
 217                         else
 218                                 right_member = unknown_value_expression(left_member);
 219                         break;
 220                 case COPY_MEMSET:
 221                         right_member = right;
 222                         break;
 223                 }
 224 
 225                 assign = assign_expression(left_member, '=', right_member);
 226                 split_fake_expr(assign);
 227         } END_FOR_EACH_PTR(tmp);
 228 }
 229 
 230 static void __struct_members_copy(int mode, struct expression *faked,
 231                                   struct expression *left,
 232                                   struct expression *right)
 233 {
 234         struct symbol *struct_type, *tmp, *type;
 235         struct expression *left_member;
 236         struct expression *right_member;
 237         struct expression *assign;
 238         int op = '.';
 239 
 240         if (__in_fake_assign)
 241                 return;
 242         faked_expression = faked;
 243 
 244         left = strip_expr(left);
 245         right = strip_expr(right);
 246 
 247         if (left->type == EXPR_PREOP && left->op == '*' && is_pointer(left))
 248                 left = preop_expression(left, '(');
 249 
 250         struct_type = get_struct_type(left);
 251         if (!struct_type) {
 252                 /*
 253                  * This is not a struct assignment obviously.  But this is where
 254                  * memcpy() is handled so it feels like a good place to add this
 255                  * code.
 256                  */
 257                 handle_non_struct_assignments(left, right);
 258                 goto done;
 259         }
 260 
 261         if (is_pointer(left)) {
 262                 left = deref_expression(left);
 263                 op = '*';
 264         }
 265         if (mode != COPY_MEMSET)
 266                 right = get_right_base_expr(struct_type, right);
 267 
 268         FOR_EACH_PTR(struct_type->symbol_list, tmp) {
 269                 type = get_real_base_type(tmp);
 270                 if (!type)
 271                         continue;
 272                 if (type->type == SYM_ARRAY)
 273                         continue;
 274 
 275                 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
 276                         set_inner_struct_members(mode, faked, left, right, tmp);
 277                         continue;
 278                 }
 279 
 280                 if (!tmp->ident)
 281                         continue;
 282 
 283                 left_member = member_expression(left, op, tmp->ident);
 284                 right_member = NULL;
 285 
 286                 switch (mode) {
 287                 case COPY_NORMAL:
 288                 case COPY_MEMCPY:
 289                         if (right)
 290                                 right_member = member_expression(right, op, tmp->ident);
 291                         else
 292                                 right_member = unknown_value_expression(left_member);
 293                         break;
 294                 case COPY_MEMSET:
 295                         right_member = right;
 296                         break;
 297                 }
 298                 if (!right_member) {
 299                         sm_perror("No right member");
 300                         continue;
 301                 }
 302                 assign = assign_expression(left_member, '=', right_member);
 303                 split_fake_expr(assign);
 304         } END_FOR_EACH_PTR(tmp);
 305 
 306 done:
 307         faked_expression = NULL;
 308 }
 309 
 310 static int returns_zeroed_mem(struct expression *expr)
 311 {
 312         char *fn;
 313 
 314         if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
 315                 return 0;
 316         fn = expr_to_var(expr->fn);
 317         if (!fn)
 318                 return 0;
 319         if (strcmp(fn, "kcalloc") == 0)
 320                 return 1;
 321         if (option_project == PROJ_KERNEL && strstr(fn, "zalloc"))
 322                 return 1;
 323         return 0;
 324 }
 325 
 326 static int copy_containter_states(struct expression *left, struct expression *right, int offset)
 327 {
 328         char *left_name = NULL, *right_name = NULL;
 329         struct symbol *left_sym, *right_sym;
 330         struct sm_state *sm, *new_sm;
 331         int ret = 0;
 332         int len;
 333         char buf[64];
 334         char new_name[128];
 335 
 336         right_name = expr_to_var_sym(right, &right_sym);
 337         if (!right_name || !right_sym)
 338                 goto free;
 339         left_name = expr_to_var_sym(left, &left_sym);
 340         if (!left_name || !left_sym)
 341                 goto free;
 342 
 343         len = snprintf(buf, sizeof(buf), "%s(-%d)", right_name, offset);
 344         if (len >= sizeof(buf))
 345                 goto free;
 346 
 347         FOR_EACH_SM(__get_cur_stree(), sm) {
 348                 if (sm->sym != right_sym)
 349                         continue;
 350                 if (strncmp(sm->name, buf, len) != 0)
 351                         continue;
 352                 snprintf(new_name, sizeof(new_name), "%s%s", left_name, sm->name + len);
 353                 new_sm = clone_sm(sm);
 354                 new_sm->name = alloc_sname(new_name);
 355                 new_sm->sym = left_sym;
 356                 __set_sm(new_sm);
 357                 ret = 1;
 358         } END_FOR_EACH_SM(sm);
 359 free:
 360         free_string(left_name);
 361         free_string(right_name);
 362         return ret;
 363 }
 364 
 365 static int handle_param_offsets(struct expression *expr)
 366 {
 367         struct expression *right;
 368         sval_t sval;
 369 
 370         right = strip_expr(expr->right);
 371 
 372         if (right->type != EXPR_BINOP || right->op != '-')
 373                 return 0;
 374 
 375         if (!get_value(right->right, &sval))
 376                 return 0;
 377 
 378         right = get_assigned_expr(right->left);
 379         if (!right)
 380                 return 0;
 381         return copy_containter_states(expr->left, right, sval.value);
 382 }
 383 
 384 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
 385 {
 386         struct expression *call, *arg;
 387         int offset;
 388 
 389         if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
 390                 return;
 391         call = strip_expr(expr->right);
 392         if (call->type != EXPR_CALL)
 393                 return;
 394         if (param != -1)
 395                 return;
 396         param = atoi(key);
 397         offset = atoi(value);
 398 
 399         arg = get_argument_from_call_expr(call->args, param);
 400         if (!arg)
 401                 return;
 402 
 403         copy_containter_states(expr->left, arg, -offset);
 404 }
 405 
 406 void __fake_struct_member_assignments(struct expression *expr)
 407 {
 408         struct symbol *left_type;
 409 
 410         if (expr->op != '=')
 411                 return;
 412 
 413         if (expr_is_zero(expr->right))
 414                 return;
 415 
 416         left_type = get_type(expr->left);
 417         if (!left_type ||
 418             (left_type->type != SYM_PTR &&
 419              left_type->type != SYM_STRUCT))
 420                 return;
 421 
 422         if (handle_param_offsets(expr))
 423                 return;
 424 
 425         if (returns_zeroed_mem(expr->right))
 426                 __struct_members_copy(COPY_MEMSET, expr, expr->left, zero_expr());
 427         else
 428                 __struct_members_copy(COPY_NORMAL, expr, expr->left, expr->right);
 429 }
 430 
 431 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
 432 {
 433         struct expression *buf;
 434         struct expression *val;
 435 
 436         buf = get_argument_from_call_expr(expr->args, 0);
 437         val = get_argument_from_call_expr(expr->args, 1);
 438 
 439         buf = strip_expr(buf);
 440         __struct_members_copy(COPY_MEMSET, expr, remove_addr(buf), val);
 441 }
 442 
 443 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
 444 {
 445         struct expression *dest;
 446         struct expression *src;
 447 
 448         dest = get_argument_from_call_expr(expr->args, 0);
 449         src = get_argument_from_call_expr(expr->args, 1);
 450 
 451         __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), remove_addr(src));
 452 }
 453 
 454 static void match_memdup(const char *fn, struct expression *call_expr,
 455                         struct expression *expr, void *_unused)
 456 {
 457         struct expression *left, *right, *arg;
 458 
 459         if (!expr || expr->type != EXPR_ASSIGNMENT)
 460                 return;
 461 
 462         left = strip_expr(expr->left);
 463         right = strip_expr(expr->right);
 464 
 465         if (right->type != EXPR_CALL)
 466                 return;
 467         arg = get_argument_from_call_expr(right->args, 0);
 468         __struct_members_copy(COPY_MEMCPY, expr, left, arg);
 469 }
 470 
 471 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
 472 {
 473         struct expression *dest;
 474 
 475         dest = get_argument_from_call_expr(expr->args, 0);
 476         __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), NULL);
 477 }
 478 
 479 static void match_sscanf(const char *fn, struct expression *expr, void *unused)
 480 {
 481         struct expression *arg;
 482         int i;
 483 
 484         i = -1;
 485         FOR_EACH_PTR(expr->args, arg) {
 486                 if (++i < 2)
 487                         continue;
 488                 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
 489         } END_FOR_EACH_PTR(arg);
 490 }
 491 
 492 static void unop_expr(struct expression *expr)
 493 {
 494         if (expr->op != SPECIAL_INCREMENT &&
 495             expr->op != SPECIAL_DECREMENT)
 496                 return;
 497 
 498         if (!is_pointer(expr))
 499                 return;
 500         faked_expression = expr;
 501         __struct_members_copy(COPY_MEMCPY, expr, expr->unop, NULL);
 502         faked_expression = NULL;
 503 }
 504 
 505 static void register_clears_param(void)
 506 {
 507         struct token *token;
 508         char name[256];
 509         const char *function;
 510         int param;
 511 
 512         if (option_project == PROJ_NONE)
 513                 return;
 514 
 515         snprintf(name, 256, "%s.clears_argument", option_project_str);
 516 
 517         token = get_tokens_file(name);
 518         if (!token)
 519                 return;
 520         if (token_type(token) != TOKEN_STREAMBEGIN)
 521                 return;
 522         token = token->next;
 523         while (token_type(token) != TOKEN_STREAMEND) {
 524                 if (token_type(token) != TOKEN_IDENT)
 525                         return;
 526                 function = show_ident(token->ident);
 527                 token = token->next;
 528                 if (token_type(token) != TOKEN_NUMBER)
 529                         return;
 530                 param = atoi(token->number);
 531                 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
 532                 token = token->next;
 533         }
 534         clear_token_alloc();
 535 }
 536 
 537 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
 538 {
 539         struct expression *arg;
 540 
 541         while (expr->type == EXPR_ASSIGNMENT)
 542                 expr = strip_expr(expr->right);
 543         if (expr->type != EXPR_CALL)
 544                 return;
 545 
 546         /*
 547          * FIXME:  __struct_members_copy() requires an expression but
 548          * get_variable_from_key() returns a name/sym pair so that doesn't
 549          * work here.
 550          */
 551         if (strcmp(key, "$") != 0)
 552                 return;
 553 
 554         arg = get_argument_from_call_expr(expr->args, param);
 555         if (!arg)
 556                 return;
 557 
 558         if (strcmp(value, "0") == 0)
 559                 __struct_members_copy(COPY_MEMSET, expr, remove_addr(arg), zero_expr());
 560         else
 561                 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
 562 }
 563 
 564 void register_struct_assignment(int id)
 565 {
 566         add_function_hook("memset", &match_memset, NULL);
 567         add_function_hook("__memset", &match_memset, NULL);
 568 
 569         add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
 570         add_function_hook("memmove", &match_memcpy, INT_PTR(0));
 571         add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
 572         add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
 573 
 574         if (option_project == PROJ_KERNEL)
 575                 return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
 576 
 577         add_function_hook("sscanf", &match_sscanf, NULL);
 578 
 579         add_hook(&unop_expr, OP_HOOK);
 580         register_clears_param();
 581         select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
 582 
 583         select_return_states_hook(CONTAINER, &returns_container_of);
 584 }