Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
- Subject: Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
- From: Ken Thomases <email@hidden>
- Date: Sun, 21 Nov 2010 19:00:52 -0600
On Nov 21, 2010, at 12:56 PM, James Bucanek wrote:
> Ken Thomases <mailto:email@hidden> wrote (Sunday, November 21, 2010 6:13 AM -0600):
>
>> What possible uninitialized value could be "created by a stack allocation at"
>> that line?
>
> I don't know.
Hmm. This may have been a red herring. According to Valgrind's docs, "For uninitialised values originating from a stack allocation, Memcheck can tell you which function allocated the value, but no more than that -- typically it shows you the source location of the opening brace of the function."
>>> Note that valgrind is not saying that the data was being overwritten, but
>>> that NSConcreteData merely "depends on" (a.k.a. "reads") information from an
>>> address space that formerly belonged to the stack frame of
>>> -readNamePackagesOp, which should now be considered as invalid/uninitialized.
>
>> My point is that I suspect something is doing a copy of some uninitialized
>> bytes from a stack variable over top of NSConcreteData's internal state. Later, when NSConcreteData accesses it, it's basing a jump or move on this
>> corrupted data, which Valgrind knows comes from uninitialized data. (Valgrind
>> knows that a copy from uninitialized data propagates the uninitialized-ness,
>> even though the destination bytes have been written to.)
>
> But what code could that be? The NSData object's internal variables are allocated on the heap by +alloc. The only reference my code has to that is the NSData* data variable.
>
> There are only three other references to this variable after it's created, and those are all used to send it a message. The only messages sent are, in order:
>
> -autorelease
> -retain
> -bytes
> -release
>
> That's total extent of interaction with the NSData object.
Well, I had been thinking that a) NSConcreteData might store the data buffer inline, using some obscure technique, like the extraBytes parameter of NSAllocateObject; and b) overrunning or underrunning the buffer would thus clobber the object's internal state. That would have required writing to the read-only contents, which you've said is definitely not happening. So, it's probably a dead end.
On the other hand, it's one possible explanation for why using -dataWithBytesNoCopy:... makes the problem go away. With that method, NSConcreteData probably does not store the data buffer inline. It presumably just keeps the original pointer to the original buffer. On the other hand, yes, in my hypothesized scenario there would still be a case of writing to a buffer that ought to be read-only, and under-/overrunning its bounds, which should cause other problems.
>> On the other hand, the ...d08 address doesn't correspond to an instruction. It's in the middle of an instruction within the function prologue. I suspect
>> you have a different version of Mac OS X, with a different Foundation
>> framework. I'd be curious to know exactly what -[NSConcreteData dealloc] is
>> doing when Valgrind complains.
>
> So would I. :)
For what it's worth, the ...d08 address does make sense for the 64-bit -[NSConcreteData dealloc] of Foundation from Mac OS X 10.6.5. The code will have just retrieved the _bytes member of NSConcreteData and compared it to nil, which is where Valgrind complained. Note, it's not that the _bytes member is a stale pointer to some no-longer-valid stack frame. It's complaining that the _bytes member is itself uninitialized. (Just comparing it to nil and doing a jump based on that is triggering the Valgrind complaint. It hasn't even dereferenced the pointer by that point.)
I'm not sure how that counts as an uninitialized value created by stack allocation within -readNamePackagesOp.
Another thing: from my reading of Valgrind's docs, the address of a stack variable does not become nor point to an "uninitialized value" when the stack frame is invalidated. Rather, the address of the former stack frame is marked as inaccessible. (This is from the discussion of V vs. A bits.) So, if NSConcreteData were referencing the original location of the 'batch' variable, you'd be getting a different error from Valgrind.
Have you considered Valgrind's Ptrcheck tool? I don't actually know if it's available for Mac OS X, but if it is, it could provide a different view on this problem.
Regards,
Ken
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden