php / php/php-src

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

Đang mở
#8,874 6 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Bug Extension: ffi Status: Needs Triage
Ngôn ngữ chính
C
Star
40.4k
Fork
8.2k
Merge trung bình
2 ngày 13 giờ
Pull request đã merge (30 ngày)
96

Mô tả

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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Tái hiện các trường hợp var_dump(), var_export() và FFI::string(), sau đó kiểm tra Zend/zend_object_handlers.c quanh dòng 1880 và cách xử lý toán hạng FFI. So sánh các lần truy cập lặp lại dạng pointer-plus-int và xác định hành vi nhất quán đối với các FFI pointers có kiểu. Hoàn tất khi hành vi đã được định nghĩa và các trường hợp được báo cáo không còn tạo ra segmentation fault hoặc TypeError không nhất quán.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
c, php
Lĩnh vực
backend
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.