I am getting NSData on my socket receiving function and I'm trying to copy that data in a tempbuffer of my audio class, I am using external type global variable to do so.
This is my code:
memcpy([recorder tempBuffer].mdata,(__bridger const void *)data,data.length);
Here recorder is my extern type global variable of audio class.
When control reaches this line of code an exception is thrown, what possibly be the mistake.
There are really three possibilities here:
[recorder tempBuffer].mdata is not a valid pointer. (What type is it, for instance? If it's a NSMutableData, you should be accessing its mutableBytes property.)
[recorder tempBuffer].mdata is not a valid pointer of sufficient size (data.length).
(__bridger const void *)data is not a valid pointer of sufficient size.
Of the three, I can guarantee that #3 needs addressing. A NSData is not itself the data you want, but an object wrapping the data you want. Instead of using a bridge here, you should be using data.bytes.
The other two, I can't help you with. I don't know what type mdata is or where it was allocated.
If the destination buffer is really a buffer you allocated with malloc or a uint8_t (or equivalent) buffer, you should:
Check to make sure that the destination buffer is big enough to hold the entire data contents.
Don't try to cast the NSData to a (void *) pointer, but rather use:
memcpy(destination, data.bytes, data.length);
If the NSData is not in a contiguous block (which in iOS 7 and later, it might not be), data.bytes will copy it to a contiguous buffer, which you can then use with memcpy.
Or better, you can avoid this redundant copy, by removing memcpy altogether:
[data getBytes:destination length:data.length];
This will, if the NSData is not in a contiguous block, avoid having data.bytes copy it to a contiguous buffer which you would then copy again with the memcpy.
Bottom line, NSData has a rich interface that should eliminate the need to use low-level memcpy calls yourself.
From the question, it's not clear what [recorder tempBuffer].mdata is and how you allocated it, so perhaps you can clarify. Hopefully that's not another NSData object that you're trying to copy into.
Related
I'm working on a NSData extension that encrypts data with a key, as shown below. I'm not too savvy with Objective-C, but would like to use it for this Cordova plugin, instead of requiring another plugin to bridge Swift files.
I'm curious if I need to do any work to ensure that all clean-up in my methods is happening, so that each time this method is called, there are no leaks.
When extending an NS object, does one need to wrap their methods in #autoreleasepool {}?
This is the method that encrypts data (NSData+AES256Encrypt.m):
- (NSData *)AES256EncryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeros for padding
// Get key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
kCCOptionPKCS7Padding, keyPtr,
kCCKeySizeAES256, NULL, [self bytes],
dataLength, buffer, bufferSize, &numBytesEncrypted);
if(cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
It is used in conjunction with NSString+AES256Encrypt.m:
- (NSString *)AES256EncryptWithKey:(NSString *)key {
NSData *plainData = [self dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [plainData AES256EncryptWithKey:key];
NSString *encryptedString = [encryptedData base64Encoding];
return encryptedString;
}
The line that concerns me is free(buffer) used in the first method posted above, called if cryptStatus is false (meaning it failed to encrypt). I also notice that method dataWithBytesNoCopy has a parameter freeWhenDone which:
If YES, the returned object takes ownership of the bytes pointer and frees it on deallocation.
But I'm not sure if it applies to my situation.
Thanks for any and all help.
I don't see any issues.
Autoreleasing is only for Objective-C objects. It basically delays the actual -release call a little bit by putting the object in an autorelease pool, which gets flushed after every iteration of the main run loop, calling -release on every object in the pool. Objects returned from methods are typically autoreleased, though ARC has a mechanism which can often avoid the overhead of the actual pool by figuring out that the value is only needed by the caller, and can keep track of the reference and just call -release there. In ARC mode, the compiler figures out for you when autorelease vs release is needed, and does not let you call those methods yourself.
Most of the time, you don't need your own autorelease pools, though if you are doing something in a loop where every iteration can create lots of temporary objects, you may want an autorelease_pool for every loop iteration so that memory does not get built up but rather gets cleaned up each time so the next iteration can re-use that memory. If you are writing a command-line program or some other tool which does not have its own Objective-C support, then yes you need an autorelease pool around the entry point at least.
C heap memory using malloc/free is outside the autorelease concept (which only pertains to the retain/release mechanism of NSObject). For every malloc(), you need to eventually call free() on that memory once it is no longer needed, otherwise it's a leak. The code above is correct -- there is a malloc(), and then either free() is called when returning nil, or the initWithBytesNoCopy: method is called (which is a special method which uses the passed-in bytes as the actual NSData storage, avoiding the overhead of a memory copy and further internal malloc, and will then call free() when the object itself is dealloced).
initWithBytesNoCopy:length: just calls -initWithBytesNoCopy:length:freeWhenDone: with a YES parameter for freeWhenDone, basically, per its documentation. You can call the longer method explicitly if you think it makes it more readable (as it does more clearly indicate you were aware of the free behavior), but it will work the same either way.
The NSData encrypt method really doesn't create any objects other than the one you are returning -- all of its code is more straight C code. So an autorelease pool would not help anything. The NSString encrypt method does create a few temporary objects, so if the amount of memory being encrypted is substantial, an autorelease pool around that may help if you have subsequent significant work (but be sure to have a strong reference to the object being returned outside the pool scope). And really, ARC will most likely figure out the temporary nature of most of those objects, and more efficiently deal with them than an autorelease pool anyways.
If you can profile your code using Instruments, you can see the memory usage of your program as it runs, and it would only be places with significant spikes that you would consider using a local autorelease pool.
I have some event from C++ written library which works in background thread:
virtual void OnData(const char* data)
{
NSLog(#"Here 'data' string is present %s", data);
#autoreleasepool {
NSString* sData= [NSString stringWithCString:data encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Here _sometimes_ 'data'(%s) is nil (\0). But sData is always present %#", data, sData);
[callback OnData:sData];
});
};
}
And sometimes I have NULL(I suspect its garbage actually) in dispatch_async block in argument variable. But local NSString variable is always here. Why?
P.S. Do I actually must use #autoreleasepool in this situation?
You have no assurances about the lifespan of the buffer that const char *data was pointing to by the time the async block is performed. The data could be dangling pointer by that point (and should be assumed to be so). It's very dangerous to use C-style pointers in any asynchronous references or outside the context they were originally created.
You should either use memory managed objects (e.g. NSData, NSString, etc.) or, if you insist on using C-style pointers and need to reference this pointer in the asynchronous block, copy the data to your own buffer, use that buffer, and then free it when you're done using that buffer in your asynchronous routine. In this case, you have your sData, so just don't refer to data after that point, and you'll be fine.
P.S. You later ask whether you must use #autoreleasepool in this situation.
In short, in most cases, no additional autorelease pool is needed. Notably, when using Grand Central Dispatch (e.g. dispatch_async), it has its own autorelease pools, so you don't have to create one. And, when your main thread yield back to its run loop, again, it's pool is drained. In short, you only need manually created autorelease pools when instantiating your own NSThread objects.
Having said that, sometimes you will introduce autorelease pools if doing significant memory intensive operations prior to yielding back to the run loop. In that case, you'll add autorelease pools in order to reduce the peak memory usage of the app. But this would not appear to be one of those cases.
If you had something like this:
void CallOnData()
{
char *test = malloc(5 * sizeof(char));
strcpy(test, "test");
OnData(test);
free(test);
}
You should expect data to be "NULL" in the block.
And autorelease is not needed, assuming you're using ARC, which you should be.
What is the difference between
+ (instancetype)dataWithBytes:(const void *)bytes length:(NSUInteger)length;
and
+ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
Also,
+ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
if b == YES, will it free the bytes automatically after converted to data?
I am working on an app and almost finished it. But the last problem is it crashes with memory error when it runs on device. It only crashes when on device, but in simulator it is perfect.
"malloc: * error for object 0x17415d0c0: Invalid pointer dequeued from free list * set a breakpoint in malloc_error_break to debug";
I have been working on this issue for several days:
iOS - My app crashes with memory Error if only runs on Device
But finally I found the problem, inside my Encryption and Decryption function, I have this:
Byte *buffer = (Byte*)malloc(asciiDataLength);
After I process with buffer, I convert it to NSData:
NSData *plainData = [NSData dataWithBytesNoCopy:buffer length:asciiDataLength freeWhenDone:YES];
This code caused my app to crash continuously, I changed it to
NSData *plainData = [NSData dataWithBytes:buffer length:asciiDataLength];
free(buffer);
Then my app never crash again.
So, I have to free the Byte by myself, ARC will not free it for me.
+ dataWithBytes:length::
Creates and returns a data object containing a given number of bytes copied from a given buffer.
+ dataWithBytesNoCopy:length::
Creates and returns a data object that holds length bytes from the buffer bytes.
dataWithBytes makes a copy of the buffer for the data, while the NoCopy version does not.
Important note: in the discussion section of dataWithBytesNoCopy:length::
The returned object takes ownership of the bytes pointer and frees it on deallocation. Therefore, bytes must point to a memory block allocated with malloc.
This means that initialising with this method essentially hands ownership of the memory to the NSData object, which will release it with free once it is done. If you try to initialise it with memory that you didn't allocate with malloc, your app will crash when the data object is deallocated.
dataWithBytesNoCopy is useful for when you get the bytes in a buffer from somewhere else, and are ready to hand them over to the NSData object, and won't use them yourself again outside of that.
If you want to initialise the data with memory you manage yourself, use + dataWithBytesNoCopy:length:freeWhenDone:. This is useful if the buffer will be stored somewhere persistently, and not changed or released.
However, if you are not sure how to correctly manage this memory manually, it is better to use dataWithBytes. The other methods are present for performance reasons, as avoiding copying large chunks of data can save a lot of time, but if you aren't sure how to use them, it's probably best not to — an app that doesn't crash is preferable to an app that crashes quickly.
[[NSData alloc] initWithBytes:buffer length:buflength] create a data object containing buflength bytes copied from the buffer bytes.
[NSData dataWithBytesNoCopy:buffer length:buflength] creates a data object that holds buflength bytes from the buffer bytes. The returned object takes ownership of the buffer pointer and frees it on deallocation. Therefore, buffer must point to a memory block allocated with malloc.
I am trying to find memory leaks in a very complicated legacy system that is written in C++/C on the Solaris operating system. the idea is to log every malloc and free and then postproccess the log.
i was able to write a stub malloc and free function that gets called correctly. the problem is that they dont do anyhing other than log. As a result the sytem crashes
My question is: is they a substitute malloc library that works on solaris that is can call from my stub malloc& free functions?
Why don't you just do an LD_PRELOAD of libumem and use UMEM_DEBUG? The manpage for umem_debug should give you more information.
Ideally, You should some memory profiling tool but in the absence of the same you can try to implement your own leak detector as you plan to.
You can just call malloc and free library versions through your wrapper.
Here is a scheme that you may try to implement:
Your wrapper function should implement a functionality wherein your wrapper for malloc stores the line number, file name, size requested & address being returned by malloc in a linked list.
How to get filename and line number?
Hint: Use __FILE__, __LINE__
The free wrapper should check the address being sent for freeing against the list and remove the entry from the linked list.
At the end of the program you should print contents of this linked list which gives you leaking memory size, file name and line number from where the buffer was allocated.
Update:
How do you map program malloc calls to own wrapper calls without infinite recurssion?
Through clever Use of Macros!
#define malloc(X) my_malloc( X, __FILE__, __LINE__, __FUNCTION__)
void* my_malloc(size_t size, const char *file, int line, const char *func)
{
void *p = malloc(size);
printf ("Allocated = %s, %i, %s, %p[%li]\n", file, line, func, p, size);
/*Link List functionality goes in here*/
return p;
}
In addition to libumem, I would recommend using Solaris Studio dbx which includes with RTC, a memory leak detector.
This function is in a loop. When I run the program, the line with IntPtr is giving me memory problems, I've put delete[], but it still doesn't solve the memory problem, can anyone help please? thanks
void showImage(IplImage *img,System::Windows::Forms::PictureBox^ picturebox)
{
IntPtr ip(new unsigned char[img->widthStep*img->height]); // this line causing memory usage to keep going up very fast
//memcpy(ip.ToPointer(),img->imageData,img->widthStep*img->height);
//picturebox->Image = gcnew Bitmap(img->width,img->height, img->widthStep, System:rawing::Imaging::PixelFormat::Format24bppRgb, ip);
delete[] ip;
}
This is C++\CLI
It is rather sad that this code compiles, but that is by design. The delete operator applied to a managed type doesn't actually free any memory. It calls the IDisposable::Dispose() method on the passed object. It is rather sad that this even works, the IntPtr gets boxed to turn it into an object and then checked to see if it implements the IDisposable interface. It doesn't of course, nothing happens.
You have to pass the pointer that you got back from the new operator. Don't forget to do this in a finally block so an exception cannot cause a leak.
Btw, there are more complications in the code that you commented. The Bitmap constructor you use requires you to keep the IntPtr valid, you cannot release the memory until the Bitmap is no longer used. So using delete isn't actually valid. Consider using Bitmap.LockBits() instead to get a pointer to a Bitmap that manages its own memory. And watch out for stride.