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 7:41 PM, Linus Torvalds
<torvalds@xxxxxxxxxxxxxxxxxxxx> wrote:
>
> Hmm. It exposes other problems.
>
> For example, the fact that we look up the identifier now exposes the
> fact that "first_subobject()" creates this dummy "EXPR_IDENTIFIER"
> expression that has no identifier. That will then cause
> "find_identifier()" to fail, which in turn causes convert_ident() to
> fail. Resulting in the parse tree having remaining EXPR_IDENTIFIER
> nodes, which will later result in "unknown expression (25,0)" errors.
>
> That's easy enough to fix with just adding the proper initializer, ie
>
>     new->expr_ident = field->ident;
>
> to first_subobject().

Actually, sadly, while that worked for my test-cases (and for Josh's
case), it turns out to really *not* work in general: the dummy
EXPR_IDENTIFIER that we create may end up referring to a unnamed
union, which doesn't *have* an ident associated with it.

This only really triggers when you mix named initializers with then
relying on the whole "initialize the next one without a name", but
that does happen. And it fundamentally breaks that whole "use
find_identifier()" approach.

So convert_ident() really cannot use find_indent(), and really does
have to use "sym->offset". But that doesn't work for anonymous union
members, because that offset was the offset within the anonymous
union, not the parent structure.

However, the fix is "simple". We can just say that anonymous
union/structure member offsets have to be the offsets within the
parent union instead, and fix things up. So how about a patch like
this *instead* of the previous patch..

                 Linus
 evaluate.c |  2 +-
 symbol.c   | 16 ++++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/evaluate.c b/evaluate.c
index 03992d03ae1d..78150f83a19f 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1898,7 +1898,7 @@ static struct symbol *find_identifier(struct ident *ident, struct symbol_list *_
 				sub = find_identifier(ident, ctype->symbol_list, offset);
 				if (!sub)
 					continue;
-				*offset += sym->offset;
+				*offset = sym->offset;
 				return sub;
 			}	
 		}
diff --git a/symbol.c b/symbol.c
index a2731348a011..32af64050a64 100644
--- a/symbol.c
+++ b/symbol.c
@@ -116,6 +116,18 @@ static int bitfield_base_size(struct symbol *sym)
 	return sym->bit_size;
 }
 
+static void update_symbol_offsets(struct symbol *sym, unsigned int offset)
+{
+	struct symbol *field;
+
+	if (sym->type != SYM_STRUCT && sym->type != SYM_UNION)
+		return;
+	FOR_EACH_PTR(sym->symbol_list, field) {
+		field->offset += offset;
+		update_symbol_offsets(field, offset);
+	} END_FOR_EACH_PTR(field);
+}
+
 /*
  * Structures are a bit more interesting to lay out
  */
@@ -174,6 +186,10 @@ static void lay_out_struct(struct symbol *sym, struct struct_union_info *info)
 	bit_size = (bit_size + align_bit_mask) & ~align_bit_mask;
 	sym->offset = bits_to_bytes(bit_size);
 
+	/* If it's an unnamed struct or union, update the offsets of the sub-members */
+	if (sym->offset && !sym->ident)
+		update_symbol_offsets(sym, sym->offset);
+
 	info->bit_size = bit_size + base_size;
 	// warning (sym->pos, "regular: offset=%d", sym->offset);
 }

[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