php / php/php-src

Segfaults, inconsistency and confusion when adding (+) `int` to typecasted FFI\CData

Abierto
#8,874 6 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Bug Extension: ffi Status: Needs Triage
Lenguaje dominante
C
Estrellas
40.4k
Forks
8.1k
Merge medio
2 d 13 h
PR fusionados (30 d)
96

Descripción

Description

The following code:

<?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

$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
$ffi = FFI::cdef('

  typedef long unsigned int size_t;
  void *malloc(size_t size);

');

$ptr = $ffi->cast('uint8_t *', $ffi->malloc(27));

// Fill memory with "A..Z" for presentational purposes
for ($i = 0; $i < 26; $i++) {
  $ptr[$i] = $i + 65; // 'A'
}

var_dump(FFI::string($ptr, 16));
var_dump(FFI::string($ptr + 5, 16));
var_dump(FFI::string($ptr + 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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Reproduce los casos de var_dump(), var_export() y FFI::string(), y luego inspecciona Zend/zend_object_handlers.c alrededor de la línea 1880 y el manejo de operandos de FFI. Compara los accesos repetidos de pointer-plus-int y determina el comportamiento coherente para los FFI pointers tipados. Se considera completado cuando el comportamiento está definido y los casos reportados ya no producen un segmentation fault ni un TypeError incoherente.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
c, php
Área
backend
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
35/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.