Massive allocations with with CFString while writing to NSOutputStream in iOS - ios

I have problem with large number of allocations while writing to NSOutputStream. I am using few classes together that are supposed to stream data from AudioUnit to remote server. Code below:
AudioProcessor.m
Data *data = [Data sharedData]; //it's shared data I use to store information for the final socket
intFromBuffer = audioBufferList->mBuffers[0].mData;
NSUInteger length = audioBufferList->mBuffers[0].mDataByteSize;
NSMutableData *dataOut = [[NSMutableData alloc] initWithCapacity:0];
[dataOut appendBytes:(const void *)intFromBuffer length:length * sizeof(SInt16)];
[data setOutput:dataOut]; //it writes data to the shared data
Data.m
#implementation Data
NSMutableData *output;
NSMutableData *input;
#synthesize output;
#synthesize input;
+(id)sharedData {
static Data *sharedData = nil;
#synchronized(self) {
if (sharedData == nil) {
sharedData = [[self alloc] init];
}
return sharedData;
}
}
-(void) setOutput:(NSMutableData*)outputt{
output = outputt;
}
-(void) setInput:(NSMutableData*)inputt{
input = inputt;
}
#end
NetworkCommunication.m
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
//NSLog(#"changed!!!!");
if ([keyPath isEqualToString:#"output"]) {
Data *data = [Data sharedData];
[self writeOut:data.output];
}
}
- (void)writeOut:(NSString *)s {
NSString *dataTo = [NSString stringWithFormat:#"%#\n", s];
NSData *data = [[NSData alloc] initWithData:[dataTo dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
}
It generally creates great amount of data, which in 2,5 min was about 200 MB in virtual memory. I tried to simply pass stringWithFormat: directly to my writeOut: function however it gives nothing, not idea how to deal with it.
If someone asks why I use stringWithFormat, simply because I need to put \n for server to read the message.
Any help much appreciated.
EDIT 1:
I tied it different way. In my AudioProcessor.m (because that's the data is created - in the recorder callback) I set it this way:
dataOut = [[NSMutableData alloc] initWithCapacity:0];
[dataOut appendBytes:(const void *)intFromBuffer length:length * sizeof(SInt16)];
net = [NetworkCommunication init];
const char *s = [dataOut bytes];
[[net outputStream] write:s maxLength:strlen(s)];
Now it generates insane allocations of type Malloc 1,00KB, and Malloc 2,00 KB with NSThread callStackSymbol and NSThread callStackReturnAddresses. What's still wrong?

Did you try sending C strings?
const char *s = [dataTo UTF8String];
[outputStream write:s maxLength:strlen(s)];

Related

Veracode CWE ID 416: Use After Free

How to fix Veracode Use After Free (CWE ID 416)
Recommendations from Veracode: Ensure that all pointers are set to NULL once the memory they point to has been freed.
Error pointed on: Line 8 "return result;"
+ (NSData *)dataFromBase64String:(NSString *)aString
{
NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
size_t outputLength = 0;
void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength];
free(outputBuffer);
return result;
}
Veracode scan does just help you to find places in code where you could improve security related coding. It does not stop attacks of course, but if your application is really that much security oriented you can make it more difficult to read out memory that is left after processing.
The word "Error" in the logging of Veracode is maybe a bit overused..
But my suggestion to address Veracodes Error pointed on: Line 8 "return result;" would be..
+ (NSData *)dataFromBase64String:(NSString *)aString
{
if (aString!=nil && [aString length]) {
size_t outputLength = 0;
void *outputBuffer = NULL;
NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
if (outputBuffer==NULL) return nil; //if NewBase64Decode() failed there is nothing to free..
NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength];
free(outputBuffer);
outputBuffer = NULL;
return result;
}
return nil;
}
This is because free'd memory is not set to NULL without your intent, so someone scanning memory for left overs would maybe find some clues about the former content of address.
here some nice discussion if NULL after free is really needed.
If you go that much into detail to avoid any kind of risk then you could also initiate outputBuffer with NULL (void* outputBuffer = NULL;) before you even use it.
Well it is another discussion if this is a bit overdo for some objC code where just swizzling could override the whole method.
EDIT: even more spagetti code, trying to avoid returning any value other than void and change a passed argument instead.
+ (void)dataFromBase64String:(NSString *)aString toResult:(NSData**)result
{
if (aString!=nil && [aString length]) {
size_t outputLength = 0;
void *outputBuffer = NULL;
NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
if (outputBuffer==NULL) return; //if NewBase64Decode() failed there is nothing to do
*result = [NSData dataWithBytes:outputBuffer length:outputLength];
free(outputBuffer);
outputBuffer = NULL;
}
}
//and call like..
NSData *myresult = nil;
[YOURCLASS dataFromBase64String:#"someString" toResult:&myresult];
NSLog(#"result=%#",myresult);
Now i wonder what Veracode is reporting with the edit above..

Send hexString Data through UDP

I'm developing an iOS app. I've come across a problem.
I am trying to send a hexString data through UDP to an wifi camera, which will response while getting correct data. My code is shown below. However I can't get any response from my wifi camera. (I'm using
https://github.com/robbiehanson/CocoaAsyncSocket)
NSString *sendMsg = #"6745000005000000000000000000000000000000000000001400000067450000140000000A";
NSData *bytes = [sendMsg dataUsingEncoding:NSUTF16BigEndianStringEncoding];
NSString *host = #"255.255.255.255";
[self.udpSocket sendData:bytes toHost:host port:ListenPort withTimeout:-1 tag:1];
Beside, I've try send my data through PacketSender (an app can send UDP data), which has a correct response.
enter image description here
Problem has been solved. The problem is while converting NSString to NSData. It's hex string which need to convert to NSData. Below is my code which works.
- (NSData *)dataFromHexString:(NSString *)hexString {
NSAssert((hexString.length > 0) && (hexString.length % 2 == 0), #"hexString.length mod 2 != 0");
NSMutableData *data = [[NSMutableData alloc] init];
for (NSUInteger i=0; i<hexString.length; i+=2) {
NSRange tempRange = NSMakeRange(i, 2);
NSString *tempStr = [hexString substringWithRange:tempRange];
NSScanner *scanner = [NSScanner scannerWithString:tempStr];
unsigned int tempIntValue;
[scanner scanHexInt:&tempIntValue];
[data appendBytes:&tempIntValue length:1];
}
return data;}

Convert dispatch_data_t to NSString after a read operation

In my small iOS app I have a CSV file that represents an histogram. The content of file is:
label0,value0
...
labelN,valueN
In my ViewController I read the file async with Grand Central Dispatch this way:
//create the channel with which read the CSV file
dispatch_io_t ch = dispatch_io_create_with_path(DISPATCH_IO_STREAM, [[[NSBundle mainBundle] pathForResource:#"histogram1" ofType:#"csv"] UTF8String], O_RDONLY, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int error) {
if(!error){
NSLog(#"Channel created!");
}
});
//read the whole file
dispatch_io_read(ch, 0, SIZE_MAX, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(bool done, dispatch_data_t dataRead, int error) {
if(!error && done){
NSString *ma = ; //???
NSLog(#"%#", ma);
}
});
I'd like to convert the dataRead (of type dispatch_data_t) to NSString to extract the values that represent the bars of the histogram.
There are a number of ways to do this, but the function you're looking for is dispatch_data_apply. Assuming the string you're reading is UTF8, this should work:
#interface NSString (FromDispatchData)
+ (instancetype)stringFromDispatchData: (dispatch_data_t)data;
#end
#implementation NSString (FromDispatchData)
+ (instancetype)stringFromDispatchData: (dispatch_data_t)data
{
if (!data)
return nil;
NSMutableString* str = [NSMutableString string];
dispatch_data_apply(data, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
[str appendString: [[NSString alloc] initWithBytes:buffer length:size encoding: NSUTF8StringEncoding]];
return true;
});
return [[self class] stringWithString: str];
}
#end

How to properly split up NSData?

I'm trying to split up NSData into smaller <100 length chunks so I can send them over CoreBluetooth but for some reason, it decides to mess up occasionally, proven by the fact that trying to combine the data and decoding the object from within the same method fails. Because of this, I'm assuming I'm splitting up the NSData wrong?
Here is the code I'm using to split it up (Taken from some kind stranger on stackoverflow!)
// Split up the data and put into Array
NSUInteger length = [data length];
NSUInteger chunkSize = 100;
NSUInteger offset = 0;
do {
NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset;
NSData* chunk = [NSData dataWithBytesNoCopy:(char *)[data bytes] + offset
length:thisChunkSize freeWhenDone:NO];
offset += thisChunkSize;
[orderQueue addObject:chunk];
} while (offset < length);
The data is then recombined and the object unarchived as so:
NSMutableData *finishedData = [[NSMutableData alloc] init];
for (NSData *dataChunk in orderQueue) {
[finishedData appendData:dataChunk];
}
Order *order = [NSKeyedUnarchiver unarchiveObjectWithData:finishedData]; // ERRORS OUT ON THIS LINE
finishedData = [[NSMutableData alloc] init];
dataChunks = [[NSMutableArray alloc] init];
On paper, I honestly think I'm doing it right but it still bugs out occasionally. Any ideas why this might be? :< I get the following error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSKeyedUnarchiver initForReadingWithData:]: incomprehensible archive (0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30)'
I just ran this code to check your logic and it's correct.
NSMutableArray *orderQueue = [[NSMutableArray alloc] init];
NSString *originalString = #"Here are some strings for you.";
for (NSInteger i = 0; i < 1000; ++i)
{
#autoreleasepool {
originalString = [originalString stringByAppendingString:#"\nHere are some strings for you."];
}
}
NSData *data = [originalString dataUsingEncoding:NSUTF8StringEncoding];
// Split up the data and put into Array
NSUInteger length = [data length];
NSUInteger chunkSize = 100;
NSUInteger offset = 0;
do {
NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset;
NSData* chunk = [NSData dataWithBytesNoCopy:(char *)[data bytes] + offset
length:thisChunkSize freeWhenDone:NO];
offset += thisChunkSize;
[orderQueue addObject:chunk];
} while (offset < length);
NSMutableData *finishedData = [[NSMutableData alloc] init];
for (NSData *dataChunk in orderQueue) {
[finishedData appendData:dataChunk];
}
NSString *recreatedString = [[NSString alloc] initWithData:finishedData encoding:NSUTF8StringEncoding];
NSLog(#"%#", recreatedString);
NSLog(#"%#", [originalString isEqualToString:recreatedString] ? #"Equal" : #"Error");
Your error must be somewhere else, potentially in the way you're responding to the <NSCoding> protocol in the Order class.

UIImage not received correctly from server

I am kind of new to objective-c so please help. i am receiving the image but not completely here is my code.
I am sure that the problems is here and not on the server side, but if you need me to post the code of the server side then ill do that.
uint8_t buf[3000000];
int len = 0;
len = [inputStream read:buf maxLength:3000000];
UIImage* fooo ;
NSMutableData *dataa=[[NSMutableData alloc] initWithLength:0];
do{
len = [inputStream read:buf maxLength:3000000];
if(len>0) current+=len;
}
while (len>-1);
[dataa appendBytes: (const void *)buf length:current];
fooo = [[UIImage alloc] initWithData:dataa];
[inputStream close];
[outputStream close];
server side
String FilePath=xxxxx.jpeg";
System.out.println (FilePath);
File file1=new
File(xxxxxx\\38.jpeg");
long v=file1.length();
byte [] mybytearray = new byte [(int)file1.length()];
FileInputStream fis = new
FileInputStream(FilePath);
BufferedInputStream bis = new
BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
os = connectionSocket.getOutputStream();//outpustream
System.out.println("Sending...");
os.write(mybytearray,0,mybytearray.length);
System.out.println("Sent");
os.flush();
Every time when stream comes you creating a new data and try to append.. but actually you are not appending all data to one data object you are doing this way NSMutableData *dataa=[[NSMutableData alloc] initWithLength:0]
I will prefer have an instance variable and do like this
if(!_data) {
_data = [[NSMutableData alloc] initWithLength:0];
}
Whole code should be like this, code is from apple documentation
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if(!_data) {
_data = [[NSMutableData data] retain];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[_data appendBytes:(const void *)buf length:len];
// bytesRead is an instance variable of type NSNumber .
[bytesRead setIntValue:[bytesRead intValue]+len];
} else {
NSLog(#"no buffer!");
}
break;
}
You should handle stream events. Stream will not bring data in one big chunk, so that's why we appending data here. Delegate method will be called with an event and you can set check on event.
When you got this event NSStreamEventEndEncountered close your stream object and create uiimage object
switch(NSStreamEventEndEncountered){
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
stream = nil; // stream is ivar, so reinit it
if (_data!=nil)
UIImage *image = [UIImage imageWithData:_data];
}

Resources