Re: Designated initializers for fields in anonymous structs and unions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jul 31, 2014 at 11:10 AM,  <josh@xxxxxxxxxxxxxxxx> wrote:
> Test case:
>
> struct S {
>     int a;
>     union {
>         int b;
>         int c;
>     };
> };
>
> static struct S s = {
>     .a = 0,
>     .b = 0,
> };

So sparse fails on this test-case (differently from what Josh
reported, because apparently Josh is running 0.5.0) with:

  t.c:10:6: warning: Initializer entry defined twice
  t.c:11:6:   also defined here

because the offsets are miscomputed. The conversion from
EXPR_IDENTIFIER (an initializer entry with a named identifier) to
EXPR_POS (an initializer entry with a byte offset) got this wrong.

We need to use "find_identifier()" that does the proper recursive
lookup and updates the offset, but the required structure type wasn't
passed down to convert_designators() and convert_ident(), so the patch
is a bit bigger than just changing a couple of lines.

I'm quite sure we still screw complex intiializers up . But this makes
at least Josh's test-case pass, and looks superficially sane.

Hmm?

                  Linus
From 7670d933e82917ea28a7e5a5df09bcc9744dba34 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Date: Thu, 31 Jul 2014 19:01:36 -0700
Subject: [PATCH] Make 'convert_ident()' use 'find_identifier()' to get the
 proper member offset

The convert_ident() function used to do

	struct symbol *sym = e->field;
	e->init_offset = sym->offset;

which is wrong for embedded unnamed unions.  It really wants to do
"find_identifier()", which looks up the field name in the structure or
union type, and properly adds the offsets when it looks things up in an
anonymous structure or union.

However, we didn't pass in the right symbol type, so convert_ident()
couldn't be just trivially converted with a couple of lines.

This changes the code to pass in the struct/union type, and also
re-organizes find_identifier() to have a nicer calling convention.  We
now pass in the type, not the name-list, which makes it possible for
find_identifier() to do the peeling of the SYM_NODE if required,
simplifying the callers (including the recursive call for the anonymous
case).

Reported-by: Just Triplett <josh@xxxxxxxxxxxxxxxx>
Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
---
 evaluate.c | 47 ++++++++++++++++++++++++++---------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/evaluate.c b/evaluate.c
index 03992d03ae1d..5195decd1b2e 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1872,13 +1872,19 @@ static struct symbol *evaluate_preop(struct expression *expr)
 	return ctype;
 }
 
-static struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset)
+static struct symbol *find_identifier(struct ident *ident, struct symbol *ctype, int *offset)
 {
-	struct ptr_list *head = (struct ptr_list *)_list;
-	struct ptr_list *list = head;
+	struct ptr_list *head, *list;
 
+	if (ctype->type == SYM_NODE)
+		ctype = ctype->ctype.base_type;
+	if (ctype->type != SYM_UNION && ctype->type != SYM_STRUCT)
+		return NULL;
+
+	head = (struct ptr_list *)ctype->symbol_list;
 	if (!head)
 		return NULL;
+	list = head;
 	do {
 		int i;
 		for (i = 0; i < list->nr; i++) {
@@ -1889,13 +1895,8 @@ static struct symbol *find_identifier(struct ident *ident, struct symbol_list *_
 				*offset = sym->offset;
 				return sym;
 			} else {
-				struct symbol *ctype = sym->ctype.base_type;
 				struct symbol *sub;
-				if (!ctype)
-					continue;
-				if (ctype->type != SYM_UNION && ctype->type != SYM_STRUCT)
-					continue;
-				sub = find_identifier(ident, ctype->symbol_list, offset);
+				sub = find_identifier(ident, sym, offset);
 				if (!sub)
 					continue;
 				*offset += sym->offset;
@@ -1965,7 +1966,7 @@ static struct symbol *evaluate_member_dereference(struct expression *expr)
 		return NULL;
 	}
 	offset = 0;
-	member = find_identifier(ident, ctype->symbol_list, &offset);
+	member = find_identifier(ident, ctype, &offset);
 	if (!member) {
 		const char *type = ctype->type == SYM_STRUCT ? "struct" : "union";
 		const char *name = "<unnamed>";
@@ -2220,23 +2221,27 @@ static void convert_index(struct expression *e)
 	e->init_expr = child;
 }
 
-static void convert_ident(struct expression *e)
+static void convert_ident(struct expression *e, struct symbol *ctype)
 {
+	int offset;
 	struct expression *child = e->ident_expression;
-	struct symbol *sym = e->field;
+
+	ctype = find_identifier(e->expr_ident, ctype, &offset);
+	if (!ctype)
+		return;
 	e->type = EXPR_POS;
-	e->init_offset = sym->offset;
+	e->init_offset = offset;
 	e->init_nr = 1;
 	e->init_expr = child;
 }
 
-static void convert_designators(struct expression *e)
+static void convert_designators(struct expression *e, struct symbol *ctype)
 {
 	while (e) {
 		if (e->type == EXPR_INDEX)
 			convert_index(e);
 		else if (e->type == EXPR_IDENTIFIER)
-			convert_ident(e);
+			convert_ident(e, ctype);
 		else
 			break;
 		e = e->init_expr;
@@ -2322,7 +2327,7 @@ static struct expression *check_designators(struct expression *e,
 				err = "field name not in struct or union";
 				break;
 			}
-			ctype = find_identifier(e->expr_ident, ctype->symbol_list, &offset);
+			ctype = find_identifier(e->expr_ident, ctype, &offset);
 			if (!ctype) {
 				err = "unknown field name in";
 				break;
@@ -2392,7 +2397,7 @@ static struct expression *next_designators(struct expression *old,
 		if (!copy) {
 			field = old->field->next_subobject;
 			if (!field) {
-				convert_ident(old);
+				convert_ident(old, ctype);
 				return NULL;
 			}
 			copy = e;
@@ -2406,7 +2411,7 @@ static struct expression *next_designators(struct expression *old,
 		new->expr_ident = field->ident;
 		new->ident_expression = copy;
 		new->ctype = field;
-		convert_ident(old);
+		convert_ident(old, ctype);
 	}
 	return new;
 }
@@ -2465,7 +2470,7 @@ static void handle_list_initializer(struct expression *expr,
 			top = next;
 			/* deeper than one designator? */
 			jumped = top != e;
-			convert_designators(last);
+			convert_designators(last, ctype);
 			last = e;
 		}
 
@@ -2497,7 +2502,7 @@ found:
 
 	} END_FOR_EACH_PTR(e);
 
-	convert_designators(last);
+	convert_designators(last, ctype);
 	expr->ctype = ctype;
 }
 
@@ -2901,7 +2906,7 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
 			return NULL;
 		}
 
-		field = find_identifier(expr->ident, ctype->symbol_list, &offset);
+		field = find_identifier(expr->ident, ctype, &offset);
 		if (!field) {
 			expression_error(expr, "unknown member");
 			return NULL;
-- 
2.1.0.rc0.52.gaa544bf


[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux