Pointers to primitive objects not properly changing value - objective-c

I am having a bit of an issue passing a reference to a primitive type through chaining, and having the value represented by the pointer change correctly. The weird part is, if I call getBytes directly from main function, byteLocation is properly adjusted, but if I chain it through a convenience function, it seems get a junk value. Actually, even weirder, it at first gets the correct value when stepping through the debugger, but executes the return clause twice. The first return clause gets the correct value, the second loads byteLocation with a junk value. Any ideas?
EDIT (Actual Code):
#property (strong, nonatomic, nonnull) NSData* data;
#property (assign, nonatomic) CFByteOrder byteOrder;
- (void)convertBytesToHostOrder:(nonnull void*)buffer length:(NSUInteger)length {
if(length > 1 && self.byteOrder != CFByteOrderGetCurrent()) {
// Swap bytes if the packet endiness differs from the host
char* fromBytes = buffer;
for(NSUInteger i=0; i < length/2; i++) {
NSUInteger indexes[2] = {i, length-i-0};
char byte = fromBytes[indexes[0]];
fromBytes[indexes[0]] = fromBytes[indexes[1]];
fromBytes[indexes[1]] = byte;
}
}
}
- (nonnull void*)getBytes:(nonnull void*)buffer startingFrom:(nonnull NSUInteger*)location length:(NSUInteger)length {
NSRange range = NSMakeRange(*location, length);
[self.data getBytes:buffer range:range]; // self.data is an instance of NSData
[self convertBytesToHostOrder:buffer length:length];
NSUInteger update = range.location + range.length;
*location = update;
return buffer;
}
- (NSTimeInterval)readTimeIntervalStartingFrom:(nonnull NSUInteger*)byteLocation {
uint32_t seconds;
uint16_t milliseconds;
// This line of code screws up the byteLocation pointer for some reason
[self getBytes:&seconds startingFrom:byteLocation length:sizeof(seconds)];
[self getBytes:&milliseconds startingFrom:byteLocation length:sizeof(milliseconds)];
NSTimeInterval ti = seconds + milliseconds / ((double) 1000 * (1 << 6));
return ti;
}
- (void)readData {
NSUInteger byteLocation = 0;
self.sequenceNumber = *(uint8_t*) [self getBytes:&_sequenceNumber startingFrom:&byteLocation length:sizeof(_sequenceNumber)];
self.flags = *(uint8_t*) [self getBytes:&_flags startingFrom:&byteLocation length:sizeof(_flags)];
// Continue to process packet data if we didn't get a goodbye message
if(!(self.flags & LBRadarPongFlagGoodbye)) {
// Parse accelerations
int16_t int16;
self.accelerationX = (*(int16_t*) [self getBytes:&int16 startingFrom:&byteLocation length:sizeof(int16)]) / kGToRaw;
self.accelerationY = (*(int16_t*) [self getBytes:&int16 startingFrom:&byteLocation length:sizeof(int16)]) / kGToRaw;
self.accelerationZ = (*(int16_t*) [self getBytes:&int16 startingFrom:&byteLocation length:sizeof(int16)]) / kGToRaw;
// Parse peripheral states
self.batteryVoltage = [self readFloat16From:&byteLocation];
self.chargeCurrent = [self readFloat16From:&byteLocation];
self.systemCurrent = [self readFloat16From:&byteLocation];
// All previous lines of code work properly and as expected.
// Buffers are read properly, and byteLocation properly reflects 14, which is the number of bytes read up to this point.
self.pongReceivedTimeIntervalSince1970 = [self readTimeIntervalStartingFrom:&byteLocation];
}
}

The problem seems to be with incrementing the location. In both cases you should copy from position zero, up to the size of the variable. In the following code:
[self readBytes:&seconds location:byteLocation length:sizeof(seconds)]
[self readBytes:&milliseconds location:byteLocation length:sizeof(milliseconds)]
The first call starts at position zero and reads 32 bits. The second one starts at position 32, which doesn't even fit in the variable's 16 bits. This is overflowing the buffer. Try this instead:
- (void*)readBytes:(void*)buffer location:(NSUInteger*)location length:(NSUInteger)length {
// The difference is in the next line. Zero instead of *location
[NSData getBytes:&buffer range:NSMakeRange(0, length)];
*location = *location + length;
return buffer; // Seems to be called twice, first time location* has the correct byteLocation inside it, second time location* has a junk value
}

At a guess[*] your error is on the line:
[self.data getBytes:&buffer range:NSMakeRange(*location, length)];
You are passing a void * value by taking the address of buffer - which is already a void *. Changing this to:
[self.data getBytes:buffer range:NSMakeRange(*location, length)];
will at least produce non-garabge results.
[*] I can only guess as the code you posted did not even compile, I edited your question to correct some of the more obvious errors - but even that involved some guessing! You should post real code.

I should have just posted the actual code, sorry guys. Turns out the error was in a helper function (convertBytesToHostOrder). This was reading out of bounds of buffer. Since buffer was the parameter right before byteLocation, it seems that writing at a location 1 spot beyond buffer was the byteLocation location. Fixed now and everything is working.
- (void)convertBytesToHostOrder:(nonnull void*)buffer length:(NSUInteger)length {
if(length > 1 && self.byteOrder != CFByteOrderGetCurrent()) {
// Swap bytes if the packet endiness differs from the host
char* fromBytes = buffer;
for(NSUInteger i=0; i < length/2; i++) {
NSUInteger indexes[2] = {i, length-i-0};
char byte = fromBytes[indexes[0]];
fromBytes[indexes[0]] = fromBytes[indexes[1]];
fromBytes[indexes[1]] = byte;
}
}
}
Should be:
NSUInteger indexes[2] = {i, length-i-1};

Related

Objective C- Confusing EXC_BAD_ACCESS when using [NSString initwithdata]

I am having some trouble using the data that I receive from a remote server. This is how I take in the data from my nsinputstream:
case NSStreamEventHasBytesAvailable:
{
if(!_data)
{
_data = [NSMutableData data];
}
uint8_t buffer = malloc(1024);
NSInteger *len = [inputStream read:buffer maxLength:1024];
if(len)
{
_data = [[NSData alloc]initWithBytesNoCopy:buffer length:1024];
[self closeThread];
}
shouldClose = YES;
break;
}
In the same class I have this function to return the data in order to use it in different classes:
-(NSData *)returnData {
return self.data;
}
In the view controller that I want to use the data in I have this code to retrieve the data for use:
_schools = [_server returnData];
NSString *schoolString = [[NSString alloc] initWithData:self.schools encoding:NSUTF8StringEncoding];//exc_bad_access
From what I understand about EXC_BAD_ACCESS exceptions they usually mean that you are trying to access data that either doesn't exist or is not allocated. The _schools variable shows a size of 1024 bytes so I know there is memory correctly allocated for it. Is there something else going wrong that I am missing?
You appear to have mixed up the types of the variables on these two lines:
uint8_t buffer = malloc(1024);
NSInteger *len = [inputStream read:buffer maxLength:1024];
In its current form, you will malloc'ate 1024 bytes of memory, and attempt to store the pointer to said memory in a uint8_t (which CLANG will rightly scream at you for), thus truncating the pointer and not providing a buffer, but rather a single unsigned 8-bit byte for the stream to attempt to read into. Also, -[NSInputStream read:maxLength:] does not return NSInteger *, just plain NSInteger, so all you need to do is swap the pointers on the two variables:
uint8_t *buffer = malloc(1024);
NSInteger len = [inputStream read:buffer maxLength:1024];
and it should work just fine.

fetcherWithRequest:fetcherClass not found

I am getting a warning in my GTMHTTPUploadFetcher.m file that says "-fetcherWithRequest:fetcherClass" not found (return type defaults to "id")
for this code
+ (GTMHTTPUploadFetcher *)uploadFetcherWithRequest:(NSURLRequest *)request
fetcherService:(GTMHTTPFetcherService *)fetcherService {
// Internal utility method for instantiating fetchers
GTMHTTPUploadFetcher *fetcher;
if (fetcherService) {
fetcher = [fetcherService fetcherWithRequest:request
fetcherClass:self];
} else {
fetcher = (GTMHTTPUploadFetcher *) [self fetcherWithRequest:request];
}
return fetcher;
}
and then I get an error involving the Foundation Framework
Parse Issue
expected expression
//this is where the expected expression is
- (void)uploadNextChunkWithOffset:(NSUInteger)offset
fetcherProperties:(NSMutableDictionary *)props {
// upload another chunk
NSUInteger chunkSize = [self chunkSize];
NSString *rangeStr, *lengthStr;
NSData *chunkData;
NSUInteger dataLen = [self fullUploadLength];
if (offset == kQueryServerForOffset) {
// resuming, so we'll initially send an empty data block and wait for the
// server to tell us where the current offset really is
chunkData = [NSData data];
rangeStr = [NSString stringWithFormat:#"bytes */%lu", (unsigned long)dataLen];
lengthStr = #"0";
offset = 0;
} else {
// uploading the next data chunk
#if DEBUG
**//this is the exact line of code causing the problem//**
(unsigned long)NSAssert2(offset < dataLen, #"offset %lu exceeds data length %lu",
offset, dataLen);
#endif
NSUInteger thisChunkSize = chunkSize;
// if the chunk size is bigger than the remaining data, or else
// it's close enough in size to the remaining data that we'd rather
// avoid having a whole extra http fetch for the leftover bit, then make
// this chunk size exactly match the remaining data size
BOOL isChunkTooBig = (thisChunkSize + offset > dataLen);
BOOL isChunkAlmostBigEnough = (dataLen - offset < thisChunkSize + 2500);
if (isChunkTooBig || isChunkAlmostBigEnough) {
thisChunkSize = dataLen - offset;
}
chunkData = [self uploadSubdataWithOffset:offset
length:thisChunkSize];
rangeStr = [NSString stringWithFormat:#"bytes %lu-%u/%lu",
(unsigned long)offset, offset + thisChunkSize - 1, (unsigned long)dataLen];
lengthStr = [NSString stringWithFormat:#"%lu", (unsigned long)thisChunkSize];
}
//related to this
! expanded from macro 'NSAssert2'
#define NSAssert2(condition, desc, arg1, arg2) NSAssert((condition), (desc), (arg1), (arg2))
! expanded from macro 'NSAssert'
#if !defined(_NSAssertBody)
#define NSAssert(condition, desc, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while(0)
#endif
Only started getting the error after I updated Xcode (not to new version just update)
anyone have any suggestions not sure these two are related or not so will post this second part separately.
Solved this by going into time machine and resurrecting the old .m file and replacing it. It no doesn't give me an error, however I can't upload video because of MIME type problem, but that's another post.
Solved this by going into time machine and resurrecting the old .m file and replacing it.

bad access playing back user recording synchronised with animation based on recording volume with array

I am trying to store an array based on audio input and then play animation frames corresponding to the input while the recording is played back.
The code is working up to now except after a while it crashes in the simulator and highlights
"CCLOG(#"adding image: %#", characterImageString);";
with this:
EXC_BAD_ACCESS (code=1, address=0xd686be8)
which is memory management I know but I am absolutely stumped.
if(isRecording){
int myInt;
NSString * characterImageString;
//get a number based on the volume input
float f = audioMonitorResults * 200; //convert max(0.06) to 12
f=((f/12)*10);
NSNumber *myNumber = [NSNumber numberWithDouble:(f+0.5)];
myInt = [myNumber intValue] + 1;
//create the image file name from the intiger we
//created from the audiomonitor results
if(myInt < 10){
characterImageString = [NSString stringWithFormat:#"fungus000%i.png",myInt];
} else if (myInt == 10){
characterImageString = [NSString stringWithFormat:#"fungus00%i.png",myInt];
}
CCLOG(#"adding image: %#", characterImageString);
//add each frame
[animationSequence addObject:characterImageString];
// print array contents
NSLog(#"animationSequence Array: %#", animationSequence);
// print array size
NSLog(#"animationSequence Number of Objects in Array: %u", [animationSequence count]); }
This is the code that plays as the audio is playing back:
-(void) updateAnimation:(ccTime) delta{
myFrame ++;
NSString *imageToDisplay;
imageToDisplay = animationSequence[myFrame];
CCTexture2D *currentTextureToDisplay = [[CCTextureCache sharedTextureCache] addImage:imageToDisplay];
[character setTexture:currentTextureToDisplay];
CCLOG(#"current texture to display: %#", currentTextureToDisplay);
if (myFrame >= [animationSequence count]) {
[self unschedule:#selector(updateAnimation:)];
}
Your characterImageString is nil if myInt > 10
The exception is thrown, because you're trying to print a variable, which hasn't been initialized.
You could try changing your code to something like this:
if(myInt < 10)
{
characterImageString = [NSString stringWithFormat:#"fungus000%i.png",myInt];
}
else if (myInt >= 10 && myInt < 100)
{
characterImageString = [NSString stringWithFormat:#"fungus00%i.png",myInt];
}
else if (myInt >= 100 && myInt < 1000)
{
characterImageString = [NSString stringWithFormat:#"fungus0%i.png",myInt];
}
else
{
characterImageString = [NSString stringWithFormat:#"fungus%i.png",myInt];
}
Obviously small debugging goes a long way. Could you add control printout for myInt before the line
if(myInt < 10){
to see the value of myInt before the crash?
if myInt is <= 0 your program has no protection for such case so resulting picture will not exist.
And for myInt > 10 the program will crash since NSString * characterImageString; is an automatic uninitialized variable of the random value.
hmmm ... some motherhood and apple pie , hard with the info available. Not certain what the initial float value is, so declare somewhere your min and max image numbers (say, kMinFrameNumber and kMaxFrameNumber). Since the float value could be anything at the start of your algorithm, add the following 'defensive' lines after computing myInt:
myInt=MAX(kMinFrameNumber,myInt);
myInt=MIN(kMaxFrameNumber,myInt);
then formatting :
characterImageString = [NSString stringWithFormat:#"fungus%04i.png",myInt];
finally, i doubt the exception is thrown at the highlighted line (that is where it is detected).
a. How did you declare the array animationSequence (is it retained?). If not, it could get autoreleased under your feet at some random interval, and you would be trying to send a message to a deallocated instance.
b. You should also check for bounds before addressing animationSequence
if(myFrame<[animationSequence count]-1) {
imageToDisplay = animationSequence[myFrame];
} else {
CCLOGERROR(#"Yelp ! addressing out of bounds!");
// terminate neatly here ! as in unschedule and return
}
c. check if your texture is nil before setting a sprite (it will accept a nil texture in cocos2d version 2.0) but, you are in the dark about the state of your code.

EXC_BAD_ACCESS when passing a pointer-to-pointer in a struct?

I've got a c-array of CGPoints in a struct. I need to replace this array when another CGPoint is added. I'd swear I'm doing this right and it seems to work fine a few times but eventually I'll get a EXC_BAD_ACCESS. What am I missing?
Here's the struct, which I've truncated to remove a lot of items that don't pertain.
typedef struct{
CGPoint **focalPoints;
NSUInteger focalPointCount;
CGRect boundingRect;
}FocalPoints;
Here's how I initialize it:
CGPoint *fPoints = (CGPoint *)malloc(sizeof(CGPoint));
FocalPoints focalInfo = {&fPoints, 0, rect};
Note that focalInfo is passed by reference to another function, like so: anotherFunction(&focalInfo).
Now here's the function that replaces the Points array with a new one:
void AddFocalPoint (CGPoint focalPoint, FocalPoints *focal){
if (focalPoint.x == CGFLOAT_MAX) return;
if (!CGRectContainsPoint(focal->boundingRect, focalPoint)) return;
int origCount = focal->focalPointCount;
int newCount = origCount + 1;
CGPoint *newPoints = (CGPoint *) malloc((newCount) * sizeof(CGPoint));
for (int i = 0; i < newCount; i++)
newPoints[i] = (i < origCount) ? *focal->focalPoints[i] : focalPoint; //error occurs here
free(*focal->focalPoints);
*focal->focalPoints = newPoints;
focal->focalPointCount = newCount;
}
The EXC_BAD_ACCESS error occurs in the above code on line 8: newPoints[i] = (i < origCount) ? *focal->focalPoints[i] : focalPoint;. So what exactly am I doing wrong?
This is a bit of a long shot, but maybe there's an issue with operator priority in *focal->focalPoints[i]. Have you try adding parentheses according to what you are trying to achieve ?
I believe the issue comes with where GCPoint *fPoints allocated as &fPoints evaluates to an address of that ... which is no longer valid once the function exits.
(The data to which it points was allocated fine with malloc.)
Aside from the suggestion I made in a comment, of using a linked list/NSMutableArray, my other suggestion would be that you use realloc() instead of constantly using malloc(), copying by hand, and then free()ing the old allocation.
void * realloc(void *ptr, size_t size);
The realloc() function tries to change the size of the allocation pointed to by ptr to size, and returns ptr. If there is not enough room to enlarge the memory allocation pointed to by ptr, realloc() creates a new allocation, copies as much of the old data pointed to by ptr as will fit to the new allocation, frees the old allocation, and returns a pointer to the allocated memory.
This is pretty much exactly what you are doing, but you can let the library handle it for you.
(May I also humbly suggest using the word "focal" slightly less to name variables in your function?) (Also also, I'm not really clear on why focalPoints in your struct is a pointer-to-pointer. You just want an array of structs -- a single pointer should be fine.)
Consider the following (somewhat extensive) rewrite; hope that it's helpful in some way.
typedef struct{
CGPoint *points; // Single pointer
NSUInteger count;
CGRect boundingRect;
} FocalPoints;
// Renamed to match Apple's style, like e.g. CGRectIntersectsRect()
void FocalPointsAddPoint (FocalPoints *, CGPoint);
void FocalPointsAddPoint (FocalPoints *f, CGPoint thePoint){
if (thePoint.x == CGFLOAT_MAX) return;
if (!CGRectContainsPoint(f->boundingRect, thePoint)) return;
NSUInteger origCount = f->count; // |count| is typed as NSUInteger; |origCount|
NSUInteger newCount = origCount + 1; // and |newCount| should be consistent
// Greatly simplified by using realloc()
f->points = (CGPoint *) realloc(f->points, newCount * sizeof(CGPoint));
(f->points)[newCount-1] = thePoint;
f->count = newCount;
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Just for testing; any point should be inside this rect
CGRect maxRect = CGRectMake(0, 0, CGFLOAT_MAX, CGFLOAT_MAX);
// Can initialize |points| to NULL; both realloc() and free() know what to do
FocalPoints fp = (FocalPoints){NULL, 0, maxRect};
int i;
for( i = 0; i < 10; i++ ){
FocalPointsAddPoint(&fp, CGPointMake(arc4random() % 100, arc4random() % 100));
NSLog(#"%#", NSStringFromPoint(fp.points[i]));
}
}
return 0;
}

LLVM GCC 4.2 EXC_BAD_ACCESS

Below code runs just fine on GCC 4.2 but fails with EXC_BAD_ACCESS in LLVM GCC 4.2
- (double_t)readDouble {
double_t *dt = (double_t *)(buffer+offset);
double_t ret = *dt; // Program received signal: EXC_BAD_ACCESS
offset += 8;
return ret;
}
That's how I allocate
int dataLength = [data length];
buffer = malloc(dataLength + 1);
buffer[dataLength] = 0; // null terminate to log
[data getBytes:(void *)buffer length:[data length]];
//NSLog(#"%s", buffer);
Offset and buffer is like
#interface PRDataSet : NSObject {
NSMutableArray *tables;
NSMutableDictionary *tablesByName;
NSMutableDictionary *tablesById;
#private
NSURLConnection *conn;
int offset;
char *buffer;
}
Yes offset is within range.
I do not free the buffer before I use it.
Any ideas?
This could be an aligment problem. The ARM processors (and many other processors) have restrictions regarding the data alignment, e.g. they can only read and write floating-point numbers from addresses that are a multiple of 4 or 8.
From the way the buffer is allocated in your code, it might not be allocated properly, or your double_t data elements aren't aligned within the buffer.
In order to avoid the problem, you should try to first copy the data into an aligned buffer and read it from there.
LLVM just doesn't read float directly.
Here's the solution:
- (uint32_t)readUInt32 {
uint32_t ret = *(uint32_t *)(buffer+offset);
offset += 4;
return ret;
}
- (uint16_t)readUInt16 {
uint16_t ret = *(uint16_t *)(buffer+offset);
offset += 2;
return ret;
}
- (uint64_t)readUInt64 {
uint64_t ret = *(uint64_t *)(buffer+offset);
offset += 8;
return ret;
}
- (float_t)readSingle {
uint32_t t = [self readUInt32];
float_t ret = *((float_t *)(&t));
return ret;
}
- (double_t)readDouble {
uint64_t t = [self readUInt64];
double_t ret = *((double_t *)(&t));
return ret;
}