Skip to content

Commit 7227bb6

Browse files
committed
Fix GH-9068: Conditional jump or move depends on uninitialised value(s)
See GH-9068 for analysis. This patch preserves the scratch registers of the SysV x86-64 ABI by storing them on the stack and restoring them later. We need to do this to prevent the registers of the caller from being corrupted. The reason these get corrupted is because the compiler is unaware of the Valgrind replacement function and thus makes assumptions about the original function regarding registers which are not true for the replacement function.
1 parent 4c9375e commit 7227bb6

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

Zend/zend_string.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,57 @@ ZEND_API void zend_interned_strings_switch_storage(bool request)
372372
# define I_REPLACE_SONAME_FNNAME_ZU(soname, fnname) _vgr00000ZU_ ## soname ## _ ## fnname
373373
#endif
374374

375-
ZEND_API bool ZEND_FASTCALL I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val)(zend_string *s1, zend_string *s2)
375+
#define VALGRIND_REPLACEMENT_STRING_EQUAL_VAL_MEMCMP_WRAPPER I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val_memcmp_wrapper)
376+
#define VALGRIND_REPLACEMENT_STRING_EQUAL_VAL I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val)
377+
#define STR1(X) #X
378+
#define STR(X) STR1(X)
379+
380+
bool VALGRIND_REPLACEMENT_STRING_EQUAL_VAL_MEMCMP_WRAPPER(zend_string *s1, zend_string *s2)
376381
{
377382
return !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1));
378383
}
379384

385+
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__ILP32__)
386+
/*
387+
* See https://github.com/php/php-src/issues/9068
388+
* We need to preserve the scratch registers because we cannot know what
389+
* the compiler assumes to be unchanged by the original
390+
* zend_string_equal_val implementation.
391+
* We can safely use push and pop because we're not in leaf function.
392+
* We're using a function defined using inline assembly so that the compiler does not
393+
* mess with our store and restore procedure.
394+
*/
395+
__asm__ (
396+
".globl " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) "\n\t"
397+
".type " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) ", @function\n\t"
398+
STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) ":\n\t"
399+
"pushq %rdi\n\t"
400+
"pushq %rsi\n\t"
401+
"pushq %rdx\n\t"
402+
"pushq %rcx\n\t"
403+
"pushq %r8\n\t"
404+
"pushq %r9\n\t"
405+
"pushq %r10\n\t"
406+
"pushq %r11\n\t"
407+
"callq " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL_MEMCMP_WRAPPER) "\n\t"
408+
"popq %r11\n\t"
409+
"popq %r10\n\t"
410+
"popq %r9\n\t"
411+
"popq %r8\n\t"
412+
"popq %rcx\n\t"
413+
"popq %rdx\n\t"
414+
"popq %rsi\n\t"
415+
"popq %rdi\n\t"
416+
"ret\n\t"
417+
".size " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) ", .-" STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) "\n\t"
418+
);
419+
#else
420+
ZEND_API bool ZEND_FASTCALL VALGRIND_REPLACEMENT_STRING_EQUAL_VAL(zend_string *s1, zend_string *s2)
421+
{
422+
return VALGRIND_REPLACEMENT_STRING_EQUAL_VAL_MEMCMP_WRAPPER(s1, s2);
423+
}
424+
#endif
425+
380426
#if defined(__GNUC__) && defined(__i386__)
381427
ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string *s2)
382428
{

0 commit comments

Comments
 (0)