https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86913
Bug ID: 86913
Summary: Sending a nil message using a method signature
returning a struct corrupts the stack
Product: gcc
Version: 8.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: objc
Assignee: unassigned at gcc dot gnu.org
Reporter: yavor at gnu dot org
Target Milestone: ---
Created attachment 44524
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44524&action=edit
Preprocessed source of the test program
Josh Freeman discovered that sending a nil message using a method signature
that returns a structure results in:
1. Garbage values in the returned structure's members (affects: x86/x86_64,
with and without optimization)
2. A corrupted stack (affects: x86 with -O1 or -O2)
After some investigation, I can confirm that this bug was fixed in April 2013
(r198140, PR target/57018). But the change was reverted in November 2013 as
part of a fix for PR target/57293 (r205498). AFAICT all compiler versions are
affected, except 4.8 (the fix was backported to the gcc-4_8-branch in May
2013).
Minimized test program based on Josh's test program for GNUstep:
...
#include <objc/runtime.h>
#import <objc/Object.h>
int printf (const char *, ...);
struct Size { float w; float h; };
static const struct Size ZeroSize = {0.0, 0.0};
@interface NilMsgCheck : Object
+ (id) new;
- (struct Size) nmcZeroSize;
- (void) nmcSendNilMsg;
@end
@implementation NilMsgCheck
+ (id) new
{
return class_createInstance (self, 0);
}
- (struct Size) nmcZeroSize
{
return ZeroSize;
}
- (void) nmcSendNilMsg
{
struct Size size = [self nmcZeroSize];
printf ("[self nmcZeroSize] returned: w = %f; h = %f\n", size.w, size.h);
size = [nil nmcZeroSize];
printf ("[nil nmcZeroSize] returned: w = %f; h = %f\n", size.w, size.h);
}
@end
int
main (void)
{
NilMsgCheck *object = [NilMsgCheck new];
[object nmcSendNilMsg];
return 0;
}
...
On x86_64-linux-gnu, it prints:
[self nmcZeroSize] returned: w = 0.000000; h = 0.000000
[nil nmcZeroSize] returned: w = -nan; h = 0.000000
On x86-linux-gnu (with optimization) it segfaults (or, if built with
-fstack-protector-strong it aborts with "stack smashing detected").
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/home/yavor/libexec/gcc/i686-pc-linux-gnu/8.2.0/lto-wrapper
Target: i686-pc-linux-gnu
Configured with: ./configure --prefix=/home/yavor --disable-nls
--disable-multilib --enable-languages=c,objc
Thread model: posix
gcc version 8.2.0 (GCC)