From 3fa5d6d66889a313fc6d74a8d7ba3280548ac8fa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 27 Oct 2012 14:55:48 +0300 Subject: [PATCH] sval: create a new basic storage for storing the value of things Before everything was a long long, but that can't store the value of ULLONG_MAX. This patch the sval_t type which holds a ctype as well as the ->value. It also adds some helper functions in smatch_sval.c. Eventually all the places which currently use "long long" will be updated to use an sval. Signed-off-by: Dan Carpenter --- Makefile | 2 +- smatch.h | 22 ++++++ smatch_ranges.c | 34 ++++++++- smatch_sval.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 smatch_sval.c diff --git a/Makefile b/Makefile index c6599548..cb1109a4 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ SMATCHDATADIR=$(PREFIX)/share/smatch/ SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \ smatch_helper.o smatch_type.o smatch_hooks.o smatch_function_hooks.o \ smatch_modification_hooks.o smatch_extra.o smatch_estate.o smatch_math.o \ - smatch_ranges.o smatch_implied.o smatch_ignore.o smatch_project.o \ + smatch_sval.o smatch_ranges.o smatch_implied.o smatch_ignore.o smatch_project.o \ smatch_tracker.o smatch_files.o smatch_expression_stacks.o \ smatch_constraints.o smatch_buf_size.o smatch_capped.o smatch_db.o \ smatch_expressions.o smatch_returns.o smatch_parse_call_math.o \ diff --git a/smatch.h b/smatch.h index b4909a8e..8c6f3dfe 100644 --- a/smatch.h +++ b/smatch.h @@ -18,6 +18,14 @@ #include "parse.h" #include "expression.h" +typedef struct { + struct symbol *type; + union { + long long value; + unsigned long long uvalue; + }; +} sval_t; + struct smatch_state { const char *name; void *data; @@ -488,4 +496,18 @@ void print_held_locks(); /* check_assigned_expr.c */ struct expression *get_assigned_expr(struct expression *expr); +/* smatch_sval.c */ +sval_t sval_blank(struct expression *expr); +sval_t sval_from_val(struct expression *expr, long long val); +int sval_unsigned(sval_t sval); +int sval_signed(sval_t sval); +int sval_bits(sval_t sval); +int sval_cmp(sval_t one, sval_t two); +int sval_cmp_val(sval_t one, long long val); +sval_t sval_cast(sval_t sval, struct expression *expr); +sval_t sval_preop(sval_t sval, int op); +sval_t sval_binop(sval_t left, int op, sval_t right); +const char *sval_to_str(sval_t sval); +long long sval_to_ll(sval_t sval); + #endif /* !SMATCH_H_ */ diff --git a/smatch_ranges.c b/smatch_ranges.c index a91b54d0..0582a9ec 100644 --- a/smatch_ranges.c +++ b/smatch_ranges.c @@ -74,12 +74,40 @@ void get_value_ranges(char *value, struct range_list **rl) if (*c == '(') c++; start = c; - if (!strncmp(start, "min", 3)) { - val1 = LLONG_MIN; + + if (!strncmp(start, "max", 3)) { + val1 = LLONG_MAX; c += 3; - } else if (!strncmp(start, "max", 3)) { + } else if (!strncmp(start, "u64max", 6)) { + val1 = LLONG_MAX; // FIXME + c += 6; + } else if (!strncmp(start, "s64max", 6)) { val1 = LLONG_MAX; + c += 6; + } else if (!strncmp(start, "u32max", 6)) { + val1 = UINT_MAX; + c += 6; + } else if (!strncmp(start, "s32max", 6)) { + val1 = INT_MAX; + c += 6; + } else if (!strncmp(start, "u16max", 6)) { + val1 = USHRT_MAX; + c += 6; + } else if (!strncmp(start, "s16max", 6)) { + val1 = SHRT_MAX; + c += 6; + } else if (!strncmp(start, "min", 3)) { + val1 = LLONG_MIN; c += 3; + } else if (!strncmp(start, "s64min", 6)) { + val1 = LLONG_MIN; + c += 6; + } else if (!strncmp(start, "s32min", 6)) { + val1 = INT_MIN; + c += 6; + } else if (!strncmp(start, "s16min", 6)) { + val1 = SHRT_MIN; + c += 6; } else { while (*c && *c != ',' && *c != '-') c++; diff --git a/smatch_sval.c b/smatch_sval.c new file mode 100644 index 00000000..9469166b --- /dev/null +++ b/smatch_sval.c @@ -0,0 +1,230 @@ +/* + * smatch/smatch_sval.c + * + * Copyright (C) 2012 Oracle. + * + * Licensed under the Open Software License version 1.1 + * + * + * Basically the point of sval is that it can hold both ULLONG_MAX and + * LLONG_MIN. If it is an unsigned type then we use sval.uvalue or if it is + * signed we use sval.value. + * + * I considered just using one bit to store whether the value was signed vs + * unsigned but I think it might help to have the type information so we know + * how to do type promotion. + * + */ + +#include "smatch.h" +#include "smatch_slist.h" +#include "smatch_extra.h" + +sval_t sval_blank(struct expression *expr) +{ + sval_t ret; + + ret.type = get_type(expr); + if (!ret.type) + ret.type = &llong_ctype; + ret.value = 123456789; + + return ret; +} + +sval_t sval_from_val(struct expression *expr, long long val) +{ + sval_t ret; + + ret = sval_blank(expr); + ret.value = val; + ret = sval_cast(ret, expr); + + return ret; +} + +int sval_unsigned(sval_t sval) +{ + return type_unsigned(sval.type); +} + +int sval_signed(sval_t sval) +{ + return !type_unsigned(sval.type); +} + +int sval_bits(sval_t sval) +{ + if (!sval.type) + return 32; + return sval.type->bit_size; +} + +/* + * Casts the values and then does a compare. Returns -1 if one is smaller, 0 if + * they are the same and 1 if two is larger. + */ +int sval_cmp(sval_t one, sval_t two) +{ + if (one.value < two.value) + return -1; + if (one.value == two.value) + return 0; + return 1; +} + +int sval_cmp_val(sval_t one, long long val) +{ + if (one.value < val) + return -1; + if (one.value == val) + return 0; + return 1; +} + +sval_t sval_cast(sval_t sval, struct expression *expr) +{ + sval_t ret; + + ret = sval_blank(expr); + switch (sval_bits(ret)) { + case 8: + if (sval_unsigned(ret)) + ret.value = (long long)(unsigned char)sval.value; + else + ret.value = (long long)(char)sval.value; + break; + case 16: + if (sval_unsigned(ret)) + ret.value = (long long)(unsigned short)sval.value; + else + ret.value = (long long)(short)sval.value; + break; + case 32: + if (sval_unsigned(ret)) + ret.value = (long long)(unsigned int)sval.value; + else + ret.value = (long long)(int)sval.value; + break; + default: + ret.value = sval.value; + } + return ret; + +} + +sval_t sval_preop(sval_t sval, int op) +{ + switch (op) { + case '!': + sval.value = !sval.value; + break; + case '~': + sval.value = ~sval.value; + /* fixme: should probably cast this here */ + break; + case '-': + sval.value = -sval.value; + break; + } + return sval; +} + +sval_t sval_binop(sval_t left, int op, sval_t right) +{ + sval_t ret; + + /* fixme: these need to have proper type promotions */ + ret.type = left.type; + switch (op) { + case '*': + ret.value = left.value * right.value; + break; + case '/': + if (right.value == 0) { + sm_msg("internal error: %s: divide by zero", __func__); + ret.value = 123456789; + } else { + ret.value = left.value / right.value; + } + break; + case '+': + ret.value = left.value + right.value; + break; + case '-': + ret.value = left.value - right.value; + break; + case '%': + if (right.value == 0) { + sm_msg("internal error: %s: MOD by zero", __func__); + ret.value = 123456789; + } else { + ret.value = left.value % right.value; + } + break; + case '|': + ret.value = left.value | right.value; + break; + case '&': + ret.value = left.value & right.value; + break; + case SPECIAL_RIGHTSHIFT: + ret.value = left.value >> right.value; + break; + case SPECIAL_LEFTSHIFT: + ret.value = left.value << right.value; + break; + case '^': + ret.value = left.value ^ right.value; + break; + default: + sm_msg("internal error: %s: unhandled binop %s", __func__, + show_special(op)); + ret.value = 1234567; + } + return ret; +} + +const char *sval_to_str(sval_t sval) +{ + static char buf[30]; + + if (sval_unsigned(sval) && sval.value == ULLONG_MAX) + return "u64max"; + if (sval.value == LLONG_MAX) + return "s64max"; + if (sval_unsigned(sval) && sval.value == UINT_MAX) + return "u32max"; + if (sval.value == INT_MAX) + return "s32max"; + if (sval_unsigned(sval) && sval.value == USHRT_MAX) + return "u16max"; + + if ((sval.type == &sshort_ctype || sval.type == &short_ctype) && sval.value == SHRT_MIN) + return "s16min"; + if ((sval.type == &sint_ctype || sval.type == &int_ctype) && sval.value == INT_MIN) + return "s32min"; + if (sval_signed(sval) && sval.value == LLONG_MIN) + return "s64min"; + + if (sval_unsigned(sval)) + snprintf(buf, sizeof(buf), "%llu", sval.value); + else if (sval.value < 0) + snprintf(buf, sizeof(buf), "(%lld)", sval.value); + else + snprintf(buf, sizeof(buf), "%lld", sval.value); + + return buf; +} + +/* + * This function is for compatibility. Eventually everything will use svals + * and we can get rid of whole_range.max. + */ +long long sval_to_ll(sval_t sval) +{ + if (sval_unsigned(sval) && sval.value == ULLONG_MAX) + return whole_range.max; + return sval.value; +} + -- 2.11.4.GIT