1

I just wonder what's happen when free() called about member of struct tonight. Let see below simple code in c.

typedef struct {
    int c[5];
    int a[10];
    int *b;
}stma;
int main() {
    stma *he = (stma*)malloc(sizeof(stma));
    int *ac = he->a;
    free(ac); //This point is crash.
    return 0;
}

The free make crash. But next code is work well.

typedef struct {
    int c[5];
    int a[10];
    int *b;
}stma;
int main() {
    stma *he = (stma*)malloc(sizeof(stma));
    int *ac = he->c; //This point is changed.
    free(ac); //Work well.
    return 0;
}

Of course, I could think second will work well and first is not correct code too.

What I wonder is what is happen during first execution. free() free 'a' variable, the middle of struct, not address of struct.

he->a is not malloced, dynamically assigned and couldn't be free. In this case, he->c memory address is 00D2Ad50 and he->a is 00D2AD64. The struct variable will be placed in heap by malloc(). he->c have same address of 'he'. And he->c + 4*5 is he->a. he->a is also in heap? Then, what happen on free(he->a)?

Barmar
  • 741,623
  • 53
  • 500
  • 612
Lightstar
  • 183
  • 3
  • 12
  • 5
    It's undefined behavior. The argument to `free()` has to be a pointer returned by `malloc()`. – Barmar Mar 04 '18 at 15:33
  • 1
    That's undefined behavior. – user202729 Mar 04 '18 at 15:33
  • *Why* would you want to do this, *even if* it was well defined? – Jesper Juhl Mar 04 '18 at 15:33
  • What would _you_ expect to happen? – Jabberwocky Mar 04 '18 at 15:34
  • 1
    [don't cast malloc](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar Mar 04 '18 at 15:37
  • It's very fast comments. I intend the first variable of struct will be same with address of struct. @Barmar. About your first comment, then, for example, it mean it have a list of address returned by malloc() and only a address in this list can be free() regardless of memory space? I confused because not malloc() variable in struct is also in heap. – Lightstar Mar 04 '18 at 15:42
  • Yes, pointers to the middle are in the heap. But the memory management functions only know about the actual pointers that they returned. It might have a list of pointers, or it can put housekeeping information before that address. If you give it a different pointer, it won't be able to find the information about how to free it. – Barmar Mar 04 '18 at 15:48

1 Answers1

6

The first of your examples is undefined behavior. You try to free what you didn't get from a memory management function (malloc). And like undefined behavior means - it may crash, work or anything - the behavior is not specified by the standard. So anything may happen.

From §7.22.3.3¶2

Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.1

Your second example is not undefined behavior and is perfectly legal - this is validated by the quote given below. From §6.7.2.1¶15 N1570

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared.A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

As there is no padding involved then the address of the first member is necessarily the one returned by the malloc previously called. By the quote previously mentioned about free this is alright.

Also another point to be made is - not casting the return value of malloc and checking the return value of malloc.

1. One violation of this would when you try to free memory from the middle of the allocated object or something you didn't allocate at all using memory management function.int *a = malloc(sizeof*a * 5) and then calling free(&a[5]) this will be undefined behavior or even this int a[10]; and then calling free(&a[5]) would be one. For dynamic allocation, you can always shrink the allocated space using realloc (freeing the memory that is not needed.)

Community
  • 1
  • 1
user2736738
  • 30,591
  • 5
  • 42
  • 56