[php-src] Issue #8874: Segfaults, inconsistency and confusion when adding (+) `int` to typecasted FFI\CData

From: Date: Sun, 26 Jun 2022 09:07:14 +0000
Subject: [php-src] Issue #8874: Segfaults, inconsistency and confusion when adding (+) `int` to typecasted FFI\CData
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-241811@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/8874 Author: exikyut ### Description The following code: ```php <?php $ffi = FFI::cdef(' typedef long unsigned int size_t; void *malloc(size_t size); '); $ptr = $ffi->cast('uint8_t *', $ffi->malloc(8)); print "A: "; var_dump($ptr); print "B: "; var_dump($ptr + 1); print "C: "; var_dump($ptr); print "D: "; var_dump($ptr + 1); ``` Resulted in this output: ``` A: object(FFI\CData:uint8_t*)#4 (1) { [0]=> int(0) } B: object(FFI\CData:uint8_t*)#5 (1) { [0]=> int(0) } C: Segmentation fault ``` But I expected this output instead: *Not sure what would be canonically correct* I get the following backtrace: ``` #0 0x00007ffff43a7915 in ?? () from /usr/lib/php/20210902/ffi.so #1 0x00005555558be86d in zend_std_get_properties_for (obj=<optimized out>, purpose=<optimized out>) at ./Zend/zend_object_handlers.c:1880 #2 0x00005555557a77e1 in php_var_dump (struc=0x7ffff5413530, level=1) at ./ext/standard/var.c:163 #3 0x00005555557a7ce1 in zif_var_dump (execute_data=<optimized out>, return_value=<optimized out>) at ./ext/standard/var.c:228 #4 0x000055555589797b in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER () at ./Zend/zend_vm_execute.h:1235 #5 execute_ex (ex=0x7ffff5455e40) at ./Zend/zend_vm_execute.h:55752 #6 0x000055555589eced in zend_execute (op_array=0x7ffff548c000, return_value=0x0) at ./Zend/zend_vm_execute.h:60123 #7 0x00005555558311cd in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=3) at ./Zend/zend.c:1790 #8 0x00005555557ccc71 in php_execute_script (primary_file=primary_file@entry=0x7fffffffd760) at ./main/main.c:2538 #9 0x0000555555915673 in do_cli (argc=2, argv=0x555555ac5390) at ./sapi/cli/php_cli.c:969 #10 0x0000555555677f11 in main (argc=2, argv=0x555555ac5390) at ./sapi/cli/php_cli.c:1371 ``` Here's line 1880: https://github.com/php/php-src/blob/PHP-8.1.7/Zend/zend_object_handlers.c#L1880 ### Additionally, *This* code (which swaps var_dump() for var_export(), to take the alternate path through zend_std_get_properties_for()): ```php <?php $ffi = FFI::cdef(' typedef long unsigned int size_t; void *malloc(size_t size); '); $ptr = $ffi->cast('uint8_t *', $ffi->malloc(8)); print "A: "; var_export($ptr); print "\nB: "; var_export($ptr + 1); print "\nC: "; var_export($ptr); print "\nD: "; var_export($ptr + 1); ``` Results in this output: ``` A: FFI\CData::__set_state(array( )) B: FFI\CData::__set_state(array( )) C: FFI\CData::__set_state(array( )) D: PHP Fatal error: Uncaught TypeError: Unsupported operand types: FFI\CData + int ``` But I expected this output instead: *Not sure what would be canonically correct* ### hOwEvEr, ***ThIs*** code: ```php <?php $ffi = FFI::cdef(' typedef long unsigned int size_t; void *malloc(size_t size); '); $cast = $ffi->cast('uint8_t *', $ffi->malloc(27)); // Fill memory with "A..Z" for presentational purposes for ($i = 0; $i < 26; $i++) { $cast[$i] = $i + 65; // 'A' } var_dump(FFI::string($cast, 16)); var_dump(FFI::string($cast + 5, 16)); var_dump(FFI::string($cast + 5, 16)); ``` Produces ***this*** output!! ``` string(16) "ABCDEFGHIJKLMNOP" string(16) "FGHIJKLMNOPQRSTU" PHP Fatal error: Uncaught TypeError: Unsupported operand types: FFI\CData + int ``` --- Commentary: I'm currently using the FFI to mmap() some data into memory (for both read and write). Reading and writing integer values (typecasted to uint16_t/uint32_t) is working perfectly fine (thanks for plumbing everything out so this is as simple as assigning to a PHP array :D), but now I needed to read and write sequences of characters (binary data I want written to specific offsets). Naturally that's done in C by just assigning to ptr + offset (where ptr might be uint8_t * and offset is int), so I wondered if the same worked here. It... \*does\*, I think...? Except it crashes. This is why I said I don't know what the canonically-correct outcome here is: this is currently Schrodinger's architecture, where I'm equally observing "yes that's the right way to do it" and \**crash*\* and I don't know where to put the consensus :) I was reading the values I wanted to mmap() using (PHP-side) fread() so I'll either just stick with that or play with FFI::memcpy() for now. Thanks again for FFI, it's really awesome. ### PHP Version PHP 8.1.7 from sury.org ### Operating System Debian 11.3

« previous php.bugs (#241811) next »