Skip to content

gh-148510: restore func_version check in _LOAD_ATTR_PROPERTY_FRAME#148528

Open
NekoAsakura wants to merge 4 commits intopython:mainfrom
NekoAsakura:gh-148510/load-attr-property-frame
Open

gh-148510: restore func_version check in _LOAD_ATTR_PROPERTY_FRAME#148528
NekoAsakura wants to merge 4 commits intopython:mainfrom
NekoAsakura:gh-148510/load-attr-property-frame

Conversation

@NekoAsakura
Copy link
Copy Markdown
Contributor

@NekoAsakura NekoAsakura commented Apr 13, 2026

Do not merge.
Prerequisite: #148524
Mean +- std: [main] 12.8 ms +- 0.2 ms -> [branch] 12.3 ms +- 0.1 ms

Copy link
Copy Markdown
Member

@Fidget-Spinner Fidget-Spinner left a comment

Choose a reason for hiding this comment

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

Just one thing that should be addressed. Thanks!

assert((oparg & 1) == 0);
assert(Py_IS_TYPE(fget, &PyFunction_Type));
PyFunctionObject *f = (PyFunctionObject *)fget;
EXIT_IF(f->func_version != func_version);
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.

Note: this does not need an FT_ATOMIC_ load (check the rest of bytecodes.c). On FT, I suspect it's because function verison resets are stop-the-world (see Objects/funcobject.c)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Would you like me to document this in 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.

No it's fine. The rest of bytecodes.c works like that and has no comments too.

Comment on lines +987 to +988
PyFunctionObject *func = (PyFunctionObject *)fget;
if (func->func_version != func_version) {
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.

This needs a stronger invariant. There might be a case where fget is deallocated or deleted, and we are thus accessing a NULL pointer!

The reason why this is safe currently in the bytecodes interpreter but not here is that we have _GUARD_TYPE_VERSION in the bytecodes interpreter that guarantees that our cached function is alive.
While here, the _GUARD_TYPE_VERSION only sets the type version, and doesn't stop optimization if we detect something wrong.

To make this safe, you need to get the probable type in _GUARD_TYPE_VERSION, and also set things to contradiction+done if they don't already match the type_version in there. Since we record LOAD_ATTR_PROPERTY's type, this will then be safe to access if that passes.

@NekoAsakura
Copy link
Copy Markdown
Contributor Author

Seems like probable_type gets dereferenced without a NULL check here.

if (probable_type->tp_version_tag == type_version && sym_set_type_version(owner, type_version)) {
// Promote the probable type version to a known one.
if ((probable_type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) == 0) {

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.

3 participants