php / php/php-src

[FFI] Segfault/memory leak on incorrect use of FFI definitions

Abierto
#12,910 1 comentario 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Bug Extension: ffi Status: Verified
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

class MyClass
{
    public static function do(): void
    {
        $ffi = FFI::cdef("struct struct1{int x;};struct struct2{int y;};void takesStruct1(struct struct1*);", __DIR__ . "/a.out");
        $struct2 = $ffi->new("struct struct2");
        $ffi->takesStruct1(FFI::addr($struct2));
    }
}

MyClass::do();

With the following C source for a.out (compile with cc -shared test.c):

#include <stdio.h>
struct struct1{int x; int y;};
struct struct2{int x;};
void takesStruct1(struct struct1*){printf("I took a struct1!");}

Resulted in this output:

php: /home/iggyvolz/php-src/ext/ffi/ffi.c:1631: zend_ffi_ctype_name: Assertion `0' failed.
Aborted

With the following gdb backtrace:

#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0)   
    at ./nptl/pthread_kill.c:44
#1  0x00007ffff6bfcd9f in __pthread_kill_internal (signo=6, threadid=<optimized out>)
    at ./nptl/pthread_kill.c:78
#2  0x00007ffff6badf32 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff6b98472 in __GI_abort () at ./stdlib/abort.c:79
#4  0x00007ffff6b98395 in __assert_fail_base (
    fmt=0x7ffff6d0ca90 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n",
    assertion=assertion@entry=0x555555e9582e "0",
    file=file@entry=0x555555e95188 "/home/iggyvolz/php-src/ext/ffi/ffi.c", line=line@entry=1631,
    function=function@entry=0x555555e97ca0 <__PRETTY_FUNCTION__.58> "zend_ffi_ctype_name")
    at ./assert/assert.c:92
#5  0x00007ffff6ba6e32 in __GI___assert_fail (assertion=0x555555e9582e "0",
    file=0x555555e95188 "/home/iggyvolz/php-src/ext/ffi/ffi.c", line=1631,
    function=0x555555e97ca0 <__PRETTY_FUNCTION__.58> "zend_ffi_ctype_name") at ./assert/assert.c:101       
#6  0x0000555555779388 in zend_ffi_ctype_name (buf=0x7fffffffa4e0, type=0x7ffff407f080)
    at /home/iggyvolz/php-src/ext/ffi/ffi.c:1631
#7  0x0000555555779932 in zend_ffi_get_class_name (prefix=0x555556dc1ad0, type=0x7ffff407f300)
    at /home/iggyvolz/php-src/ext/ffi/ffi.c:1732
#8  0x00005555557799d1 in zend_ffi_cdata_get_class_name (zobj=0x7ffff407f380)
    at /home/iggyvolz/php-src/ext/ffi/ffi.c:1745
#9  0x0000555555cfaaee in _build_trace_args (arg=0x7ffff40603c8, str=0x7fffffffa720)
    at /home/iggyvolz/php-src/Zend/zend_exceptions.c:517
#10 0x0000555555cfb06d in _build_trace_string (str=0x7fffffffa720, ht=0x7ffff405c6c0, num=0)
    at /home/iggyvolz/php-src/Zend/zend_exceptions.c:576
#11 0x0000555555cfb235 in zend_trace_to_string (trace=0x7ffff405c660, include_main=true)
    at /home/iggyvolz/php-src/Zend/zend_exceptions.c:602
#12 0x0000555555cfb3e8 in zim_Exception_getTraceAsString (execute_data=0x7ffff4016070,
    return_value=0x7fffffffaa90) at /home/iggyvolz/php-src/Zend/zend_exceptions.c:631
#13 0x0000555555c07d8c in zend_call_function (fci=0x7fffffffaa50, fci_cache=0x7fffffffa830)
    at /home/iggyvolz/php-src/Zend/zend_execute_API.c:970
#14 0x0000555555cfb6da in zim_Exception___toString (execute_data=0x7ffff4016020, 
    return_value=0x7fffffffaed0) at /home/iggyvolz/php-src/Zend/zend_exceptions.c:676
#15 0x0000555555c07d8c in zend_call_function (fci=0x7fffffffadc0, fci_cache=0x7fffffffad90)
    at /home/iggyvolz/php-src/Zend/zend_execute_API.c:970
#16 0x0000555555c0826a in zend_call_known_function (fn=0x555556d33960, object=0x7ffff4060300, 
    called_scope=0x555556dc0170, retval_ptr=0x7fffffffaed0, param_count=0, params=0x0, named_params=0x0)
    at /home/iggyvolz/php-src/Zend/zend_execute_API.c:1051
#17 0x0000555555cf7b95 in zend_call_known_instance_method (fn=0x555556d33960, object=0x7ffff4060300, 
    retval_ptr=0x7fffffffaed0, param_count=0, params=0x0) at /home/iggyvolz/php-src/Zend/zend_API.h:853    
#18 0x0000555555cf7bcf in zend_call_known_instance_method_with_0_params (fn=0x555556d33960,
    object=0x7ffff4060300, retval_ptr=0x7fffffffaed0) at /home/iggyvolz/php-src/Zend/zend_API.h:859        
#19 0x0000555555cfc8c0 in zend_exception_error (ex=0x7ffff4060300, severity=1)
    at /home/iggyvolz/php-src/Zend/zend_exceptions.c:921
#20 0x0000555555c243e1 in zend_execute_scripts (type=8, retval=0x0, file_count=3)
    at /home/iggyvolz/php-src/Zend/zend.c:1888
#21 0x0000555555b61ee2 in php_execute_script (primary_file=0x7fffffffd4f0)
    at /home/iggyvolz/php-src/main/main.c:2501
#22 0x0000555555dae79d in do_cli (argc=2, argv=0x555556c29550)
    at /home/iggyvolz/php-src/sapi/cli/php_cli.c:966
#23 0x0000555555daf56f in main (argc=2, argv=0x555556c29550)
    at /home/iggyvolz/php-src/sapi/cli/php_cli.c:1340

But when I run with this (should-be-equivalent) PHP code:

<?php
$ffi = FFI::cdef("struct struct1{int x;};struct struct2{int y;};void takesStruct1(struct struct1*);", __DIR__ . "/a.out");
$struct2 = $ffi->new("struct struct2");
$ffi->takesStruct1(FFI::addr($struct2));

I receive the correct output:

Fatal error: Uncaught FFI\Exception: Passing incompatible argument 1 of C function 'takesStruct1', expecting 'struct struct1*', found 'struct struct2*' in /home/iggyvolz/phpwayland/testsegfault.php:17
Stack trace:
#0 /.../testsegfault.php(17): FFI->takesStruct1(Object(FFI\CData:struct struct2*))    
#1 {main}
  thrown in /home/iggyvolz/phpwayland/testsegfault.php on line 17

While debugging this issue, I also found a similar-seeming issue with the following class:

<?php
FFI::cdef("void FAKE_FUNCTION();");

Returns a memory leak in the debug build of PHP:

Fatal error: Uncaught FFI\Exception: Failed resolving C function 'FAKE_FUNCTION' in /home/iggyvolz/phpwayland/testmemleak.php:2
Stack trace:
#0 /home/iggyvolz/phpwayland/testmemleak.php(2): FFI::cdef('void FAKE_FUNCT...')
#1 {main}
  thrown in /home/iggyvolz/phpwayland/testmemleak.php on line 2
[Fri Dec  8 07:48:04 2023]  Script:  '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/Zend/zend_string.h(174) :  Freeing 0x00007f7aece02dc0 (40 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec  8 07:48:04 2023]  Script:  '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/ext/ffi/ffi.c(6628) :  Freeing 0x00007f7aece5b118 (24 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec  8 07:48:04 2023]  Script:  '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/ext/ffi/ffi.c(6559) :  Freeing 0x00007f7aece5c540 (56 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec  8 07:48:04 2023]  Script:  '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/Zend/zend_hash.c(177) :  Freeing 0x00007f7aece6c300 (320 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec  8 07:48:04 2023]  Script:  '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/ext/ffi/ffi.c(6440) :  Freeing 0x00007f7aece7e000 (88 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
=== Total 5 memory leaks detected ===

Not sure whether this is a different bug or just the same underlying issue manifesting differently, but they feel similar enough that my suspicion is the latter (I can split this into a separate issue if requested).

PHP Version

PHP 8.3.0

Operating System

Debian 12

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

Empieza reproduciendo la llamada FFI basada en clases y el caso FAKE_FUNCTION no resuelto en una compilación de depuración de PHP 8.3. Inspecciona ext/ffi/ffi.c alrededor de zend_ffi_ctype_name en la línea 1631 y las ubicaciones de fugas notificadas en las líneas 6440, 6559 y 6628. Se considera terminado cuando el argumento Struct incompatible produce la excepción FFI normal sin una aserción, y la resolución fallida de la función no deja fugas de memoria en la compilación de depuración.

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.