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 }