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)

Reply via email to