Skip to content

Zend: compile time assert on Bucket size - #23079

Open
Sjord wants to merge 2 commits into
php:masterfrom
Sjord:assert-bucket-size
Open

Zend: compile time assert on Bucket size#23079
Sjord wants to merge 2 commits into
php:masterfrom
Sjord:assert-bucket-size

Conversation

@Sjord

@Sjord Sjord commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

In zend_compile.c, flags are stored in the lower bits of the Bucket address. If Bucket is aligned to 8 bytes, the lower three bits are always zero and this gives no problems. If the Bucket is not aligned, this results in non-obvious errors because the memory address and the flags overlap. This is difficult to debug when it happens, so add this assertion to make it more obvious what is wrong.

The flags are ZEND_BIND_REF, ZEND_BIND_IMPLICIT, ZEND_BIND_EXPLICIT.

Related to #19079

@TimWolla TimWolla left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just force the alignment with https://en.cppreference.com/c/language/_Alignas instead?

@TimWolla
TimWolla requested a review from arnaud-lb August 7, 2026 09:53
@marc-mabe

Copy link
Copy Markdown
Contributor

@Sjord please search for ZEND_SET_ALIGNED

Comment thread Zend/zend_types.h Outdated
} Bucket;
}) Bucket;

ZEND_STATIC_ASSERT(sizeof(Bucket) % 8 == 0, "Bucket size not compatible with storing flags in lower three bits");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sjord

Sjord commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

I have added ZEND_SET_ALIGNED. I am not convinced that this is sufficient to safely be able to store the flags, so I left the assertion for now. It seems ZEND_SET_ALIGNED specifies that the memory address is divisable by 8, not that the size is divisable by 8. I will look into this some more later.

@arnaud-lb

Copy link
Copy Markdown
Member

An alternative would be to shift by 1 in

opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | mode;
when sizeof(Bucket) is not a multiple of 8. This way we can keep the size of Bucket as small as possible. Otherwise we are adding 4 bytes to every Bucket for a single use-case.

@Sjord

Sjord commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Otherwise we are adding 4 bytes to every Bucket for a single use-case.

If this is undesirable, I suggest we keep only the static assert on bucket size for now, and look for a better solution if that assert breaks.

In zend_compile.c, flags are stored in the lower bits of the Bucket
address. If Bucket is aligned to 8 bytes, the lower three bits are
always zero and this gives no problems. If the Bucket is not aligned,
this results in non-obvious errors because the memory address and the
flags overlap. This is difficult to debug when it happens, so add this
assertion to make it more obvious what is wrong.

The flags are ZEND_BIND_REF, ZEND_BIND_IMPLICIT, ZEND_BIND_EXPLICIT.

Related to php#19079
@Sjord
Sjord force-pushed the assert-bucket-size branch from 1c5f9f5 to 2f30c08 Compare August 8, 2026 11:02
@arnaud-lb

Copy link
Copy Markdown
Member

Yes, this makes sense.

We should add some context to the assertion so that we can find why it exists. We should either mention zend_compile_static_var_common() in the ZEND_STATIC_ASSERT() message, or move the assertion next to

opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | mode;

I prefer the latter but I let you chose.

Instead of close to Bucket. This way, it is clearer what to look for if
the assertion fails.
@Sjord

Sjord commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

I moved it to zend_compile_static_var_common.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants