Skip to content

Commit 5857c57

Browse files
Merge branch '7.0' into 7.1
* 7.0: [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()`
2 parents c33d420 + a9d8914 commit 5857c57

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

Caster/FFICaster.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,21 @@ private static function castFFIPointer(Stub $stub, CType $type, ?CData $data = n
115115
private static function castFFIStringValue(CData $data): string|CutStub
116116
{
117117
$result = [];
118+
$ffi = \FFI::cdef(<<<C
119+
size_t zend_get_page_size(void);
120+
C);
118121

119-
for ($i = 0; $i < self::MAX_STRING_LENGTH; ++$i) {
122+
$pageSize = $ffi->zend_get_page_size();
123+
124+
// get cdata address
125+
$start = $ffi->cast('uintptr_t', $ffi->cast('char*', $data))->cdata;
126+
// accessing memory in the same page as $start is safe
127+
$max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start);
128+
129+
for ($i = 0; $i < $max; ++$i) {
120130
$result[$i] = $data[$i];
121131

122-
if ("\0" === $result[$i]) {
132+
if ("\0" === $data[$i]) {
123133
return implode('', $result);
124134
}
125135
}

Tests/Caster/FFICasterTest.php

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class FFICasterTest extends TestCase
2424
{
2525
use VarDumperTestTrait;
2626

27+
/**
28+
* @see FFICaster::MAX_STRING_LENGTH
29+
*/
30+
private const MAX_STRING_LENGTH = 255;
31+
2732
protected function setUp(): void
2833
{
2934
if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && 'preload' === \ini_get('ffi.enable')) {
@@ -173,52 +178,46 @@ public function testCastCuttedPointerToChar()
173178
{
174179
$actualMessage = str_repeat('Hello World!', 30)."\0";
175180
$actualLength = \strlen($actualMessage);
176-
177-
$expectedMessage = 'Hello World!Hello World!Hello World!Hello World!'
178-
.'Hello World!Hello World!Hello World!Hello World!Hello World!Hel'
179-
.'lo World!Hello World!Hello World!Hello World!Hello World!Hello '
180-
.'World!Hello World!Hello World!Hello World!Hello World!Hello Wor'
181-
.'ld!Hello World!Hel';
181+
$expectedMessage = substr($actualMessage, 0, self::MAX_STRING_LENGTH);
182182

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

187+
// the max length is platform-dependent and can be less than 255,
188+
// so we need to cut the expected message to the maximum length
189+
// allowed by pages size of the current system
190+
$ffi = \FFI::cdef(<<<C
191+
size_t zend_get_page_size(void);
192+
C);
193+
194+
$pageSize = $ffi->zend_get_page_size();
195+
$start = $ffi->cast('uintptr_t', $ffi->cast('char*', $pointer))->cdata;
196+
$max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start);
197+
$expectedMessage = substr($expectedMessage, 0, $max);
198+
187199
$this->assertDumpEquals(<<<PHP
188200
FFI\CData<char*> size 8 align 8 {
189201
cdata: "$expectedMessage"…
190202
}
191203
PHP, $pointer);
192204
}
193205

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

210-
$string = \FFI::cdef()->new('char['.$actualLength.']');
211+
$string = \FFI::cdef()->new('char['.($actualLength + 1).']');
211212
$pointer = \FFI::addr($string[0]);
212-
213213
\FFI::memcpy($pointer, $actualMessage, $actualLength);
214214

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

219218
$this->assertDumpMatchesFormat(<<<PHP
220219
FFI\CData<char*> size 8 align 8 {
221-
cdata: "$actualMessage%s"
220+
cdata: %A"$actualMessage%s"
222221
}
223222
PHP, $pointer);
224223
}

0 commit comments

Comments
 (0)