开发者

Why does a passed-by-value struct parameter get corrupted?

开发者 https://www.devze.com 2023-01-24 10:58 出处:网络
This isn’t the original code (I stripped things back in trying to simplify for debugging), but it does display the problem. On the face of it, looks simple enough:

This isn’t the original code (I stripped things back in trying to simplify for debugging), but it does display the problem. On the face of it, looks simple enough:

- (void) testMethod: (TouchData) toi  {

     TouchData newToi = toi;
     NSString *test = @"test string";
     NSLog(@"string: %@", test);

     // in ‘real’ code I pass the struct back
     // It’s void here for the simplest possible
     // case
}

TouchData is a struct, declared thus:

typedef struct {
    Entity *owner;
    CGPoint startPos;
    CGPoint latestPos;
    CGPoint startOfStraightSwipePos;
    NSTimeInterval startTime;
    NSTimeInterval latestTime;
    NSTimeInterval startOfStraightSwipeTime;
    CGFloat latestSpeed;
    NSMutableArray *gestures;
    BOOL isOfInterest;
} TouchData;

When I step through testMethod in the debugger (watching toi) on hitting NSLog (which doesn't even involve toi), all toi member values suddenly zero out. This doesn’t happen to the copy (newToi). It doesn’t happen if I pass the struct in by reference. It doesn’t happen if replace the testMethod invocation directly with the method body (ie. if I run these lines in situ rather than calling into a method). It doesn’t happen if I change the toi parameter type to a dummy struct with a couple of int members, created just before the call.

It might worth pointing out that testMethod is only called from within its own class, and that the caller has just extracted the struct from an NSMutableDictionary (via unboxing an NSValue). But given that (a) the struct is passed into the method here by value, and (b) that on entry its members as shown by the debugger are all as expected, I don’t see that this can be causing a problem. There is also the thorny issue of the two object pointers in the struct, but in other contexts they’re working out OK, and they check out in the debugger on entry to the method, so I don’t think I’ve missed essential retains.

I presume I’m running i开发者_开发问答nto some kind of heap or stack corruption, but I’ve no idea how or why. I’m new to Objective-C, and have previously worked in garbage collected environments, so my memory management experience is limited. It’s entirely possible that I’ve missed something painfully obvious.

I expect someone will tell me to make TouchData an object type instead, and indeed I may well go that way. I also have a couple of tested workarounds, ie. to either work on a copy, or pass the struct in by ref. But I’d really like to know what’s going on here.


If toi is not used after the line TouchData newToi=toi, the compiler can do whatever it wants to do in the stack memory where toi originally was placed after that line. For example, it might reuse the stack memory when calling another function, in this case NSLog.

So, watching toi by a debugger might show something strange. The compiler does often do these things, in particular if the optimization is turned on. Even with no optimization there's no guarantee that the stack location of toi is left intact after it's last used.

By the way, you said having object pointers inside toi didn't cause problems, but it's a tricky situation and I recommend strongly against that practice. Follow the standard retain/release rules; otherwise, another programmer who takes a look at your code (who might be yourself two years from now) would be totally confused. Also, the static analyzer (which can be accessed by doing Build & Analyze in XCode) might be confused and might give false positives. So, don't do that.

0

精彩评论

暂无评论...
验证码 换一张
取 消