Q:

Why does __stack_chk_fail happen when running from ipa, but not when running on device in Xcode?

Here's the specific stack trace, and see code below...
Thread 8 Crashed:
0   libsystem_kernel.dylib          0x00000001969bb270 __pthread_kill + 8
1   libsystem_pthread.dylib         0x0000000196a5916c pthread_kill + 108
2   libsystem_c.dylib               0x0000000196932b94 __abort + 112
3   libsystem_c.dylib               0x00000001969333f8 __stack_chk_fail + 208

This only occurs after I export the ipa for enterprise deployment, and try to run it on my device.  The same device, that it runs just fine on when debugging within Xcode.  Any thoughts?  What am I doing that's corrupting the stack?
// MACROS USED
#define BUFFER_SIZE_MAX 20480 // 20KB max payload for URL requests
#define BUFFER_SIZE_READ 4096 // 4KB
#define BUFFER_SIZE 4100 // 4KB w padding
#define NUL '\0'
... relavent code ...

char readBuffer[BUFFER_SIZE] = {};
long bytesRead = 0;
char *buff = NULL;
while (((bytesRead = read(sck, readBuffer, BUFFER_SIZE_READ)) > 0)) {
    if (!stop || *stop) {  // volatile bool* passed to method
        break;
    }
    if (bytesRead > 0) {
        readBuffer[bytesRead] = NUL; // add NUL terminator
    }
    long len = bytesRead;
    if (buff) {
        len += strlen(buff);
        buff = (char *)realloc(buff, len * sizeof(char));
    } else {
        buff = (char *)malloc(len * sizeof(char));
        buff[0] = NUL;
    }
    strcat(buff, readBuffer);
    if (strlen(buff) >= BUFFER_SIZE_MAX) {
        // payload shouldn't be bigger than 20K in most use-cases
        // adjust BUFFER_SIZE_MAX as needed
        break;

    }
}
if (buff) {
    response = strdup(buff);
    free(buff);
}
LOGV("\n\n<<<<<============\nHTTP payload:\n<<<<<============>>>>>>");
LOGV("\n\nREQUEST:\n----------->\n%s", request);
LOGV("\n\nRESPONSE:\n----------->\n%s\n\n", response);
close(sck);
return response; /// must call free

A:

a few issues here any of which could cause your issue:
1) readBuffer is 4100 bytes in size.
but when you do "readBuffer[bytesRead] = NUL;" you could be writing to readBuffer[4100] ie past the end of the buffer.
char readBuffer[BUFFER_SIZE] should be char readBuffer[BUFFER_SIZE+1].
2) buff = (char *)malloc(len * sizeof(char));
you alloc the amount of data that you received, but don't allow for null terminator which would be added when calling strcat(). you should alloc (len + 1).
3) buff = (char *)realloc(buff, len * sizeof(char));
again you are allocing without regard for null terminator.
should be buff = (char *)realloc(buff, (len+1) * sizeof(char));
When you are writing to memory you don't own, then behavior becomes undetermined. So somethings it might be an issue other times you might get away with it. It depends what exists in the memory that you are overwriting. SO you are always doing a bad thing here, but only sometimes seeing the consequences of it.

