Bugzilla – Bug 80
C front-end crash on empty structure
Last modified: 2003-11-04 13:52:39
You need to log in before you can comment on or make changes to this bug.
108 gally> llvm-gcc -c cracktacular.c cracktacular.c: In function `foo': cracktacular.c:3: internal compiler error: Segmentation fault Please submit a full bug report, with preprocessed source if appropriate. See <URL:http://llvm.cs.uiuc.edu> for instructions. 109 gally> cat cracktacular.c typedef struct { } the_coolest_struct_in_the_world; extern the_coolest_struct_in_the_world xyzzy; void *foo() { return &xyzzy; } The unfortunate thing is that regular old gcc accepts this code, and I think it should be giving us a parse error. In ISO9899 6.2.5 (20), it says that "A structure type describes a sequentially allocated *nonempty* set of member objects..." (emphasis mine).
Another crashing testcase involving an empty struct: 247 gally> cat arf4.i typedef struct { } rwlock_t; struct fs_struct { rwlock_t lock; int umask; }; void __copy_fs_struct(struct fs_struct *fs) { fs->lock = (rwlock_t) { }; } I expect that this is a very closely-related problem. Note that if you take out `umask' from fs_struct, the crash stops happening.
I should perhaps point out that the reason we are interested in these empty structs is that the linux kernel sources assume that empty structs are OK.
The "critical" status was just us kidding around. :-)
Fixed. Testcase: test/Regression/CFrontend/2003-11-01-EmptyStructCrash.c Thanks! -Chris
I can reproduce it as of Nov 4, 2003, so the bug is not fixed.
So the confusion stems from the fact that Chris only fixed the first but not the second test case. I managed to narrow my large test case to an exact replica of Brian's post.
Ah, roit. The second, even uglier test is now llvm/test/Regression/CFrontend/2003-11-04-EmptyStruct.c -Chris
This is now (re)fixed. Here's a CFE patch: $ diff -u llvm-types.c~ llvm-types.c --- llvm-types.c~ 2003-11-02 17:08:38.000000000 -0600 +++ llvm-types.c 2003-11-04 13:25:46.000000000 -0600 @@ -672,7 +672,7 @@ unsigned ElSize = GetDeclSize(field); /* In bits */ int HasSignedField; unsigned StartByte; - if (BitAlignment > ElSize) ElSize = BitAlignment; + if (ElSize && BitAlignment > ElSize) ElSize = BitAlignment; HasSignedField = !TREE_UNSIGNED(TREE_TYPE(field)); @@ -1205,15 +1205,25 @@ fprintf(stderr, "Setting field indexes to: { "); #endif + Idx = 0; for (; Field; Field = GetNextFieldDecl(Field)) { unsigned FieldByteOffset = GetFieldOffset(Field)/8; - for (Idx = 0; Idx+1 < Result->NumElements && - ElementOffsets[Idx+1] <= FieldByteOffset; ++Idx) + for (; Idx+1 < Result->NumElements && + ElementOffsets[Idx+1] <= FieldByteOffset && + ElementOffsets[Idx] != FieldByteOffset; ++Idx) /*empty*/; #if DEBUG_STRUCT_LAYOUT fprintf(stderr, "%d, ", Idx); #endif SET_DECL_LLVM(Field, llvm_constant_new_integral(UByteTy, Idx)); + + /* If we just passed over a zero sized field, skip ahead to the next + * field, so we don't assign all consequtive zero sized elements to the + * same field. + */ + if (Idx+1 < Result->NumElements && + ElementOffsets[Idx+1] == ElementOffsets[Idx]) + ++Idx; /* Start looking at the next field */ } #if DEBUG_STRUCT_LAYOUT