11

Is it okay to call free on a pointer which is pointing at the first member of a struct (and the struct is the one involved with malloc)? I know in principle the pointer is pointing at the right thing anyway...

struct s {int x;};
//in main
struct s* test;
test = (struct s*) malloc(sizeof(*test));
int* test2;
test2 = &(test->x);
free(test2); //is this okay??

Also, will the answer change if int x is replaced with a struct?

Update: Why would I want to write code like this?

struct s {int x;};
struct sx1 {struct s test; int y;}; //extending struct s
struct sx2 {struct s test; int z;}; //another
// ** some functions to keep track of the number of references to each variable of type struct s 
int release(struct s* ptr){
  //if the number of references to *ptr is 0 call free on ptr
}
int main(){
    struct sx1* test1;
    struct sx2* test2;
    test1 = (sx1*) malloc(sizeof(*sx1));
    test2 = (sx2*) malloc(sizeof(*sx2));
    //code that changes the number of references to test1 and test2, calling functions defined in **
    release(test1);
    release(test2);
}
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • @user71815 I don't think it's necessary, better compile and check. (& then let us know) – Akash Chandwani Apr 13 '16 at 12:51
  • 3
    Why would you ever write code like this? – Lundin Apr 13 '16 at 12:53
  • It is definitely a strange thing to do. I would never write code like this. Why not just free the original pointer, instead of trying to infer it from the address of a structure member? – Tom Karzes Apr 13 '16 at 12:55
  • @TomKarzes yeah - what happens when someone shoves in another thing at the start? – Martin James Apr 13 '16 at 12:59
  • "Delete this question if it has already been asked." No. Other people may found it useful some years later. – nalzok Apr 13 '16 at 13:11
  • @user71815 In the edit, you seem to free the same pointer that you got from malloc? If so, it isn't the same case as your original question. – Lundin Apr 13 '16 at 13:23
  • @user71815 Ok, I see what you're trying to do, i.e. use a common structure prefix for variable structures. But you should still be able to use the top-level pointer, without referencing the first member to get the address. – Tom Karzes Apr 13 '16 at 13:40
  • @TomKarzes: Code which is supposed to receive one of several structure types that share a common prefix, act upon the passed object, and then free it, might only receive a pointer to the common-prefix structure rather than a pointer to the containing structure. – supercat Apr 13 '16 at 20:17
  • Possible duplicate of [In C, does a pointer to a structure always point to its first member?](http://stackoverflow.com/questions/7312555/in-c-does-a-pointer-to-a-structure-always-point-to-its-first-member) – Ciro Santilli OurBigBook.com May 08 '16 at 09:47

2 Answers2

7

Yes this is ok.

6.7.2.1

  1. 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.

Which means that this is defined:

struct s {int x;};
struct s* test;
test = (struct s*) malloc(sizeof(*test));
int* p = &(test->x);
free(p);
Community
  • 1
  • 1
2501
  • 25,460
  • 4
  • 47
  • 87
  • 6
    Yes, it is OK in the sense that the behavior is defined by the standard and is what was probably intended. But no, it is **not** OK in the sense that it is poor style, as it opens avenues for surprising failures later, in the event that the structure definition is modified. – John Bollinger Apr 13 '16 at 13:12
  • The standard does not guarantee a pointer to one type is identical to a pointer to another type, except for `char *`. Thus, no, it is **not ok**. It just happens to work on (allmost) all recent implementations because they use a unified address space. – too honest for this site Apr 13 '16 at 13:55
  • 1
    Even if those two pointers, `s` and `p`, are of different size, different alignment, and have different representation, they still point to the same address and the same object, and thus using either to free the memory is strictly conforming. – 2501 Apr 13 '16 at 14:17
  • They definitively don't point to the same object. Reason should be clear: the types differ. I'm with you about the address. 7.22.3.3p2 is relevant, too. Considering the conversions to/from `void *` you seem to be right it is allowed, though. I still think it is bad practice and might confuse static code-checkers. Anyway, I withdraw my objection, but your answer should have more info. – too honest for this site Apr 13 '16 at 14:20
  • @Olaf: Taking the address of the first item of a structure is equivalent to converting that structure's address to that type. That operation may on some implementations involve changing the bit representation of the pointer, but if one starts with a non-null void* returned from malloc, conversion of the pointer through any sequence of pointer-to-data types and back to void* is guaranteed to yield the original pointer. – supercat Apr 13 '16 at 20:22
  • @supercat: Which is exactly the reason I changed my mind. But thanks for elaborating a bit more, beginners might appreciate it. I still would reject such code because it (unnecessarily) obfuscates the intention. – too honest for this site Apr 13 '16 at 21:50
  • @Olaf: If one has a number of structures which share a common prefix and needs to have a function which can work with any of them, one may not have a way of finding out the original structure type from the pointer (especially if the common prefix includes pointers to functions that operate on the type in question--in which case the type might not even have existed when the code receiving the pointer was written). – supercat Apr 13 '16 at 22:00
  • @supercat: What would be the difference passing the pointer to the `struct` itself? A function taking an e.g. `int *`, but `free`ing the `struct` **implicitly** is very bad coding style. This is not about finding the "original" structure, but using a different pointer type to free an object. I'd kick anyone showing such code to me where it really hurts. – too honest for this site Apr 13 '16 at 22:13
  • @Olaf: As I said, one wouldn't generally do this with primitives, but rather with nested structures used to achieve the same semantics as object-oriented languages offer with inheritance. In languages like Java, C#, etc. if one defines a type `Animal` and has types `Cat` and `Dog` derive from animal, code which expects a reference to an `Animal` can accept a reference to a `Cat` or `Dog`. To achieve that functionality in C, types `Cat` and `Dog` would both start with an `Animal` as their first field, and code which expects to receive a pointer to some kind of struct derived from `Animal`... – supercat Apr 14 '16 at 06:21
  • ...would accept an `*Animal`. An alternative approach use the fact that compilers used to interpret the "common initial subsequence" rule as applying to typecast pointers just as it applies to unions, but such treatment by compilers has become unfashionable. Passing a pointer to a nested structure is icky but it's the only way hyper-modern compilers allow for code to receive a pointer to a structure whose exact type is unknown but whose initial sequence is known. – supercat Apr 14 '16 at 06:26
  • @supercat Have a look at gcc `-fplan9-extensions`. You might find it very interesting. No need to explicitly use the first member. – too honest for this site Apr 14 '16 at 12:36
  • @Olaf: Such a thing isn't part of the Standard. Passing a pointer to the first member is icky, but it is allowed in strictly-conforming code. Personally what I'd like to see would be directives to specify an aliasing model; one model every compiler should support is "assume anything might alias anything" (so programs including such directive would be specified to work regardless of a compiler's normal aliasing assumptions), and a model which is generally much stricter than the standard *but* would include intrinsics via which programmers could identify places where aliasing is required. – supercat Apr 14 '16 at 15:42
  • @Olaf: The exemption of "character types" from the aliasing rules is a nasty horrible hack which should have been recognized as obsolescent from the get-go, since it can significantly degrade the performance of code which needs to work with large quantities of "real" character-type data, so a directive to waive that exemption could greatly improve the performance of such code. Further, code which uses character pointers or memcpy within a loop will block a compiler from caching global variables through the loop; allowing a programmer to specify, before the loop, that things of type X... – supercat Apr 14 '16 at 15:47
  • ...will be used *exclusively* as type Y within the loop would allow the compiler to ensure that any global variables of type X are synchronized with memory before the loop starts, and again after the loop ends, but would avoid requiring any synchronization within the loop. – supercat Apr 14 '16 at 15:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109190/discussion-between-olaf-and-supercat). – too honest for this site Apr 14 '16 at 19:32
5

As per the C11 standard, chapter §6.7.2.1

[...] There may be unnamed padding within a structure object, but not at its beginning.

which means there cannot be any padding at the beginning of a structure. So, the first member will have the same address as that of the structure variable.

free() needs a pointer which has been previously returned by malloc() or family.

In your case, you're passing the same address that malloc() had returned. So, you're good to go.

nalzok
  • 14,965
  • 21
  • 72
  • 139
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261