sprintf function call in .c file in iOS app crashing.

Discussion in 'iOS Programming' started by mycompuser, Jun 26, 2013.

  1. mycompuser macrumors member

    Joined:
    May 8, 2012
    #1
    Hi All,

    Mine is an iOS application (xcode 4.5.2 and iOS 6.1) I make use of a 3rd party library which is written in .C file.

    There in one of the methods named lookup_txt, the DNS error "kDNSServiceErr_Timeout = -65568" which is an enum is formatted into a string using sprintf.

    Found that this formatting code is crashing occasionally. Not sure why.

    Code:
            
    	char *response = NULL;
            signed int timeout_error_code = kDNSServiceErr_Timeout;
            response = (char*)malloc(6);
            sprintf(response, "%d", timeout_error_code);  <----This line crashes occasionally.
    Below is the extract from apple's crash dump.

    Code:
    Thread 7 Crashed:
    0   libsystem_kernel.dylib        	0x31912350 __pthread_kill + 8
    1   libsystem_c.dylib             	0x30ebe11e pthread_kill + 54
    2   libsystem_c.dylib             	0x30efa9f2 __abort + 90
    3   libsystem_c.dylib             	0x30ec00f6 __chk_fail + 26
    4   libsystem_c.dylib             	0x30ec019e __sprintf_chk + 54
    5   MyApp                    	        0x0028724a lookup_txt (lookup_sd.c:206)
    Found that sprintf is a macro for __sprintf_chk which appears in the callstack above and also found in _stdio.h.

    Code:
    #define sprintf(str, ...) \
      __builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
    
    Can somebody help me out of the possible reason why this sprintf could be crashing?.

    Thanks in advance for the help.
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    What happens if timeout_error_code is too big (when \0 terminated) to fit in the space you have allocated for the string? I suspect your app will crash...
     
  3. mycompuser thread starter macrumors member

    Joined:
    May 8, 2012
    #3
    Hi,

    I made the below chagnes to the existing code and found that there was no crash.
    Found that variable "response" did contain the integer number as is without truncation. Even when I assigned a greater value (replace -65568 with -6556800), the integer was getting formatted correctly without any crash.
    Code:
            response = (char*)malloc(2);//reduce size from 6 to 2.
            response[2] = '\0';//tried without this line of code as well but no crash.
    
    As i said, this sprintf seem to be crashing occasionally.

    Another thing is that the string objected that is returned by this method needs to be on the heap (to ensure that object doesnot go out of scope). Once the returned data is consumed, the caller will free the object.

    Any reason why sprintf would crash?

    Alternatively, can you guys provide an equivalent "C" code snippet which creates an object on heap, formats the string and stores it on the heap and returns the pointer to the heap?

    Thanks & Regards.
     
  4. MeFromHere, Jun 26, 2013
    Last edited: Jun 26, 2013

    MeFromHere macrumors 6502

    Joined:
    Oct 11, 2012
    #4
    sprintf() fails when the output buffer you provide is too small for the text that sprintf() wants to put in the buffer. It can also fail if the format string doesn't match the arguments that follow it.

    If your call to sprintf() crashes the app, check that your arguments match the format string, and check that your buffer is large enough.

    But there's really NO good reason to use sprint() for anything. You should use snprintf() instead. You give it a pointer to your buffer and the size of your buffer. The function either writes nothing in the buffer, or writes a string that is guaranteed to be terminated with '\0'. If the whole string won't fit, it writes as much as it can, and always puts the '\0' at the end.

    The value returned by the function tells you the length of the result string, not including the final '\0'. Except if it truncated the output, it tells you how long the string WOULD HAVE BEEN if the buffer was big enough.

    Examples:
    Code:
    char s[5];
     
    snprintf(s, sizeof(s), "1");     // s is "1", return value is 1
    snprintf(s, sizeof(s), "1234");  // s is "1234", return value is 4
    snprintf(s, sizeof(s), "12345"); // s is "1234", return value is 5
    snprintf(s, 1, "12345");         // s is "", return value is 5
    snprintf(s, 0, "12345");         // s is not altered, return value is 5
    snprintf(NULL, 0, "12345");      // NULL pointer is ok, return value is 5
    
    Note that the behavior of the last two examples is what the C99 standard demands, but some implementations get it wrong. Test these cases in your environment before you trust it.

    In a working implementation, you can always use the last example to find out how big your buffer needs to be, then malloc a buffer (get 1 byte more than the snprintf() return value), then call snprintf() with a pointer to your new buffer. This works even with a complex format string that uses many arguments.
     
  5. mycompuser thread starter macrumors member

    Joined:
    May 8, 2012
    #5
    Thanks for the reply.

    Will try it with in the actual environment and see if the crash issue still exists.


    Thanks & Regards.
     

Share This Page