diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-08-08 18:45:26 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-08-08 18:45:26 +0200 |
commit | 1bffdc1843a5a95bdc23f266dc17839cbf9d4916 (patch) | |
tree | 451026c7c6d71ec6885d94172ca59b070d215e29 | |
parent | 13252024246cc03fc8cc0d812c61421f96faa3c7 (diff) | |
parent | 172d4be4d5955c6a963663da46f9a88c49c00cc2 (diff) | |
download | sparse-1bffdc1843a5a95bdc23f266dc17839cbf9d4916.tar.gz |
Merge branch 'wstring-init' into next
* teach sparse about wide string initializers
-rw-r--r-- | evaluate.c | 25 | ||||
-rw-r--r-- | symbol.c | 25 | ||||
-rw-r--r-- | symbol.h | 7 | ||||
-rw-r--r-- | validation/init-wstring.c | 40 | ||||
-rw-r--r-- | validation/init_cstring.c | 2 |
5 files changed, 89 insertions, 10 deletions
@@ -102,9 +102,10 @@ static struct symbol *evaluate_string(struct expression *expr) struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); struct expression *initstr = alloc_expression(expr->pos, EXPR_STRING); unsigned int length = expr->string->length; + struct symbol *char_type = expr->wide ? wchar_ctype : &char_ctype; sym->array_size = alloc_const_expression(expr->pos, length); - sym->bit_size = bytes_to_bits(length); + sym->bit_size = length * char_type->bit_size; sym->ctype.alignment = 1; sym->string = 1; sym->ctype.modifiers = MOD_STATIC; @@ -117,10 +118,10 @@ static struct symbol *evaluate_string(struct expression *expr) initstr->string = expr->string; array->array_size = sym->array_size; - array->bit_size = bytes_to_bits(length); - array->ctype.alignment = 1; + array->bit_size = sym->bit_size; + array->ctype.alignment = char_type->ctype.alignment; array->ctype.modifiers = MOD_STATIC; - array->ctype.base_type = &char_ctype; + array->ctype.base_type = char_type; array->examined = 1; array->evaluated = 1; @@ -405,7 +406,10 @@ static inline int is_string_type(struct symbol *type) { if (type->type == SYM_NODE) type = type->ctype.base_type; - return type->type == SYM_ARRAY && is_byte_type(type->ctype.base_type); + if (type->type != SYM_ARRAY) + return 0; + type = type->ctype.base_type; + return is_byte_type(type) || is_wchar_type(type); } static struct symbol *bad_expr_type(struct expression *expr) @@ -2768,7 +2772,6 @@ static struct expression *handle_scalar(struct expression *e, int nested) static int handle_initializer(struct expression **ep, int nested, int class, struct symbol *ctype, unsigned long mods) { - int is_string = is_string_type(ctype); struct expression *e = *ep, *p; struct symbol *type; @@ -2802,7 +2805,7 @@ static int handle_initializer(struct expression **ep, int nested, * pathologies, so we don't need anything fancy here. */ if (e->type == EXPR_INITIALIZER) { - if (is_string) { + if (is_string_type(ctype)) { struct expression *v = NULL; int count = 0; @@ -2823,7 +2826,7 @@ static int handle_initializer(struct expression **ep, int nested, /* string */ if (is_string_literal(&e)) { /* either we are doing array of char, or we'll have to dig in */ - if (is_string) { + if (is_string_type(ctype)) { *ep = e; goto String; } @@ -2848,10 +2851,12 @@ String: *p = *e; type = evaluate_expression(p); if (ctype->bit_size != -1) { - if (ctype->bit_size + bits_in_char < type->bit_size) + struct symbol *char_type = e->wide ? wchar_ctype : &char_ctype; + unsigned int size_with_null = ctype->bit_size + char_type->bit_size; + if (size_with_null < type->bit_size) warning(e->pos, "too long initializer-string for array of char"); - else if (Winit_cstring && ctype->bit_size + bits_in_char == type->bit_size) { + else if (Winit_cstring && size_with_null == type->bit_size) { warning(e->pos, "too long initializer-string for array of char(no space for nul char)"); } @@ -307,6 +307,29 @@ void merge_type(struct symbol *sym, struct symbol *base_type) merge_type(sym, sym->ctype.base_type); } +static bool is_wstring_expr(struct expression *expr) +{ + while (expr) { + switch (expr->type) { + case EXPR_STRING: + return 1; + case EXPR_INITIALIZER: + if (expression_list_size(expr->expr_list) != 1) + return 0; + expr = first_expression(expr->expr_list); + break; + case EXPR_PREOP: + if (expr->op == '(') { + expr = expr->unop; + break; + } + default: + return 0; + } + } + return 0; +} + static int count_array_initializer(struct symbol *t, struct expression *expr) { int nr = 0; @@ -321,6 +344,8 @@ static int count_array_initializer(struct symbol *t, struct expression *expr) */ if (t->ctype.base_type == &int_type && t->rank == -2) is_char = 1; + else if (t == wchar_ctype && is_wstring_expr(expr)) + is_char = 1; switch (expr->type) { case EXPR_INITIALIZER: { @@ -430,6 +430,13 @@ static inline int is_byte_type(struct symbol *type) return type->bit_size == bits_in_char && type->type != SYM_BITFIELD; } +static inline int is_wchar_type(struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return type == wchar_ctype; +} + static inline int is_void_type(struct symbol *type) { if (type->type == SYM_NODE) diff --git a/validation/init-wstring.c b/validation/init-wstring.c new file mode 100644 index 00000000..d9ce3b3c --- /dev/null +++ b/validation/init-wstring.c @@ -0,0 +1,40 @@ +static const __WCHAR_TYPE__ ok0[] = L"abc"; +_Static_assert(sizeof(ok0) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok1[] = (L"abc"); +_Static_assert(sizeof(ok1) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok2[] = { L"abc" }; +_Static_assert(sizeof(ok2) == 4 * sizeof(__WCHAR_TYPE__)); + +static const __WCHAR_TYPE__ ok3[4] = L"abc"; +_Static_assert(sizeof(ok3) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok4[4] = (L"abc"); +_Static_assert(sizeof(ok4) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok5[4] = { (L"abc") }; +_Static_assert(sizeof(ok5) == 4 * sizeof(__WCHAR_TYPE__)); + +static const __WCHAR_TYPE__ ok6[7] = L"abc"; +_Static_assert(sizeof(ok6) == 7 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok7[7] = (L"abc"); +_Static_assert(sizeof(ok7) == 7 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok8[7] = { (L"abc") }; +_Static_assert(sizeof(ok8) == 7 * sizeof(__WCHAR_TYPE__)); + +static const __WCHAR_TYPE__ *ptr[] = { L"abc" }; +_Static_assert(sizeof(ptr) == sizeof(void *)); + +static struct s { + const __WCHAR_TYPE__ str[4]; +} str = { L"xyz" }; + +static const __WCHAR_TYPE__ ko3[3] = L"abc"; +static const __WCHAR_TYPE__ ko2[2] = L"abc"; + +/* + * check-name: init-wstring + * check-command: sparse -Winit-cstring $file + * + * check-error-start +init-wstring.c:29:38: warning: too long initializer-string for array of char(no space for nul char) +init-wstring.c:30:38: warning: too long initializer-string for array of char + * check-error-end + */ diff --git a/validation/init_cstring.c b/validation/init_cstring.c index 00eca20a..bac814e4 100644 --- a/validation/init_cstring.c +++ b/validation/init_cstring.c @@ -1,11 +1,13 @@ static struct alpha { char a[2]; } x = { .a = "ab" }; +static const char str[2] = "abc"; /* * check-name: -Winit-cstring option * * check-command: sparse -Winit-cstring $file * check-error-start init_cstring.c:3:14: warning: too long initializer-string for array of char(no space for nul char) +init_cstring.c:4:28: warning: too long initializer-string for array of char * check-error-end */ |