From aa198d93e6a28bd8c040d82a00a9256d97d61516 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 8 Aug 2020 06:18:42 +0200 Subject: wstring: add support for evaluation of wide string Evaluation doesn't know about wide strings. Fix this by: 1) selecting the right base type (char_ctype vs wchar_ctype) 2) adapting the type, size & alignment of the underlying array to this base type. Signed-off-by: Luc Van Oostenryck --- evaluate.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/evaluate.c b/evaluate.c index dddea761..acad11ab 100644 --- a/evaluate.c +++ b/evaluate.c @@ -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; -- cgit 1.2.3-korg From a060d243f8dc17e399641b0dfebeb4faf5eb7580 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 8 Aug 2020 06:22:56 +0200 Subject: wstring: add support for checking size in string initializer A warning is given for string initializers if the LHS array is not large enough to contains the string. But this check doesn't knowns about wide strings. Fix this by selecting the correct char type and use this type for the size calculations. Signed-off-by: Luc Van Oostenryck --- evaluate.c | 6 ++++-- validation/init-wstring.c | 41 +++++++++++++++++++++++++++++++++++++++++ validation/init_cstring.c | 2 ++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 validation/init-wstring.c diff --git a/evaluate.c b/evaluate.c index acad11ab..bbfa77c3 100644 --- a/evaluate.c +++ b/evaluate.c @@ -2841,10 +2841,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)"); } diff --git a/validation/init-wstring.c b/validation/init-wstring.c new file mode 100644 index 00000000..846b6e2c --- /dev/null +++ b/validation/init-wstring.c @@ -0,0 +1,41 @@ +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-known-to-fail + * + * 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 */ -- cgit 1.2.3-korg From 7d3b07840e745152eca4723790c4a988b623107a Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 8 Aug 2020 06:24:23 +0200 Subject: wstring: add support for examination of string initialization The examination of a string initializer doesn't know about wide strings. The only thing needed is if the base type is some kind of char but for wide chars, this type is the same as 'int' and an array of ints can't be treated the same as an array of chars. So, do the detection for wide string initializers as: 1) check that the LHS base type is wchar_ctype 2) check that the RHS is a kind of string expression (possibly between braces or parenthesis, recursively). Signed-off-by: Luc Van Oostenryck --- symbol.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/symbol.c b/symbol.c index 6fcb1b15..7f0c8558 100644 --- a/symbol.c +++ b/symbol.c @@ -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: { -- cgit 1.2.3-korg From ce8785f0a92426cc2039a00e9fc8699b5e7d3ce1 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 8 Aug 2020 06:26:28 +0200 Subject: wstring: add helper is_wchar_type() Like is_byte_type() but for wide chars. Signed-off-by: Luc Van Oostenryck --- symbol.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/symbol.h b/symbol.h index 8e7a2860..0e15f7bf 100644 --- a/symbol.h +++ b/symbol.h @@ -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) -- cgit 1.2.3-korg From 446313222a0b47504d162a1e67527fb517275096 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 8 Aug 2020 06:25:40 +0200 Subject: wstring: extend is_string_type() to also detect wide strings When evaluating initializers, it must be known if it is for a string or not. But sparse doesn't known about wide strings. Fix this by modifying is_string_type() to use is_wchar_type() in addition of is_byte_type(). Signed-off-by: Luc Van Oostenryck --- evaluate.c | 5 ++++- validation/init-wstring.c | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/evaluate.c b/evaluate.c index bbfa77c3..8d09c560 100644 --- a/evaluate.c +++ b/evaluate.c @@ -406,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) diff --git a/validation/init-wstring.c b/validation/init-wstring.c index 846b6e2c..d9ce3b3c 100644 --- a/validation/init-wstring.c +++ b/validation/init-wstring.c @@ -32,7 +32,6 @@ static const __WCHAR_TYPE__ ko2[2] = L"abc"; /* * check-name: init-wstring * check-command: sparse -Winit-cstring $file - * check-known-to-fail * * check-error-start init-wstring.c:29:38: warning: too long initializer-string for array of char(no space for nul char) -- cgit 1.2.3-korg From 172d4be4d5955c6a963663da46f9a88c49c00cc2 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 8 Aug 2020 06:26:21 +0200 Subject: wstring: call is_string_type() only when needed Just a tiny code reorganization to call is_string_type() only where & when needed. Signed-off-by: Luc Van Oostenryck --- evaluate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/evaluate.c b/evaluate.c index 8d09c560..d2cf1c0a 100644 --- a/evaluate.c +++ b/evaluate.c @@ -2764,7 +2764,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; @@ -2798,7 +2797,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; @@ -2819,7 +2818,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; } -- cgit 1.2.3-korg