Skip to content

Commit

Permalink
Merge branch '6.4' into 7.0
Browse files Browse the repository at this point in the history
* 6.4:
  [HttpClient][Mailer] Revert "Let curl handle transfer encoding", use HTTP/1.1 for Mailgun
  Reviewed Catalan missing translations
  [AssetMapper] Upgrade importmap polyfill
  Fix typo: synchronous -> synchronously
  [Serializer] Check if exception message in test is correct
  Ibexa is sponsoring Symfony 5.4, thanks to them! \o/
  [VarDumper] Fix `FFICaster` test to be platform-adaptable
  [String] Add `alias` case to `EnglishInflector`
  [FrameworkBundle] Throw runtime exception when trying to use asset-mapper while http-client is disabled
  [SecurityBundle] Remove unused memory users’ `name` attribute from the XSD
  [VarExporter] generate __doUnserialize() method in ProxyHelper::generateLazyProxy()
  Double check if pcntl function exists
  Add additional headers in Scaleway bridge
  [VarDumper] Fix FFI caster test
  [DependencyInjection] Add test coverage for `AutowireCallable::buildDefinition()`
  • Loading branch information
nicolas-grekas committed Jun 28, 2024
2 parents 5d2a35f + c31566e commit a9d8914
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 23 deletions.
14 changes: 12 additions & 2 deletions Caster/FFICaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,21 @@ private static function castFFIPointer(Stub $stub, CType $type, ?CData $data = n
private static function castFFIStringValue(CData $data): string|CutStub
{
$result = [];
$ffi = \FFI::cdef(<<<C
size_t zend_get_page_size(void);
C);

for ($i = 0; $i < self::MAX_STRING_LENGTH; ++$i) {
$pageSize = $ffi->zend_get_page_size();

// get cdata address
$start = $ffi->cast('uintptr_t', $ffi->cast('char*', $data))->cdata;
// accessing memory in the same page as $start is safe
$max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start);

for ($i = 0; $i < $max; ++$i) {
$result[$i] = $data[$i];

if ("\0" === $result[$i]) {
if ("\0" === $data[$i]) {
return implode('', $result);
}
}
Expand Down
41 changes: 20 additions & 21 deletions Tests/Caster/FFICasterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class FFICasterTest extends TestCase
{
use VarDumperTestTrait;

/**
* @see FFICaster::MAX_STRING_LENGTH
*/
private const MAX_STRING_LENGTH = 255;

protected function setUp(): void
{
if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && 'preload' === \ini_get('ffi.enable')) {
Expand Down Expand Up @@ -173,52 +178,46 @@ public function testCastCuttedPointerToChar()
{
$actualMessage = str_repeat('Hello World!', 30)."\0";
$actualLength = \strlen($actualMessage);

$expectedMessage = 'Hello World!Hello World!Hello World!Hello World!'
.'Hello World!Hello World!Hello World!Hello World!Hello World!Hel'
.'lo World!Hello World!Hello World!Hello World!Hello World!Hello '
.'World!Hello World!Hello World!Hello World!Hello World!Hello Wor'
.'ld!Hello World!Hel';
$expectedMessage = substr($actualMessage, 0, self::MAX_STRING_LENGTH);

$string = \FFI::cdef()->new('char['.$actualLength.']');
$pointer = \FFI::addr($string[0]);
\FFI::memcpy($pointer, $actualMessage, $actualLength);

// the max length is platform-dependent and can be less than 255,
// so we need to cut the expected message to the maximum length
// allowed by pages size of the current system
$ffi = \FFI::cdef(<<<C
size_t zend_get_page_size(void);
C);

$pageSize = $ffi->zend_get_page_size();
$start = $ffi->cast('uintptr_t', $ffi->cast('char*', $pointer))->cdata;
$max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start);
$expectedMessage = substr($expectedMessage, 0, $max);

$this->assertDumpEquals(<<<PHP
FFI\CData<char*> size 8 align 8 {
cdata: "$expectedMessage"…
}
PHP, $pointer);
}

/**
* It is worth noting that such a test can cause SIGSEGV, as it breaks
* into "foreign" memory. However, this is only theoretical, since
* memory is allocated within the PHP process and almost always "garbage
* data" will be read from the PHP process itself.
*
* If this test fails for some reason, please report it: We may have to
* disable the dumping of strings ("char*") feature in VarDumper.
*
* @see FFICaster::castFFIStringValue()
*/
public function testCastNonTrailingCharPointer()
{
$actualMessage = 'Hello World!';
$actualLength = \strlen($actualMessage);

$string = \FFI::cdef()->new('char['.$actualLength.']');
$string = \FFI::cdef()->new('char['.($actualLength + 1).']');
$pointer = \FFI::addr($string[0]);

\FFI::memcpy($pointer, $actualMessage, $actualLength);

// Remove automatically addition of the trailing "\0" and remove trailing "\0"
$pointer = \FFI::cdef()->cast('char*', \FFI::cdef()->cast('void*', $pointer));
$pointer[$actualLength] = "\x01";

$this->assertDumpMatchesFormat(<<<PHP
FFI\CData<char*> size 8 align 8 {
cdata: "$actualMessage%s"
cdata: %A"$actualMessage%s"
}
PHP, $pointer);
}
Expand Down

0 comments on commit a9d8914

Please sign in to comment.