zend_portability: Add ZEND_CONTAINER_OF()#21903
Conversation
Changes made with Coccinelle:
@@
type T_container;
identifier member;
expression e;
@@
- (T_container *)(((char *)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
@@
type T_container;
identifier member;
expression e;
typedef uintptr_t;
@@
- (T_container *)(((uintptr_t)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
@@
type T_container;
identifier member;
expression e;
@@
- (const T_container *)(((char *)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
@@
type T_container;
identifier member;
expression e;
typedef uintptr_t;
@@
- (const T_container *)(((uintptr_t)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
| #define ZEND_ELEMENT_COUNT(m) | ||
| #endif | ||
|
|
||
| #define ZEND_CONTAINER_OF(ptr, Type, member) ((Type*)((char*)(1 ? (ptr) : &((Type*)0)->member) - offsetof(Type, member))) |
There was a problem hiding this comment.
Nit: This will discard const from ptr. With _Generic it would be possible to retain it. get_bcmath_number_from_obj() looks like the only relevant case, but also looks somewhat questionable. obj should not be const if we return a mutable pointer derived from it.
There was a problem hiding this comment.
get_bcmath_number_from_obj() simply seems to be my mistake.
There was a problem hiding this comment.
get_bcmath_number_from_obj()simply seems to be my mistake.
Yes, that's a pre-existing bug.
With
_Genericit would be possible to retain it.
Good idea, will look into that.
|
I think this relies on UB (pointer arithmetic on NULL) |
That branch is never evaluated; it's also the “accepted” solution to define |
This doesn't matter for UB.
The Linux kernel is compiled with various flags that makes various UB defined, so I'm not so sure this is a valid comparison. |
|
I believe it's not UB unless executed, but we can probably achieve something similar with static assets? |
The issue is that compilers can assume UB never happens, and then start removing stuff or doing whatever they want if that code is present (see famous blog article about UB: https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633) |
|
So, I have a different understanding.
Yes, but this branch is already provably dead. UB allows the compiler to make some assumptions. For example:
In other words, my understanding is: UB in dead branches has an effect on the result of the program, i.e. the compiler can assume the program is correct, and if the branch were reachable the program would not be correct, so the branch is unreachable. But that doesn't mean UB in dead branches makes the behavior of your program undefined if the branches are actually never reached. That's my understanding, though to be honest, the C spec is not nearly explicit enough about this... |
|
Unsure, but now I wonder if we even need this. |
It likely would, but my understanding is that it would be equally UB. You can't just cast between pointers of different types. (and this already affected the original implementation, you may go to My suggestion would be to just go with the established way of writing a |
|
Okay then |
Changes made with Coccinelle: