5 ms·
C11, 6.5p7: An object shall have its stored value accessed only by an lvalue expression that has one of the following types: — a type compatible with the effec
by sharpneli 11y ago
C11, 6.5p7: An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type
---------------------
If we interprete 6.5p6 like the submitter did then the whole p7 becomes meaningless for any mallocs. In that case everything always aliases everything ever when it's trough a malloced pointer. Which I hardly imagine is the point of the former paragraph. If so they have fundamentally changed the whole function of malloc. Which makes it odd as in C99 (The p6 wording was introduced there. It was not there in C89) they explicitly allowed unions to alias, just due to this issue. Would have been unnecessary if malloced things always alias.
The wording is not clear however. It would be nice to see the standards committee to publish a comment about this. This is also not the first thing in the spec that is unclear.
- pascal_cuoq 11y ago6.5:6 is certainly not saying that malloced memory always aliases with “everything”. Quite the contrary, it says that malloced memory cannot be used for type-punning. The following works and is idiomatic: uint32_t u; float f = …; memcpy(&u, &f, sizeof u); /* use u as a uint32_t in computations */ You cannot do the same thing with malloced memory: if u had been malloced memory instead of a variable, it would have been illegal to access that memory with an lvalue of type uint32_t in subsequent computations. 6.5:6 is certainly no license to use malloc'ed memory any which way.
- sharpneli 11y agoThere is a non-normative note in 6.5:6 "Allocated objects have no declared type." Sure that is not strictly part of the standard. But helps in interpreting it. I'd say it quite clearly refers to malloced objects. Malloced object is an object with no declared type. If you look at the bug report it uses malloced object as the example. And accesses it using two pointers of different types.
- nkurz 11y agoI think you are misinterpreting Pascal's example. He's saying that because 'u' is a variable with a declared type (uint32_t), it can still be used as that type even after it is written to with another type. He then claims that were it an "allocated object" with no declared type, the effective type would change to the type of the most recent write (float), and thus it could no longer be used as the original type (uint32_t). I'm not sure he's right, though. The quoted part of the standard says "stored into an object having no declared type through an lvalue having having a type that is not a character type". I would think that "through an lvalue" is referring only to the case given in the bug report, where the store is expressed as "*ptr = val", and not to the case where ptr is used as an argument to memcpy(). Am I wrong?
- sharpneli 11y agoYou're right. I did misinterpret it. However I also think you're right. Memcpy is effectively the same as through a character type in the end.
- asgfoi 11y agoUh, thanks for pointing that out. I'm familiar with allocated memory and effective type, but I never considered it from this perspective. This could be quite a nasty surprise when the only change in the code is storage duration.
- caf 11y agoWhat you're missing is that storing to an object doesn't "access it's stored value". Once you've stored to the malloced memory through an int-typed lvalue, it's effective type becomes int, and you can't access it (ie. read it) through a double-typed lvalue. But you can then write to it through a double-typed lvalue, because that doesn't access it's stored value - it overwrites it, and changes its effective type to double.
- sharpneli 11y agoThe specification defines the word "access" as: access 〈execution-time action〉 to read or modify the value of an object I would interpret that so that writing does modify the value.