-
Notifications
You must be signed in to change notification settings - Fork 8k
Throw in FFI::addr() when referencing temporary pointer #9601
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
Throw in FFI::addr() when referencing temporary pointer #9601
Conversation
bwoebi
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's okay. At least I cannot imagine any possible value from taking the address of a rc=1 adress.
|
|
dstogov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fine.
The error message might be done more clear e.g. "Cannot take FFI::addr() from temporary poiner", but I'm not sure.
…rface is rounded down since PHP 8.1.0
|
I just tried upgrading my FFI code to PHP 8.3 and it ... blew up, thanks to this. More precisely, my code looks like It can be worked around by assigning $cdata->struct_member to a temp var by reference, but that's even uglier? What this PR probably wanted to solve is catching when the owned value is destroyed. I'm not sure how to do that, but I think we may need to revert the arbitrarily restrictive behaviour of this PR? (The irony that I initially approved this is not lost on me.) |
|
@bwoebi could you please provide the complete reproduction case. |
|
Sure @dstogov, simplified reproducer: Note the difference, in the latter case the |
|
@bwoebi I wonder, why do you need these This code works in PHP-7.4 and master |
|
@dstogov I ended up with a RC=1 reference from a VAR, this was just simplified to illustrate the problem, let's say: Now, certainly |
|
But I generally need the addr trick to assign the contents directly to a variable, if it's a struct or array member, then the dim&prop write handlers handle it, but obviously |
|
I see. This probably may be fixed by the following patch diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index f91092ab03b..daca017f69f 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -4290,7 +4290,8 @@ ZEND_METHOD(FFI, addr) /* {{{ */
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
type = ZEND_FFI_TYPE(cdata->type);
- if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER) {
+ if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER
+ && cdata->ptr_holder) {
zend_throw_error(zend_ffi_exception_ce, "FFI::addr() cannot create a reference to a temporary pointer");
RETURN_THROWS();
}@iluuu1994 what do you think? |
|
@dstogov Your patch doesn't fix Bobs example for me. TBH I'm not very familiar with FFI. I remember a use-after-free for a Symfony test that used FFI: $struct = $ffi->new('Foo');
$structPtrPtr = \FFI::addr(\FFI::addr($struct));
var_dump($structPtrPtr);I don't know how to fix Bobs test, so I'm ok with just reverting this change. FFI is inherently unsafe, so users are responsible for making sure the data survives. |
Are you sure? I just verified this again and it works. <?php
$f = FFI::cdef("typedef struct { char *bar; } other;");
class Container {
public $data;
function __construct($f) { $this->data = $f->new("other"); }
function &getBar() { return $this->data->bar; } // return by ref to get CData instead of null
}
$container = new Container($f);
$data = $f->new("char[2]");
$data[0] = "1";
FFI::addr($container->getBar())[0] = $f->cast("char*", $data); // directly write it
var_dump($container);
My patch doesn't affect |
|
I see, this doesn't fix the other case: |
🤔 Yes, it fails for the code you just posted below for me.
I didn't even try this one. |
|
@bwoebi will the patch posted above help you? Or it's not enough anyway. |
|
@dstogov Yes, this helps me. The other case just happened as part of the reproducer. |
|
Well, that patch still doesn't work for me ^^ <?php
$f = FFI::cdef("typedef struct { char *bar; } other;");
class Container {
public $data;
function __construct($f) { $this->data = $f->new("other"); }
function &getBar() { return $this->data->bar; } // return by ref to get CData instead of null
}
$container = new Container($f);
$data = $f->new("char[2]");
$data[0] = "1";
FFI::addr($container->getBar())[0] = $f->cast("char*", $data); // directly write it
var_dump($container);
?>I tried on PHP-8.3 and master. But if it works for you then great 🤷♂️ 😄 |
|
No, I meant, it's enough if this fixes the latter case. I can test later. |
* PHP-8.3: Fixed regression introduced by #9601
|
@bwoebi the problem should be fixed now |
Alex Dowad (1):
Return value of mb_get_info can be NULL
Ben Ramsey (1):
Merge changes to CertificateGenerator.inc from PHP-8.2
Bob Weinand (2):
Add NEWS entry for GH-12768
USE_ZEND_ALLOC=1 in tests with zend_test.observe_opline_in_zendmm=1
Derick Rethans (2):
Import timelib 2022.10
Update NEWS
Dmitry Stogov (7):
Fixed GH-12747: Function JIT returns invalid error message for coalesce operator on invalid offset
Fixed GH-12748: Function JIT emits "could not convert to int" warning at the same time as invalid offset Error
Fixed regression introduced by php/php-src#9601
Fixed GH-12748: Function JIT emits "could not convert to int" warning at the same time as invalid offset Error
Fixed GH-12812: Integer string in variable used as offset produces wrong undefined array key warning (#12817)
Fixed GH-8251: Narrowing occurred during type inference of ZEND_FETCH_DIM_W
Fixed type inference
Florian Engelhardt (1):
Fix invalid opline in OOM handlers within ZEND_FUNC_GET_ARGS and ZEND_BIND_STATIC (#12768)
Gina Peter Banyard (5):
ext/standard: Fix GH-9316
Mention correct bug number
jit: fixed "Uninitialized string offset" warning being emitted at the same time as invalid offset Error
jit: fixed JIT "Attempt to assign property of non-object" warning emitted at the same time as Error is being thrown
Align error messages between normal VM and JIT for RW when using object as array (#12799)
Ilija Tovilo (16):
Fix undeclared variable in stat tests
Disable -fsanitize=function on Clang 17
Fix astat imperciseness excemption in test
[skip ci] Further increase allowable atime deviation
Automatically mark tests as flaky
Fix file test race condition
Retry tests on deadlock
[skip ci] Fix more test tmp file conflicts
Temporarily disable failing zlib tests on travis (#10738)
Fix use-after-free of name in var-var with malicious error handler
Fix in-place modification of filename in php_message_handler_for_zend
Reduce parallelism on frequently crashing jobs
[skip ci] Skip resource intensive tidy test on GA
Fix travis_wait
Fix leak of call->extra_named_params on internal __call
Fix compilation of ftp without openssl
Jakub Zelenka (5):
PHP 8.3 is now 8.3.1-dev
Skip slow tests on Travis
Fix bug #79945: Stream wrappers in imagecreatefrompng causes segfault
Fix stream fclose_stdiocast_flush_in_progress type
Fix #50713: openssl_pkcs7_verify() may ignore untrusted CAs
Levi Morrison (1):
test: allow other zend extensions to not fail the test
Mikhail Galanin (1):
Avoid using uninitialised struct
Muhammad Moinur Rahman (2):
Add host_cpu type for FreeBSD
Add host_cpu type for FreeBSD
Máté Kocsis (1):
Fix the default value of $fetchMode in PDO::pgsqlGetNotify()
Niels Dossche (15):
Fix GH-12635: Test bug69398.phpt fails with ICU 74.1
Fix GH-12621: browscap segmentation fault when configured in the vhost
Fix GH-12655: proc_open() does not take into account references in the descriptor array
Fix GH-12675: MEMORY_LEAK in phpdbg_prompt.c
Use __DIR__-relative path in tests
Fix GH-12702: libxml2 2.12.0 issue building from src
Fix GH-12616: DOM: Removing XMLNS namespace node results in invalid default: prefix
Fix GH-12791: Possible dereference of NULL in MySQLnd debug code
Test fixes for libxml2 2.12.0
Add missing NULL pointer checks related to the previous call frame
Add missing NULL checks for spl autoload table
Fix GH-12838: [SOAP] Temporary WSDL cache files not being deleted
Fix GH-12826: Weird pointers issue in nested loops
Fix libxml2 2.12 build due to API breaks
Fix GH-9348: FTP & SSL session reuse
Patrick Allaert (1):
PHP-8.1 is now for PHP 8.1.28-dev
Patrick Prasse (1):
Fix bug GH-12705: Segmentation fault in fpm_status_export_to_zval
Pierrick Charron (1):
Prepare PHP 8.3.1
Remi Collet (1):
zip: use index to avoid search by name
ddv (1):
Fix phpGH-12763: PGSQL pg_untrace(): Argument #1 ($connection) must be of type resource or null, PgSql\Connection given.
We're only disallowing pointers, as they always rely not only on the data but also the
CData.ptr_holderto be there. Other unowned structures should be allowed, like structs, even ifrefcount == 1. Targetingmasteras this is an improvement rather than a bugfix.