• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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: James Bucanek <email@hidden>
  • Date: Fri, 19 Nov 2010 16:26:47 -0700

Greetings,

I've returned my my debugging adventure with a surprising discovery. I'll be writing this all up as a bug report later, but for now I thought I'd throw it out for comment. I know this has turned into a Cocoa question, but it's still a debugging issue and this is where the thread started ...

Running with Rich Siegel's suggestion of using valgrind, I imbedded a copy of valgrind in the bundle of my application[1], and rewrote my launcher to run my helper tool under the control of valgrind.

Here's what valgrind (immediately!) found:

==78805== Thread 9:
==78805== Conditional jump or move depends on uninitialised value(s)
==78805==    at 0x1002AAD08: -[NSConcreteData dealloc] (in /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation)
==78805==    by 0x1000EA4B4: -[InsertPackageNamesOp dealloc] (PackageNames.m:1824)
==78805==    by 0x1000EA78E: -[InsertNamesOp dealloc] (PackageNames.m:1885)
==78805==    by 0x100AC7830: _dispatch_worker_thread2 (in /usr/lib/libSystem.B.dylib)
==78805==    by 0x100AC7167: _pthread_wqthread (in /usr/lib/libSystem.B.dylib)
==78805==    by 0x100AC7004: start_wqthread (in /usr/lib/libSystem.B.dylib)
==78805==  Uninitialised value was created by a stack allocation
==78805==    at 0x1000E4BA7: -[PackageNames readNamePackagesOp] (PackageNames.m:590)

Well, that certainly looks like my NSConcreteData dealloc problem. But here's the mystery: I have no idea why this isn't working

The problem seems to be that NSConcreteData is accessing, or trying to do something with, the address of the buffer used to initialize the NSData object. But the address is a stack frame automatic, and the NSData object was created with +[NSData dataWithBytes:length:], which should copy the contents of the bytes parameter, not hang onto it.

Here's a simplified version of my original code:

typedef struct {
    int count;
    Record set[kBatchSizeMax];
    } RecordBatch;

-(void) readNamePackagesOp
{
while (!eof) {
RecordBatch batch;
batch.count = 0;
while (!eof && batch.count<kBatchSizeMax) {
Record record = <read a record from the file>
batch.set[batch.count++] = record
}
NSData* data = [NSData dataWithBytes:&batch length:offsetof(RecordBatch,set)+sizeof(Record)*batch.count];
InsertNamesOp* insertOp = [[[InsertNamesOp alloc] initWithBatchData:data] autorelease];
[indexOpsQueue addOperation: insertOp];
}
}


Basically, I'm asking +dataWithBytes:length: to copy the structure on the stack into a newly allocated block of memory. For some reason, NSData seems to be keeping the original pointer and using it again later, long after the stack frame of the function is gone, randomly corrupting memory or throwing SIGABRTs.

The documentation for +dataWithBytes:length: says nothing about bytes being a malloc'd block, unlike other NSData constructers that clearly require malloc'd memory.

Here's all I did to fix the problem:

-(void) readNamePackagesOp
{
while (!eof) {
RecordBatch* batch = malloc(sizeof(RecordBatch));
batch->count = 0;
while (!eof && batch->count<kBatchSizeMax) {
Record record = <read a record from the file>
batch->set[batch->count++] = record
}
NSData* data = [NSData dataWithBytesNoCopy:batch length:sizeof(RecordBatch) freeWhenDone:YES];
InsertNamesOp* insertOp = [[[InsertNamesOp alloc] initWithBatchData:data] autorelease];
[indexOpsQueue addOperation: insertOp];
}
}


So unless someone can tell me otherwise, I think this is either a bug in +[NSData dataWithBytes:length:], or an oversight in the documentation.

James

[1] Embedding valgrind doesn't work. Apparently, the install path gets compiled into the tool and it can't be moved. So don't try that, it won't work. :)


James Bucanek ____________________________________________________________________ Author of Professional Xcode 3 ISBN: 9780470525227 <http://www.proxcode3.com/> and Learn Objective-C for Java Developers ISBN: 9781430223696 <http://objectivec4java.com/>

_______________________________________________
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


  • Follow-Ups:
    • Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
      • From: Ken Thomases <email@hidden>
References: 
 >Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system (From: Scott Ribe <email@hidden>)

  • Prev by Date: Re: GDB: Timed out fetching data
  • Next by Date: Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
  • Previous by thread: Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
  • Next by thread: Re: Help DTrace gurus: suggestions for capturing a mis-allocated NSData object on a customer's system
  • Index(es):
    • Date
    • Thread