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         type = get_type(left);
 155         if (!type)
 156                 return;
 157         if (type->type == SYM_PTR) {
 158                 left = deref_expression(left);
 159                 if (right)
 160                         right = deref_expression(right);
 161                 else
 162                         right = unknown_value_expression(left);
 163                 assign = assign_expression(left, '=', right);
 164                 split_fake_expr(assign);
 165                 return;
 166         }
 167         if (type->type != SYM_BASETYPE)
 168                 return;
 169         right = strip_expr(right);
 170         type = get_type(right);
 171         if (!right || !type || type->type == SYM_ARRAY)
 172                 right = unknown_value_expression(left);
 173         assign = assign_expression(left, '=', right);
 174         split_fake_expr(assign);
 175 }
 176 
 177 static void set_inner_struct_members(int mode, struct expression *faked, struct expression *left, struct expression *right, struct symbol *member)
 178 {
 179         struct expression *left_member;
 180         struct expression *right_member = NULL;  /* silence GCC */
 181         struct expression *assign;
 182         struct symbol *base = get_real_base_type(member);
 183         struct symbol *tmp;
 184 
 185         if (member->ident) {
 186                 left = member_expression(left, '.', member->ident);
 187                 if (mode != COPY_MEMSET && right)
 188                         right = member_expression(right, '.', member->ident);
 189         }
 190 
 191         FOR_EACH_PTR(base->symbol_list, tmp) {
 192                 struct symbol *type;
 193 
 194                 type = get_real_base_type(tmp);
 195                 if (!type)
 196                         continue;
 197 
 198                 if (type->type == SYM_ARRAY)
 199                         continue;
 200                 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
 201                         set_inner_struct_members(mode, faked, left, right, tmp);
 202                         continue;
 203                 }
 204                 if (!tmp->ident)
 205                         continue;
 206 
 207                 left_member = member_expression(left, '.', tmp->ident);
 208 
 209                 switch (mode) {
 210                 case COPY_NORMAL:
 211                 case COPY_MEMCPY:
 212                         if (right)
 213                                 right_member = member_expression(right, '.', tmp->ident);
 214                         else
 215                                 right_member = unknown_value_expression(left_member);
 216                         break;
 217                 case COPY_MEMSET:
 218                         right_member = right;
 219                         break;
 220                 }
 221 
 222                 assign = assign_expression(left_member, '=', right_member);
 223                 split_fake_expr(assign);
 224         } END_FOR_EACH_PTR(tmp);
 225 }
 226 
 227 static void __struct_members_copy(int mode, struct expression *faked,
 228                                   struct expression *left,
 229                                   struct expression *right)
 230 {
 231         struct symbol *struct_type, *tmp, *type;
 232         struct expression *left_member;
 233         struct expression *right_member;
 234         struct expression *assign;
 235         int op = '.';
 236 
 237 
 238         if (__in_fake_assign)
 239                 return;
 240         faked_expression = faked;
 241 
 242         left = strip_expr(left);
 243         right = strip_expr(right);
 244 
 245         struct_type = get_struct_type(left);
 246         if (!struct_type) {
 247                 /*
 248                  * This is not a struct assignment obviously.  But this is where
 249                  * memcpy() is handled so it feels like a good place to add this
 250                  * code.
 251                  */
 252                 handle_non_struct_assignments(left, right);
 253                 goto done;
 254         }
 255 
 256         if (is_pointer(left)) {
 257                 left = deref_expression(left);
 258                 op = '*';
 259         }
 260         if (mode != COPY_MEMSET)
 261                 right = get_right_base_expr(struct_type, right);
 262 
 263         FOR_EACH_PTR(struct_type->symbol_list, tmp) {
 264                 type = get_real_base_type(tmp);
 265                 if (!type)
 266                         continue;
 267                 if (type->type == SYM_ARRAY)
 268                         continue;
 269 
 270                 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
 271                         set_inner_struct_members(mode, faked, left, right, tmp);
 272                         continue;
 273                 }
 274 
 275                 if (!tmp->ident)
 276                         continue;
 277 
 278                 left_member = member_expression(left, op, tmp->ident);
 279                 right_member = NULL;
 280 
 281                 switch (mode) {
 282                 case COPY_NORMAL:
 283                 case COPY_MEMCPY:
 284                         if (right)
 285                                 right_member = member_expression(right, op, tmp->ident);
 286                         else
 287                                 right_member = unknown_value_expression(left_member);
 288                         break;
 289                 case COPY_MEMSET:
 290                         right_member = right;
 291                         break;
 292                 }
 293                 if (!right_member) {
 294                         sm_perror("No right member");
 295                         continue;
 296                 }
 297                 assign = assign_expression(left_member, '=', right_member);
 298                 split_fake_expr(assign);
 299         } END_FOR_EACH_PTR(tmp);
 300 
 301 done:
 302         faked_expression = NULL;
 303 }
 304 
 305 static int returns_zeroed_mem(struct expression *expr)
 306 {
 307         char *fn;
 308 
 309         if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
 310                 return 0;
 311         fn = expr_to_var(expr->fn);
 312         if (!fn)
 313                 return 0;
 314         if (strcmp(fn, "kcalloc") == 0)
 315                 return 1;
 316         if (option_project == PROJ_KERNEL && strstr(fn, "zalloc"))
 317                 return 1;
 318         return 0;
 319 }
 320 
 321 static int copy_containter_states(struct expression *left, struct expression *right, int offset)
 322 {
 323         char *left_name = NULL, *right_name = NULL;
 324         struct symbol *left_sym, *right_sym;
 325         struct sm_state *sm, *new_sm;
 326         int ret = 0;
 327         int len;
 328         char buf[64];
 329         char new_name[128];
 330 
 331         right_name = expr_to_var_sym(right, &right_sym);
 332         if (!right_name || !right_sym)
 333                 goto free;
 334         left_name = expr_to_var_sym(left, &left_sym);
 335         if (!left_name || !left_sym)
 336                 goto free;
 337 
 338         len = snprintf(buf, sizeof(buf), "%s(-%d)", right_name, offset);
 339         if (len >= sizeof(buf))
 340                 goto free;
 341 
 342         FOR_EACH_SM(__get_cur_stree(), sm) {
 343                 if (sm->sym != right_sym)
 344                         continue;
 345                 if (strncmp(sm->name, buf, len) != 0)
 346                         continue;
 347                 snprintf(new_name, sizeof(new_name), "%s%s", left_name, sm->name + len);
 348                 new_sm = clone_sm(sm);
 349                 new_sm->name = alloc_sname(new_name);
 350                 new_sm->sym = left_sym;
 351                 __set_sm(new_sm);
 352                 ret = 1;
 353         } END_FOR_EACH_SM(sm);
 354 free:
 355         free_string(left_name);
 356         free_string(right_name);
 357         return ret;
 358 }
 359 
 360 static int handle_param_offsets(struct expression *expr)
 361 {
 362         struct expression *right;
 363         sval_t sval;
 364 
 365         right = strip_expr(expr->right);
 366 
 367         if (right->type != EXPR_BINOP || right->op != '-')
 368                 return 0;
 369 
 370         if (!get_value(right->right, &sval))
 371                 return 0;
 372 
 373         right = get_assigned_expr(right->left);
 374         if (!right)
 375                 return 0;
 376         return copy_containter_states(expr->left, right, sval.value);
 377 }
 378 
 379 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
 380 {
 381         struct expression *call, *arg;
 382         int offset;
 383 
 384         if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
 385                 return;
 386         call = strip_expr(expr->right);
 387         if (call->type != EXPR_CALL)
 388                 return;
 389         if (param != -1)
 390                 return;
 391         param = atoi(key);
 392         offset = atoi(value);
 393 
 394         arg = get_argument_from_call_expr(call->args, param);
 395         if (!arg)
 396                 return;
 397 
 398         copy_containter_states(expr->left, arg, -offset);
 399 }
 400 
 401 void __fake_struct_member_assignments(struct expression *expr)
 402 {
 403         struct symbol *left_type;
 404 
 405         if (expr->op != '=')
 406                 return;
 407 
 408         if (expr_is_zero(expr->right))
 409                 return;
 410 
 411         left_type = get_type(expr->left);
 412         if (!left_type ||
 413             (left_type->type != SYM_PTR &&
 414              left_type->type != SYM_STRUCT))
 415                 return;
 416 
 417         if (handle_param_offsets(expr))
 418                 return;
 419 
 420         if (returns_zeroed_mem(expr->right))
 421                 __struct_members_copy(COPY_MEMSET, expr, expr->left, zero_expr());
 422         else
 423                 __struct_members_copy(COPY_NORMAL, expr, expr->left, expr->right);
 424 }
 425 
 426 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
 427 {
 428         struct expression *buf;
 429         struct expression *val;
 430 
 431         buf = get_argument_from_call_expr(expr->args, 0);
 432         val = get_argument_from_call_expr(expr->args, 1);
 433 
 434         buf = strip_expr(buf);
 435         __struct_members_copy(COPY_MEMSET, expr, remove_addr(buf), val);
 436 }
 437 
 438 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
 439 {
 440         struct expression *dest;
 441         struct expression *src;
 442 
 443         dest = get_argument_from_call_expr(expr->args, 0);
 444         src = get_argument_from_call_expr(expr->args, 1);
 445 
 446         __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), remove_addr(src));
 447 }
 448 
 449 static void match_memdup(const char *fn, struct expression *call_expr,
 450                         struct expression *expr, void *_unused)
 451 {
 452         struct expression *left, *right, *arg;
 453 
 454         if (!expr || expr->type != EXPR_ASSIGNMENT)
 455                 return;
 456 
 457         left = strip_expr(expr->left);
 458         right = strip_expr(expr->right);
 459 
 460         if (right->type != EXPR_CALL)
 461                 return;
 462         arg = get_argument_from_call_expr(right->args, 0);
 463         __struct_members_copy(COPY_MEMCPY, expr, left, arg);
 464 }
 465 
 466 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
 467 {
 468         struct expression *dest;
 469 
 470         dest = get_argument_from_call_expr(expr->args, 0);
 471         __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), NULL);
 472 }
 473 
 474 static void match_sscanf(const char *fn, struct expression *expr, void *unused)
 475 {
 476         struct expression *arg;
 477         int i;
 478 
 479         i = -1;
 480         FOR_EACH_PTR(expr->args, arg) {
 481                 if (++i < 2)
 482                         continue;
 483                 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
 484         } END_FOR_EACH_PTR(arg);
 485 }
 486 
 487 static void unop_expr(struct expression *expr)
 488 {
 489         if (expr->op != SPECIAL_INCREMENT &&
 490             expr->op != SPECIAL_DECREMENT)
 491                 return;
 492 
 493         if (!is_pointer(expr))
 494                 return;
 495         faked_expression = expr;
 496         __struct_members_copy(COPY_MEMCPY, expr, expr->unop, NULL);
 497         faked_expression = NULL;
 498 }
 499 
 500 static void register_clears_param(void)
 501 {
 502         struct token *token;
 503         char name[256];
 504         const char *function;
 505         int param;
 506 
 507         if (option_project == PROJ_NONE)
 508                 return;
 509 
 510         snprintf(name, 256, "%s.clears_argument", option_project_str);
 511 
 512         token = get_tokens_file(name);
 513         if (!token)
 514                 return;
 515         if (token_type(token) != TOKEN_STREAMBEGIN)
 516                 return;
 517         token = token->next;
 518         while (token_type(token) != TOKEN_STREAMEND) {
 519                 if (token_type(token) != TOKEN_IDENT)
 520                         return;
 521                 function = show_ident(token->ident);
 522                 token = token->next;
 523                 if (token_type(token) != TOKEN_NUMBER)
 524                         return;
 525                 param = atoi(token->number);
 526                 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
 527                 token = token->next;
 528         }
 529         clear_token_alloc();
 530 }
 531 
 532 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
 533 {
 534         struct expression *arg;
 535 
 536         while (expr->type == EXPR_ASSIGNMENT)
 537                 expr = strip_expr(expr->right);
 538         if (expr->type != EXPR_CALL)
 539                 return;
 540 
 541         /*
 542          * FIXME:  __struct_members_copy() requires an expression but
 543          * get_variable_from_key() returns a name/sym pair so that doesn't
 544          * work here.
 545          */
 546         if (strcmp(key, "$") != 0)
 547                 return;
 548 
 549         arg = get_argument_from_call_expr(expr->args, param);
 550         if (!arg)
 551                 return;
 552 
 553         if (strcmp(value, "0") == 0)
 554                 __struct_members_copy(COPY_MEMSET, expr, remove_addr(arg), zero_expr());
 555         else
 556                 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
 557 }
 558 
 559 void register_struct_assignment(int id)
 560 {
 561         add_function_hook("memset", &match_memset, NULL);
 562         add_function_hook("__memset", &match_memset, NULL);
 563 
 564         add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
 565         add_function_hook("memmove", &match_memcpy, INT_PTR(0));
 566         add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
 567         add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
 568 
 569         if (option_project == PROJ_KERNEL)
 570                 return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
 571 
 572         add_function_hook("sscanf", &match_sscanf, NULL);
 573 
 574         add_hook(&unop_expr, OP_HOOK);
 575         register_clears_param();
 576         select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
 577 
 578         select_return_states_hook(CONTAINER, &returns_container_of);
 579 }