-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix memory corruption with NSMutableData(length:) #383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I think the problem goes deeper than this. NSMutableData should create a CFMutableData and defer its operations to that. The init method we're calling here should always copy the data into the new mutable buffer. |
@parkera NSMutableData.init() calls boils down to _CFDataInit() which creates CFMutableData already. This PR corrects init method, NSMutableData(length:) to copy the contents into the new CFMutableData buffer. |
So we call malloc and get an uninitialized region, then copy it into another buffer, then free it? |
@parkera Yes. That is exactly what happens after this fix. |
Why copy an uninitialized malloc buffer? It seems like an unnecessary performance cost. |
@parkera If we have to avoid copy of malloc'ed data, we need to create buffer at Foundation layer and reuse the same. But, we may not know the capacity of the buffer and we just need to create a buffer of capacity 'length' which will be expanded on first append. So, its a trade-off between copying malloc'ed content or allow it to grow at first append call. |
I wonder if it might be better to just call the plain init method and set the length that way we are less wasteful? |
@phausler that sounds good and neat. init() would initialize buffer with default capacity (say 16) and length as 0. CFDataSetLength() would check if capacity is < newlength. If yes, and buffer is growable, it expands it. let me build it. |
Fyi this is the abstract objc version: - (id)initWithLength:(NSUInteger)length {
self = [self initWithCapacity:length];
[self setLength:length];
return self;
} |
fc0c0de
to
2ff9184
Compare
addition of testcase
2ff9184
to
fef4d19
Compare
@phausler modified fix and contributed simple testcase as well. |
Thanks! |
NSMutableData(length:) allocates a memory of 'length' bytes and initialises NSMutableData with the same malloced bytes as buffer. And, capacity is 16 (default). And, any further appends to NSMutableData actually happens outside malloced region corrupting the memory next to it.
Fix is to avoid reusing malloced region as buffer. Instead, create new buffer with capacity and copy contents of malloced region into the buffer and free malloced region after copy.