Heads Up: Code generation bug

  • Just stumbled onto this and it cost me quite a few hours of
    frustration. Hopefully someone else can benefit from this...

    I just reported to Apple a code generation bug I discovered today in
    Xcode 2.4.1 and 2.5. Under some circumstances (don't know exactly
    what though),enabling optimized code generation results in incorrect
    execution.

    Steps to Reproduce:

    1) Download and decompress sample project "GP" from
    <http://www.muratnkonar.com/source-code/GP.zip>

    2) Note that the file "FooVoo.mm" declares as a constant an NSPoint
    named "kItemLabelsOrigin" with value {20, 8}.

    3) Note also that in the init method of FooVoo, an assigment from
    kItemLabelsOrigin to a local variable "itemNameOrigin" is made.
    Immediately after the assigment, the x and y coordinates of
    itemNameOrigin are compared to the x and y coordinates of
    kItemLabelsOrigin. Depending on the result, a message is logged to
    the console. Then the values of kItemLabelsOrigin and itemNameOrigin
    are logged to the console.

    Here's the code in FooVoo.mm:

    const NSPoint kItemLabelsOrigin = NSMakePoint(20, 8);

    @implementation FooVoo

    - (id) init
    {
        NSPoint itemNameOrigin = kItemLabelsOrigin;

        if (itemNameOrigin.x == kItemLabelsOrigin.x && itemNameOrigin.y
    == kItemLabelsOrigin.y)
        {
            NSLog(@"itemNameOrigin == kItemLabelsOrigin");
        }
        else
        {
            NSLog(@"itemNameOrigin != kItemLabelsOrigin");
        }

        NSLog(@"kItemLabelsOrigin = %@", NSStringFromPoint
    (kItemLabelsOrigin));
        NSLog(@"itemNameOrigin = %@", NSStringFromPoint(itemNameOrigin));

        return [super init];
    }

    @end

    4) Build and run the project using the Release configuration (which
    has Optimization level set to "Fastest, Smallest"), observing
    messages logged to the console.

    Expected Results:

    Something like:

        Running…
        2007-11-13 20:14:11.200 GP[880] itemNameOrigin == kItemLabelsOrigin
        2007-11-13 20:14:11.201 GP[880] kItemLabelsOrigin = {20, 8}
        2007-11-13 20:14:11.201 GP[880] itemNameOrigin = {20, 8}

    Note that the log indicates that itemNameOrigin and kItemLabelsOrigin
    have (as expected) the same value.

    Actual Results:

        Running…
        2007-11-13 20:16:39.953 GP[944] itemNameOrigin != kItemLabelsOrigin
        2007-11-13 20:16:39.953 GP[944] kItemLabelsOrigin = {20, 8}
        2007-11-13 20:16:39.953 GP[944] itemNameOrigin = {0, 0}

    The assigment fails!

    _murat
  • This looks to me like floating point rounding issues. Essentially, one
    should generally avoid comparing floating point values for equality.

    Clark Cox III
    <Clark.cox...>
    Sent from my iPhone

    On Nov 13, 2007, at 20:50, m <m0987...> wrote:

    > Just stumbled onto this and it cost me quite a few hours of
    > frustration. Hopefully someone else can benefit from this...
    >
    > I just reported to Apple a code generation bug I discovered today in
    > Xcode 2.4.1 and 2.5. Under some circumstances (don't know exactly
    > what though),enabling optimized code generation results in incorrect
    > execution.
    >
    > Steps to Reproduce:
    >
    > 1) Download and decompress sample project "GP" from
    > <http://www.muratnkonar.com/source-code/GP.zip>
    >
    > 2) Note that the file "FooVoo.mm" declares as a constant an NSPoint
    > named "kItemLabelsOrigin" with value {20, 8}.
    >
    > 3) Note also that in the init method of FooVoo, an assigment from
    > kItemLabelsOrigin to a local variable "itemNameOrigin" is made.
    > Immediately after the assigment, the x and y coordinates of
    > itemNameOrigin are compared to the x and y coordinates of
    > kItemLabelsOrigin. Depending on the result, a message is logged to
    > the console. Then the values of kItemLabelsOrigin and itemNameOrigin
    > are logged to the console.
    >
    > Here's the code in FooVoo.mm:
    >
    > const NSPoint kItemLabelsOrigin = NSMakePoint(20, 8);
    >
    > @implementation FooVoo
    >
    > - (id) init
    > {
    > NSPoint itemNameOrigin = kItemLabelsOrigin;
    >
    > if (itemNameOrigin.x == kItemLabelsOrigin.x && itemNameOrigin.y
    > == kItemLabelsOrigin.y)
    > {
    > NSLog(@"itemNameOrigin == kItemLabelsOrigin");
    > }
    > else
    > {
    > NSLog(@"itemNameOrigin != kItemLabelsOrigin");
    > }
    >
    > NSLog(@"kItemLabelsOrigin = %@", NSStringFromPoint
    > (kItemLabelsOrigin));
    > NSLog(@"itemNameOrigin = %@", NSStringFromPoint(itemNameOrigin));
    >
    > return [super init];
    > }
    >
    > @end
    >
    >
    > 4) Build and run the project using the Release configuration (which
    > has Optimization level set to "Fastest, Smallest"), observing
    > messages logged to the console.
    >
    > Expected Results:
    >
    > Something like:
    >
    > Running…
    > 2007-11-13 20:14:11.200 GP[880] itemNameOrigin == kItemLabelsOrigin
    > 2007-11-13 20:14:11.201 GP[880] kItemLabelsOrigin = {20, 8}
    > 2007-11-13 20:14:11.201 GP[880] itemNameOrigin = {20, 8}
    >
    > Note that the log indicates that itemNameOrigin and
    > kItemLabelsOrigin have (as expected) the same value.
    >
    > Actual Results:
    >
    > Running…
    > 2007-11-13 20:16:39.953 GP[944] itemNameOrigin != kItemLabelsOrigin
    > 2007-11-13 20:16:39.953 GP[944] kItemLabelsOrigin = {20, 8}
    > 2007-11-13 20:16:39.953 GP[944] itemNameOrigin = {0, 0}
    >
    > The assigment fails!
    >
    > _murat
  • On Nov 14, 2007 4:09 PM, Clark S. Cox III <clarkcox3...> wrote:
    > This looks to me like floating point rounding issues. Essentially, one
    > should generally avoid comparing floating point values for equality.

    It doesn't look like it. The wrong branch would be caused by that, but
    he's doing an *assignment* to NSPoint.

    Dave.
  • On 14 Nov 2007, at 05:50, m wrote:

    > 4) Build and run the project using the Release configuration (which
    > has Optimization level set to "Fastest, Smallest"), observing
    > messages logged to the console.
    >

    Having tried it here (on Xcode 3), the level of optimization is not
    important. Anything but "None" causes the same problem.

    Matt Gough
  • If you change the initialization of your global variable to

    const NSPoint kItemLabelsOrigin = (NSPoint){20, 8};

    then it works fine.

    dave

    On 13-Nov-07, at 9:50 PM, m wrote:

    > Just stumbled onto this and it cost me quite a few hours of
    > frustration. Hopefully someone else can benefit from this...
    >
    > I just reported to Apple a code generation bug I discovered today
    > in Xcode 2.4.1 and 2.5. Under some circumstances (don't know
    > exactly what though),enabling optimized code generation results in
    > incorrect execution.
    >
    > Steps to Reproduce:
    >
    > 1) Download and decompress sample project "GP" from
    > <http://www.muratnkonar.com/source-code/GP.zip>
    >
    > 2) Note that the file "FooVoo.mm" declares as a constant an NSPoint
    > named "kItemLabelsOrigin" with value {20, 8}.
    >
    > 3) Note also that in the init method of FooVoo, an assigment from
    > kItemLabelsOrigin to a local variable "itemNameOrigin" is made.
    > Immediately after the assigment, the x and y coordinates of
    > itemNameOrigin are compared to the x and y coordinates of
    > kItemLabelsOrigin. Depending on the result, a message is logged to
    > the console. Then the values of kItemLabelsOrigin and
    > itemNameOrigin are logged to the console.
    >
    > Here's the code in FooVoo.mm:
    >
    > const NSPoint kItemLabelsOrigin = NSMakePoint(20, 8);
    >
    > @implementation FooVoo
    >
    > - (id) init
    > {
    > NSPoint itemNameOrigin = kItemLabelsOrigin;
    >
    > if (itemNameOrigin.x == kItemLabelsOrigin.x && itemNameOrigin.y
    > == kItemLabelsOrigin.y)
    > {
    > NSLog(@"itemNameOrigin == kItemLabelsOrigin");
    > }
    > else
    > {
    > NSLog(@"itemNameOrigin != kItemLabelsOrigin");
    > }
    >
    > NSLog(@"kItemLabelsOrigin = %@", NSStringFromPoint
    > (kItemLabelsOrigin));
    > NSLog(@"itemNameOrigin = %@", NSStringFromPoint(itemNameOrigin));
    >
    > return [super init];
    > }
    >
    > @end
    >
    >
    > 4) Build and run the project using the Release configuration (which
    > has Optimization level set to "Fastest, Smallest"), observing
    > messages logged to the console.
    >
    > Expected Results:
    >
    > Something like:
    >
    > Running…
    > 2007-11-13 20:14:11.200 GP[880] itemNameOrigin == kItemLabelsOrigin
    > 2007-11-13 20:14:11.201 GP[880] kItemLabelsOrigin = {20, 8}
    > 2007-11-13 20:14:11.201 GP[880] itemNameOrigin = {20, 8}
    >
    > Note that the log indicates that itemNameOrigin and
    > kItemLabelsOrigin have (as expected) the same value.
    >
    > Actual Results:
    >
    > Running…
    > 2007-11-13 20:16:39.953 GP[944] itemNameOrigin != kItemLabelsOrigin
    > 2007-11-13 20:16:39.953 GP[944] kItemLabelsOrigin = {20, 8}
    > 2007-11-13 20:16:39.953 GP[944] itemNameOrigin = {0, 0}
    >
    > The assigment fails!
    >
    > _murat
    >
  • Indeed, there are several ways to avoid triggering this particular
    manifestation of this bug. I have even constructed other cases where
    code similar to the example does *not* result in a code generation
    error. This raises the possibility that perfectly legitimate code
    (not just this construction in particular) can sometimes (but not
    always) generate incorrect code.

    Since the bug depends on optimization level, it suggests that both
    the code being compiled and the code around it play a role in whether
    the bug will occur or not.

    _murat

    On Nov 14, 2007, at 6:10 AM, David Spooner wrote:

    > If you change the initialization of your global variable to
    >
    > const NSPoint kItemLabelsOrigin = (NSPoint){20, 8};
    >
    > then it works fine.
  • On Nov 14, 2007, at 2:33 AM, Matt Gough wrote:

    > On 14 Nov 2007, at 05:50, m wrote:
    >
    >> 4) Build and run the project using the Release configuration
    >> (which has Optimization level set to "Fastest, Smallest"),
    >> observing messages logged to the console.
    >>
    >
    > Having tried it here (on Xcode 3), the level of optimization is not
    > important. Anything but "None" causes the same problem.

    I just tried it on Xcode 2.5 and got it to happen as well. Curious to
    see what was going on, I dumped the assembly language and associated
    it back to the original statements. It's been awhile since I've
    played in assembly-land, but it looks like the compare is being done
    incorrectly (the .y part). Also, for the last NSLog statement, it
    looks like when it's making a copy of itemNameOrigin to pass to
    NSStringFromPoint that it's creating a NSPoint with a value of {0, 0}
    instead of copying itemNameOrigin.

    It looks like building for i386 does something similar. Very strange...

    steve

    --------------------------------------------

    - (id) init
    {
                mflr  r0                                // (prologue)
                lis  r2,ha16(LC8)                      // building
    itemNameOrigin?
                stmw  r28,-16(r1)                      // (prologue)
                lis  r29,ha16(_kItemLabelsOrigin)      // building
    &kItemLabelsOrigin
                mr    r31,r3                            // r31 = self

        NSPoint itemNameOrigin = kItemLabelsOrigin;

                lfs  f13,lo16(LC8)(r2)                // f13 =
    itemNameOrigin.x?
                lfs  f0,lo16(_kItemLabelsOrigin)(r29)  // f0 =
    kItemLabelsOrigin.x
                stw  r0,8(r1)                          // (prologue)
                la    r2,lo16(_kItemLabelsOrigin)(r29)  // r2 =
    &kItemLabelsOrigin
                stwu  r1,-112(r1)                      // (prologue)

        if (itemNameOrigin.x == kItemLabelsOrigin.x &&
            itemNameOrigin.y == kItemLabelsOrigin.y)

                fcmpu cr7,f0,f13                        // test
    itemNameOrigin.x == kItemLabelsOrigin.x?
                bne  cr7,L2                            // -> not equal
                lfs  f0,4(r2)                          // f0 =
    kItemLabelsOrigin.y
                fcmpu cr7,f0,f13                        // test
    itemNameOrigin.x == kItemLabelsOrigin.y?
                bne  cr7,L2                            // -> not equal

        {
            NSLog(@"itemNameOrigin == kItemLabelsOrigin");

                lis  r3,ha16(LC1)
                la    r3,lo16(LC1)(r3)                  // r3 =
    @"itemNameOrigin == kItemLabelsOrigin"
                b    L9
        }
        else
        {
            NSLog(@"itemNameOrigin != kItemLabelsOrigin");

            L2:
                lis  r3,ha16(LC3)
                la    r3,lo16(LC3)(r3)                  // r3 =
    @"itemNameOrigin != kItemLabelsOrigin"
        }

            L9:
                bl    L_NSLog$stub                      // NSLog(...)

        NSLog(@"kItemLabelsOrigin = %@", NSStringFromPoint
    (kItemLabelsOrigin));

                la    r2,lo16(_kItemLabelsOrigin)(r29)  // r2 =
    &kItemLabelsOrigin
                lwz  r0,lo16(_kItemLabelsOrigin)(r29)  // r0 =
    kItemLabelsOrigin.x
                lis  r29,ha16(LC5)
                lis  r28,ha16(LC7)
                lwz  r9,4(r2)                          // r9 =
    kItemLabelsOrigin.y
                la    r29,lo16(LC5)(r29)                // r29 =
    @"kItemLabelsOrigin = %@"
                la    r28,lo16(LC7)(r28)                // r28 =
    @"itemNameOrigin = %@"
                mr    r3,r0                            // r3 =
    kItemLabelsOrigin.x
                stw  r0,64(r1)                        // copy of
    kItemLabelsOrigin.x
                mr    r4,r9                            // r4 =
    kItemLabelsOrigin.y
                stw  r9,68(r1)                        // copy of
    kItemLabelsOrigin.y
                bl    L_NSStringFromPoint$stub          //
    NSStringFromPoint(...)
                mr    r4,r3                            // r4 =
    NSStringFromPoint result
                mr    r3,r29                            // r3 =
    @"kItemLabelsOrigin = %@"
                bl    L_NSLog$stub                      // NSLog(...)

        NSLog(@"itemNameOrigin = %@", NSStringFromPoint(itemNameOrigin));

                li    r0,0                              // "copy" of
    itemNameOrigin
                stw  r0,56(r1)                        //  set to {0, 0}?
                stw  r0,60(r1)
                nop
                lwz  r3,56(r1)
                lwz  r4,60(r1)
                bl    L_NSStringFromPoint$stub          //
    NSStringFromPoint(...)
                mr    r4,r3                            // r4 =
    NSStringFromPoint result
                mr    r3,r28                            // r3 =
    @"itemNameOrigin = %@"
                bl    L_NSLog$stub                      // NSLog(...)

        return [super init];

                lis  r2,ha16(L_OBJC_CLASS_FooVoo+4)
                lis  r4,ha16(L_OBJC_SELECTOR_REFERENCES_0)
                stw  r31,72(r1)
                addi  r3,r1,72
                lwz  r2,lo16(L_OBJC_CLASS_FooVoo+4)(r2)
                lwz  r4,lo16(L_OBJC_SELECTOR_REFERENCES_0)(r4)
                stw  r2,76(r1)
                bl    L_objc_msgSendSuper$stub          // [super ...]

                addi  r1,r1,112                        // (epilogue)
                lwz  r0,8(r1)                          // (epilogue)
                lmw  r28,-16(r1)                      // (epilogue)
                mtlr  r0                                // (epilogue)
                blr                                    // (epilogue)
    }
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today