Skip to content

Fix life time of FFI CData and FFI CType with FFI\CDef #12915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: PHP-8.2
Choose a base branch
from

Conversation

nielsdos
Copy link
Member

@nielsdos nielsdos commented Dec 9, 2023

For GH-8556 the return type is stored in the CDef and doesn't outlive the CData. In that case it happened because temporaries were used, but it's also possible to get this with compiled variables when the variable holding the CDef leaves the scope.

For GH-12910 the exception trace is built after the compiled variables are destroyed, so that means the FFI CDef instance got destroyed but the CData argument still remained. When the trace building code tries to get the class string for the exception, the CData instance tries to access the already-freed CDef.

Fix all of this by storing a reference to the CDef object inside of CData and CType.

Closes GH-8556.
Closes GH-12910.

This is an alternative for #10574 that fixes the issue more efficiently and more generally.

@nielsdos nielsdos force-pushed the ffi-lifetime branch 2 times, most recently from 0a24b9c to 3ac36a2 Compare December 9, 2023 20:30
For phpGH-8556 the return type is stored in the CDef and doesn't outlive
the CData. In that case it happened because temporaries were used, but
it's also possible to get this with compiled variables when the variable
holding the CDef leaves the scope.

For phpGH-12910 the exception trace is built after the compiled variables
are destroyed, so that means the FFI CDef instance got destroyed but the
CData argument still remained. When the trace building code tries to get
the class string for the exception, the CData instance tries to access
the already-freed CDef.

Fix all of this by storing a reference to the CDef object inside of
CData and CType.

Closes phpGH-8556.
Closes phpGH-12910.
@nielsdos nielsdos marked this pull request as ready for review December 9, 2023 21:47
@nielsdos nielsdos requested a review from dstogov December 9, 2023 21:47
Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

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

I don't like this new FFI\CDef dependency especially for CData.
This looks like an attempt to manage, unmanaged C data.
And FFI anyway provides another hundred ways to short into the lag.

I'll need to think about this. I'll return to the PR a bit later.

Any arguments are welcome.

@nielsdos
Copy link
Member Author

Thanks for taking a look.

I agree that FFI provides many ways to crash PHP, but those usually involve pointers or library calls. And I agree we can't do anything about that as it's the users' responsibility. That is indeed unmanaged data.

The cases that this PR tries to solve are different: they are for problems with types being freed.
These types look and behave like PHP objects, so it causing a use-after-free is surprising because it seems like managed data. This is especially confusing when the CDef is used as a temporary: it is difficult to explain to the user why the behaviour is different than from using a CV. Even if we don't end up fixing this, we should at least in my opinion fix #12910 because otherwise debugging becomes more difficult for users (crash instead of exception).

I think we should avoid use-after-frees for types: users will have a hard time figuring out what goes wrong because use-after-frees often lead to random crashes later.

I think this approach is simpler and more efficient than remembering the types like I did in my previous attempt.

@dstogov
Copy link
Member

dstogov commented Dec 11, 2023

I think this approach is simpler and more efficient than remembering the types like I did in my previous attempt.

I agree, that we should try to solve this, especially for types and may be your approach is good enough, but I remember, FFI already had some mechanism for dallying type destruction. I should find time, to look into the problem more careful.

The main thing that I didn't like from the first look, was the FFI\CDef dependency for CData, but this also needs a more careful review.

@dstogov
Copy link
Member

dstogov commented Dec 12, 2023

I didn't completely get the reason for CData->ffi and all the related code.
Do you maintain it just to pass the proper ffi value to zend_ffi_ctype_new_ex()?

I think this should be fixed in a different way.
ZEND_METHOD(FFI, cdef) should remember CDef related types at first place and keep them until the end of request.

In #10574 you tried to do this delaying store, by resetting ZEND_FFI_ATTR_STORED.
I think, we don't need this delay and should remember types immediately.
What do you think?
Can you try this?

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.

2 participants