LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 11742 - c++11: constant emitter needs to zero-initialize padding for trivially-copyable types
Summary: c++11: constant emitter needs to zero-initialize padding for trivially-copyab...
Status: NEW
Alias: None
Product: clang
Classification: Unclassified
Component: C++11 (show other bugs)
Version: unspecified
Hardware: PC Linux
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-01-10 22:59 PST by Richard Smith
Modified: 2012-12-09 02:49 PST (History)
4 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Smith 2012-01-10 22:59:38 PST
Padding for objects with static storage duration is currently emitted as undef. This is non-conforming in C++11, because:

1) zero initialization is performed prior to constant initialization (unlike C)
2) zero initialization initializes padding to 0 bits (unlike C++98)
3) for trivially-copyable types, it is permissible to inspect the effective array of unsigned char (of size sizeof(T)) comprising the object

Hence a conforming program can tell whether the padding has been zero-initialized.
Comment 1 Duncan Sands 2012-01-11 05:17:46 PST
A testcase or three would be nice.
Comment 2 Richard Smith 2012-11-15 00:56:56 PST
Simple example:

struct S { char c = 1; __attribute__((aligned(8))) char d = 2; } s = S();
char k = ((char*)&s)[1] + 1;

... gives ...

@s = global %struct.S { i8 1, [7 x i8] undef, i8 2, [7 x i8] undef }, align 8

... which is wrong. The padding should be zeroed. Running this through opt -instcombine -globalopt gives:

@k = global i8 undef, align 1

... which is wrong. k should be 1.

(Running this through just opt -globalopt strangely gives

@k = global i8 1, align 1

which Nick tells me is a bug in globalopt.)
Comment 3 Duncan Sands 2012-11-15 02:47:30 PST
If the C++11 standard really says that *padding* must be initialized to zero
(your point 2) then indeed using undef is simply wrong.
Comment 4 Richard Smith 2012-12-03 13:08:01 PST
(In reply to comment #3)
> If the C++11 standard really says that *padding* must be initialized to zero
> (your point 2) then indeed using undef is simply wrong.

It really does. C++11 [dcl.init]p6:

"To zero-initialize an object or reference of type T means:
  — if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
  — if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
  — if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;
  — if T is an array type, each element is zero-initialized;
  — if T is a reference type, no initialization is performed."
Comment 5 Duncan Sands 2012-12-08 08:41:30 PST
I partially fixed this in dragonegg in commit 169678.  There remains the case
of something like this
  A : char;
  B : int;
which has implicit padding between A and B due to B's natural alignment.  Must
this kind of padding also be zero initialized?  Note that this is different to
your test case in a sense, though not so much in spirit.
Comment 6 Richard Smith 2012-12-09 00:07:43 PST
I'm not sure what your notation means, but if you mean something like 'struct S { char A; int B; };', then yes, if an object of type S is zero-initialized, the padding between fields must be initialized to zero bits.

In Clang at least, such a struct is emitted as 'global %struct.S { i8 1, i32 2 }'. It's not clear to me whether the padding is zero or undef in this case.
Comment 7 Duncan Sands 2012-12-09 02:49:41 PST
I'm pretty sure the padding is "undef" in this case.