LLVM GCC 4.2 EXC_BAD_ACCESS - objective-c

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;
}

Related

How to pass const void *bytes to an Objective-C block from Swift

I'm writing some Swift (1.2) code that calls an Objective-C library (transcribing some earlier Objective-C code). It's not clear how it's supposed to work. I've tried a bunch of variations, and nothing satisfies the compiler. Here's the Objective-C code I started with:
// Objective-C
NSData *fileData = //
const void *bytes = fileData.bytes;
unsigned int bufferSize = 1024; //Arbitrary
[object writeDataWithBlock:
^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) {
for (NSUInteger offset = 0; offset <= fileData.length; offset += bufferSize) {
unsigned int size = (unsigned int)MIN(fileData.length - i, bufferSize);
writeData(&bytes[i], size);
}
return YES;
}];
So far, I've gotten as far as this Swift code:
// Swift
let fileData = //
let ptr = UnsafePointer<UInt8>(fileData.bytes)
let bufferSize = 1024 // Arbitrary
object.writeDataWithBlock() { (writeData, actionError) -> Bool in
for var offset = 0; offset <= fileData.length; offset += bufferSize {
let size = CUnsignedInt(min(fileData.length - offset, bufferSize))
writeData(UnsafePointer<Void>(ptr[offset]), size)
}
return true
}
That's giving me this error:
Cannot find an initializer for type 'UnsafePointer' that accepts an arguments list of type '(UInt8)'
When I remove the UnsafePointer<Void> conversion to do a more direct translation, yielding this line:
writeData(&ptr[offset], size)
I get this error, pointing at the & character:
Type of expression is ambiguous without more context
Without the &, it yields a UInt8, giving me this error:
Cannot invoke 'writeData' with an argument list of type '(Uint8, UInt32)'
What do I need to do to read the bytes out of the NSData sequentially and pass them onto another method?
Pointer arithmetic should (and does) get you the results you're looking for.
let fileData = //
let bufferSize = 1024 // Arbitrary
object.writeDataWithBlock() { (writeData, actionError) -> Bool in
for var offset = 0; offset <= fileData.length; offset += bufferSize {
let size = CUnsignedInt(min(fileData.length - offset, bufferSize))
writeData(fileData.bytes + offset, size)
}
return true
}

Pointers to primitive objects not properly changing value

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};

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.

Programmatically get all frame variables in objective-c

I'm trying to create my own custom assert. However, I would like my assertion to automatically include all of the relevant variables. This seems really basic to me, and I've searched around for about an hour but I can't seem to find a way get access to all the relevant stack frame variables. Does anyone know how to get these variables?
FYI - I don't need to access the variables in the debugger, I need to access them programmatically. I would like to upload them along with the crash report to give me more information about the crash. I also know that I can print them out manually...that is exactly what I'm looking to avoid.
You are basically asking to re-invent a good sized chunk of the debugger.
Without symbols, there isn't anything you can interrogate to figure out the layout of the local frame. Even with symbols, it is quite likely that the optimizer will have stomped on any local variables as the optimizer will re-use stack slots at whim once it determines the variable is no longer needed within the frame.
Note that many crashes won't be able to be caught at all or, if caught, the frame within which they occurred will have long since been destroyed.
Since you mention that you are creating a custom assertion, it sounds like you really aren't looking to introspect crashes as much as dump a snap of the local frame when you programatically detect that things have gone off the rails. While there really isn't a means of automatically reporting on local stack state, you could do something like:
{ ... some function ....
... local variables ...
#define reportblock ^{ ... code that summarizes locals ... ; return summary; }
YourAssert( cond, "cond gone bad. summary: %#", reportblock());
}
Note that the #define ensures that each YourAssert() captures the state at the time of the assertion. Note also that the above might have a potentially significant impact on performance.
Note also that I just made that code up. It seems like it is worthy of investigation, but may prove non-viable for a number of reasons.
If you're willing to use Objective-C++, then this is definitely a possibility, as long as you are also willing to declare your variables differently, and understand that you will only be able to grab your own variables with this method.
Also note that it will increase your stack frame size with extra __stack_ variables, which could cause memory issues (although I doubt it, personally).
It won't work with certain constructs such as for-loops, but for 95% of cases, this should work for what you need:
#include <vector>
struct stack_variable;
static std::vector<const stack_variable *> stack_variables;
struct stack_variable {
void **_value;
const char *_name;
const char *_type;
const char *_file;
const char *_line;
private:
template<typename T>
stack_variable(const T& value, const char *type, const char *name, const char *file, const char *line) : _value((void **) &value), _type(type), _name(name), _file(file), _line(line) {
add(*this);
}
static inline void add(const stack_variable &var) {
stack_variables.push_back(static_cast<const stack_variable *>(&var));
}
static inline void remove(const stack_variable &var) {
for (auto it = stack_variables.begin(); it != stack_variables.end(); it++) {
if ((*it) == &var) {
stack_variables.erase(it);
return;
}
}
}
public:
template<typename T>
static inline stack_variable create(const T& value, const char *type, const char *name, const char *file, const char *line) {
return stack_variable(value, type, name, file, line);
}
~stack_variable() {
remove(*this);
}
void print() const {
// treat the value as a pointer
printf("%s:%s - %s %s = %p\n", _file, _line, _type, _name, *_value);
}
static void dump_vars() {
for (auto var : stack_variables) {
var->print();
}
}
};
#define __LINE_STR(LINE) #LINE
#define _LINE_STR(LINE) __LINE_STR(LINE)
#define LINE_STR _LINE_STR(__LINE__)
#define LOCAL_VAR(type, name, value)\
type name = value;\
stack_variable __stack_ ## name = stack_variable::create<type>(name, #type, #name, __FILE__, LINE_STR);\
(void) __stack_ ## name;
Example:
int temp() {
LOCAL_VAR(int, i_wont_show, 0);
return i_wont_show;
}
int main(){
LOCAL_VAR(long, l, 15);
LOCAL_VAR(int, x, 192);
LOCAL_VAR(short, y, 256);
temp();
l += 10;
stack_variable::dump_vars();
}
Output (note the junk extra bytes for the values smaller than sizeof(void *), there isn't much I can do about that):
/Users/rross/Documents/TestProj/TestProj/main.mm:672 - long l = 0x19
/Users/rross/Documents/TestProj/TestProj/main.mm:673 - int x = 0x5fbff8b8000000c0
/Users/rross/Documents/TestProj/TestProj/main.mm:674 - short y = 0xd000000010100
Threads will royally screw this up, however, so in a multithreaded environment this is (almost) worthless.
I decided to add this as a separate answer, as it uses the same approach as my other one, but this time with an all ObjC code. Unfortunately, you still have to re-declare all of your stack variables, just like before, but hopefully now it will work better with your existing code-base.
StackVariable.h:
#import <Foundation/Foundation.h>
#define LOCAL_VAR(p_type, p_name, p_value)\
p_type p_name = p_value;\
StackVariable *__stack_ ## p_name = [[StackVariable alloc] initWithPointer:&p_name\
size:sizeof(p_type)\
name:#p_name\
type:#p_type\
file:__FILE__\
line:__LINE__];\
(void) __stack_ ## p_name;
#interface StackVariable : NSObject
-(id) initWithPointer:(void *) ptr
size:(size_t) size
name:(const char *) name
type:(const char *) type
file:(const char *) file
line:(const int) line;
+(NSString *) dump;
#end
StackVariable.m:
#import "StackVariable.h"
static NSMutableArray *stackVariables;
#implementation StackVariable {
void *_ptr;
size_t _size;
const char *_name;
const char *_type;
const char *_file;
int _line;
}
-(id) initWithPointer:(void *)ptr size:(size_t)size name:(const char *)name type:(const char *)type file:(const char *)file line:(int)line
{
if (self = [super init]) {
if (stackVariables == nil) {
stackVariables = [NSMutableArray new];
}
_ptr = ptr;
_size = size;
_name = name;
_type = type;
_file = file;
_line = line;
[stackVariables addObject:[NSValue valueWithNonretainedObject:self]];
}
return self;
}
-(NSString *) description {
NSMutableString *result = [NSMutableString stringWithFormat:#"%s:%d - %s %s = { ", _file, _line, _type, _name];
const uint8_t *bytes = (const uint8 *) _ptr;
for (size_t i = 0; i < _size; i++) {
[result appendFormat:#"%02x ", bytes[i]];
}
[result appendString:#"}"];
return result;
}
+(NSString *) dump {
NSMutableString *result = [NSMutableString new];
for (NSValue *value in stackVariables) {
__weak StackVariable *var = [value nonretainedObjectValue];
[result appendString:[var description]];
[result appendString:#"\n"];
}
return result;
}
-(void) dealloc {
[stackVariables removeObject:[NSValue valueWithNonretainedObject:self]];
}
#end
Example:
#include "StackVariable.h"
int temp() {
LOCAL_VAR(int, i_wont_show, 0);
return i_wont_show;
}
int main(){
LOCAL_VAR(long, l, 15);
LOCAL_VAR(int, x, 192);
LOCAL_VAR(short, y, 256);
temp();
l += 10;
puts([[StackVariable dump] UTF8String]);
}
Output:
/Users/rross/Documents/TestProj/TestProj/main.m:676 - long l = { 19 00 00 00 00 00 00 00 }
/Users/rross/Documents/TestProj/TestProj/main.m:677 - int x = { c0 00 00 00 }
/Users/rross/Documents/TestProj/TestProj/main.m:678 - short y = { 00 01 }
This requires ARC (and all of it's magic) enabled for any file you want to test this in, or you will manually have to release the __stack_ variables, which won't be pretty.
However, it now gives you a hex dump of the variable (rather than the weird pointer one), and if you really tried hard enough (using __builtin_types_compatible), it could detect whether the result was an object, and print that.
Once again, threads will mess this up, but a simple way to fix that would be to create a NSDictionary of NSArrays, with a NSThread as the key. Makes it a bit slower, but let's be honest, if you're using this over the C++ version, you aren't going for performance.

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;
}