1

I'm getting "malloc: * error for object 0xbfffe160: pointer being freed was not allocated" when trying to free memory (in objective-c code) of an object that was allocated inside c function. This C function creates and returns binary data packet that is used as NSData later. Here's my obj-c code part where I'm creating struct variable and passing it by reference to C function:

MyPacket packetRef;
allocAuthentificationCodePacket(&packetRef);

NSData *data = [NSData dataWithBytes:packetRef.bytes length:packetRef.packet->packetSize];
free(&packetRef); // getting error

Everything work fine, except I'm trying to release the memory because the data should be retained by NSData variable. The C functions performs calloc inside itself, so I should somehow to release that memory:

packetRef->bytes = calloc(1, sizeof(*packetRef));

Here's are my structs for storing binary data:

typedef struct {

  uint8_t packetType;
  uint16_t packetBody;

} MyStruct;

and another struct:

typedef union {

  const uint8_t *bytes; 
  MyStruct *packet;

} MyPacket;

How should I free the memory? The error I'm getting is not crash, it just a message in debug console when running unit tests.

UPDATE. Tried to release "bytes" struct member but getting the same error message:

free(&packetRef.bytes);

UPDATE2. Thanks, the suggested way did worked and malloc error message disappeared from console:

free(packetRef.bytes);

However, getting a warning in Xcode "Passing 'const uint8_t *' (aka 'const unsigned char *') to parameter of type 'void *' discards qualifiers". I'm using Apple LLVM 4.1 compiler. C function resides in separate file and only a header is included because Android guys will have to reuse it.

UPDATE3. Thanks to @simonc and @nos who have pointed out the struct member "bytes" has const. The warning has disappeared after removing const. The initial idea of using const was to protect "bytes" from modification.

Centurion
  • 14,106
  • 31
  • 105
  • 197
  • I dont think calloc convenient way to work with memory in ObjC. Please have a look at http://memo.tv/archive/memory_management_with_objective_c_cocoa_iphone and also http://stackoverflow.com/questions/1150650/is-it-ok-to-use-classic-malloc-free-in-objective-c-iphone-apps – Boris Ivanov Nov 06 '12 at 14:00
  • 1
    @Whity: That's an unhelpful link. You cannot use ARC or GC to track data that is not contained in Objective-C objects, and the asker is working with data created in C functions. The second link also contradicts what you are saying. – Dietrich Epp Nov 06 '12 at 14:02
  • To your update: And again wrong. You're trying to free the pointer (which again is a stack variable). You have to free the data pointed to by the pointer (Hint: remove the `&` and see what happens). As a side note you should really delve a little deeper into the fundamentals about pointers and dynamic memory management. – Christian Rau Nov 06 '12 at 14:05
  • Idea was to show other ways to work with memory. – Boris Ivanov Nov 06 '12 at 14:06
  • @Whity: But there aren't necessarily other ways to work with memory here. It's not allocated in an Objective C file so you can't use Objective C methods to allocate it. – Dietrich Epp Nov 06 '12 at 14:12
  • I thought that guy need some more practice with memory management. For example calloc in this case is useless. alloc would be enough. – Boris Ivanov Nov 06 '12 at 15:08
  • @Whity: I feel like a broken record -- you can't call `alloc` from a C file, and you can't use it to allocate things that aren't Objective-C objects. Stop suggesting `alloc`. – Dietrich Epp Nov 07 '12 at 05:28

2 Answers2

3

This is always wrong. (Hint: It's almost always wrong to put & inside of free().)

MyPacket packetRef;
...
free(&packetRef); // getting error

It doesn't matter what MyPacket is -- it has automatic storage duration, i.e., the compiler automatically allocates storage and frees it when the function exits.

Do not free() something unless it came from malloc() (or calloc(), etc.)

Since packetRef.bytes was allocated with calloc(), you can free() that instead.

MyPacket packetRef;
allocAuthentificationCodePacket(&packetRef);
...
free(packetRef.bytes);

Update

If the function that you call, allocAuthentificationCodePacket, contains the code:

packetRef->bytes = calloc(1, sizeof(*packetRef));

And if the bytes field has type const uint8_t *, then something is wrong.

  1. Perhaps your code is wrong, and you are supposed to call some function to free the packet rather than freeing it yourself.

  2. Perhaps the type of the bytes field is wrong, and should be uint8_t * instead of const uint8_t *.

  3. Perhaps allocAuthentificationCodePacket is wrong.

Who knows? It's not wrong enough to crash, but it is a problem.

Footnote

There are no references in C. &x is "address of x", not "reference to x".

Let's consider the following code:

char *x = malloc(10);
free(x);

When people talk about this code, they will say something like "x is allocated on the heap", but that's not technically correct, x is allocated on the stack and contains the address of 10 bytes on the heap. Likewise, the line free(x) does not actually free x, it frees the memory which x points to.

So when someone tells you, "don't forget to free x", you know they actually mean "don't forget to free the memory which the value contained in x points to". People are sloppy with terminology but computers aren't.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • But there's a calloc inside C function that allocates space for packetRef->bytes. So, I don't need to release that? – Centurion Nov 06 '12 at 13:54
  • 1
    @Centurion: Think about it this way: the C function allocates memory, and stores a pointer to that memory in `packetRef.bytes`. The actual variable, `packetRef.bytes`, has automatic storage duration and does not need to be freed. However, it contains a pointer to a region of memory which must be freed. – Dietrich Epp Nov 06 '12 at 13:56
  • Thanks, but then getting a warning. Please see UPDATE2. – Centurion Nov 06 '12 at 14:08
  • @Centurion Your `bytes` member is const. Don't make it const if you intend to free it. – nos Nov 06 '12 at 14:17
2

packetRef is a stack variable in your example with packetRef->bytes heap allocated. You should therefore call free(packetRef.bytes)

Since you allocate the memory inside a function - allocAuthentificationCodePacket - you may want to create another function to free the memory

void freePacket(MyPacket* packet)
{
    free(packet->bytes);
}
simonc
  • 41,632
  • 12
  • 85
  • 103
  • I can't use packet->bytes because compiler gives me error "Member reference type is not pointer. Maybe you meant to use "."?". If I use "free(packet.bytes)" then I get a warning "Passing 'const uint8_t *' (aka 'const unsigned char *') to parameter of type 'void *' discards qualifiers". – Centurion Nov 06 '12 at 13:58
  • 1
    @Centurion: Did you actually copy and paste the entire `freePacket` function? Because it sounds like you didn't. You shouldn't be getting those errors if you copied and pasted the entire function. – Dietrich Epp Nov 06 '12 at 14:00
  • C function resides in separate c file and only a header is imported with function declaration. Because Android guys will try to reuse that. – Centurion Nov 06 '12 at 14:01
  • Excellent point, thanks. The initial idea was to secure "bytes" from modification and the structs are used both for data read and for data write (same packets). – Centurion Nov 06 '12 at 14:16