ogs
ogs

Reputation: 1239

free() complains about invalid pointer

I'm trying to build a string piece by piece in my program by concatenating some values in order to obtain something like :

|0x0F64:0x0063:0x1A|0x7CC4:0x0073:0x1A|0x0A51:0xA29A:0x9C|0xD49D:0x0058:0x10|

I would like to use a dynamic variable because the NB_ELEMENT might be improved.

#include <stdio.h>
#include <stdlib.h>

#define NB_ELEMENT 4
typedef struct
{
   unsigned short  u16Val1;
   unsigned short  u16Val2;
   unsigned char   u8Val3;
}stElement;

stElement element[NB_ELEMENT] = {{ 0 }};

int main()
{
    element[0].u16Val1 = 3940;
    element[0].u16Val2 = 99;
    element[0].u8Val3 = 26; 

    element[1].u16Val1 = 31940;
    element[1].u16Val2 = 115;
    element[2].u8Val3 = 26;           

    element[2].u16Val1 = 2641;
    element[2].u16Val2 = 41620;
    element[2].u8Val3 = 156; 

    element[3].u16Val1 = 52429;
    element[3].u16Val2 = 88;
    element[3].u8Val3 = 16;

    char *str = malloc(NB_ELEMENT * sizeof element);

    snprintf(str, sizeof element, "|0x%04x:0x%04x:0x%x\n",element[0].u16Val1,
                                                      element[0].u16Val2,
                                                      element[0].u8Val3);

    str += sprintf(str, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
                                            element[1].u16Val2,
                                            element[1].u8Val3);

    fprintf(stdout, "%s\n", str);
    free(str);
    return 0;
}

The code above returns :

*** Error in `./TEST': free(): invalid pointer: 0x0000000000cac023 ***

However, I managed to print |0x0f64:0x0063:0x1a but avec adding str += sprintf.., the error occurs.

Upvotes: 0

Views: 271

Answers (4)

P.P
P.P

Reputation: 121407

Because you are not passing free() the same pointer returned by malloc(). So, undefined behaviour.

With this statement:

 str += sprintf(str, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
                                             element[1].u16Val2,
                                             element[1].u8Val3);

You have changedstr.

From free():

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc(), or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

(emphasis mine).

Upvotes: 4

slim
slim

Reputation: 41263

 man 3 free

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs.

Since your str is a pointer obtained by adding a number to a pointer obtained from malloc(), it doesn't meet this requirement, and undefined behaviour results.

Be grateful it's a hard failure on your system -- on some systems it would have resulted in a memory leak or in weird memory corruption that would only reveal itself when your program started producing garbage.

Your code has other problems. You should probably review your C book's chapter on pointers and strings.

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074979

The problem is here:

str += sprintf(str, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
                                        element[1].u16Val2,
                                        element[1].u8Val3);

That modifies the pointer in str. So when you hand it to free later, it's not the same pointer that malloc gave you, which makes free's job rather difficult.

Solution: Don't modify the pointer. If you want to keep track of where you are in the buffer by adding the number of characters written to the pointer, use a different pointer for that:

char *str = malloc(NB_ELEMENT * sizeof element);
// ...
char * p = str;
// ...
p += sprintf(p, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
                                        element[1].u16Val2,
                                        element[1].u8Val3);
// ...
free(str);

Upvotes: 7

Jack
Jack

Reputation: 133609

You can't concatenate strings in this way in C.

str += something

just changes the address stored in str to something else, which then makes it an invalid pointer to be freed (since it's a value not obtained from malloc/calloc anymore).

You should use strncat if you want to concatenate string, by initially allocate a buffer which is large enough to fit the whole contents.

Upvotes: 2

Related Questions