aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-08-08 18:45:26 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-08-08 18:45:26 +0200
commit1bffdc1843a5a95bdc23f266dc17839cbf9d4916 (patch)
tree451026c7c6d71ec6885d94172ca59b070d215e29
parent13252024246cc03fc8cc0d812c61421f96faa3c7 (diff)
parent172d4be4d5955c6a963663da46f9a88c49c00cc2 (diff)
downloadsparse-1bffdc1843a5a95bdc23f266dc17839cbf9d4916.tar.gz
Merge branch 'wstring-init' into next
* teach sparse about wide string initializers
-rw-r--r--evaluate.c25
-rw-r--r--symbol.c25
-rw-r--r--symbol.h7
-rw-r--r--validation/init-wstring.c40
-rw-r--r--validation/init_cstring.c2
5 files changed, 89 insertions, 10 deletions
diff --git a/evaluate.c b/evaluate.c
index 9990b57b..691435f3 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;
@@ -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)");
}
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: {
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)
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
*/