I'm trying to get this code: http://code.google.com/p/switchcontrol/source/browse/trunk/code/AFSwitchControl.m compiling under Apple LLVM in Xcode 4.5.2. It works when compiled with LLVM/GCC, but crashes in the mouseDown method when switched to Apple LLVM on line 198:
NSRect knobRect = _AFSwitchControlKnobRectForInsetBackground(slotRect, _offset);
Because _offset is not set. It's suppose to be set in the bind method with this line:
[self setOffset:(CGFloat)[self state]];
But it appears that nothing is being set under LLVM for some reason. My binding call looks like:
[control bind:NSValueBinding toObject:self withKeyPath:@"isToggleSwitchOn" options:nil];
Any ideas why the control's state is not returning anything under LLVM? Thanks!
The problem is actually a few lines above, in the call to _AFSwitchControlPartRects.
- (void)mouseDown:(NSEvent *)event {
NSRect textRect, backgroundRect;
_AFSwitchControlPartRects([self bounds], &textRect, &backgroundRect);
NSRect slotRect = _AFSwitchControlInsetBackgroundRect(backgroundRect);
NSRect knobRect = _AFSwitchControlKnobRectForInsetBackground(slotRect, _offset);
The second argument to _AFSwitchControlPartRects, &textRect is a pointer to a rect.
However in the implementation of the function, that parameter is supposed to be a pointer to enough space for two rects.
NS_INLINE void _AFSwitchControlPartRects(NSRect bounds, NSRect *textRects, NSRect *backgroundRect) {
NSDivideRect(bounds, textRects, backgroundRect, NSWidth(bounds)/5.0, NSMinXEdge);
textRects[1] = _AFSwitchControlInsetTextRect(NSOffsetRect(textRects[0], NSWidth(*backgroundRect), 0));
textRects[0] = _AFSwitchControlInsetTextRect(textRects[0]);
When this writes to textRects[1], it's scribbling on -mouseDown's stack. Buffer overflow.
It looks to me like it's happening to clobber self, so the next dereference of self will die. This happens to be the use of _offset.