Skip to content

Commit 7372bc1

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 7372bc1

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

Zend/zend_string.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,69 @@ 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__) && (defined(__linux__) || defined(__MACH__) || defined(__sun) || defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__))
386+
387+
/* macOS needs an additional _ prefix to be able to call functions from asm */
388+
#ifdef __MACH__
389+
#define SYMBOL_FUNCTION_PREFIX _
390+
#else
391+
#define SYMBOL_FUNCTION_PREFIX
392+
#endif
393+
394+
/*
395+
* See https://github.com/php/php-src/issues/9068
396+
* We need to preserve the scratch registers because we cannot know what
397+
* the compiler assumes to be unchanged by the original
398+
* zend_string_equal_val implementation.
399+
* We can safely use push and pop because we're not in leaf function.
400+
* We're using a function defined using inline assembly so that the compiler does not
401+
* mess with our store and restore procedure.
402+
*/
403+
__asm__ (
404+
".globl " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) "\n\t"
405+
#ifndef __MACH__
406+
".type " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) ", @function\n\t"
407+
#endif
408+
STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) ":\n\t"
409+
"pushq %rdi\n\t"
410+
"pushq %rsi\n\t"
411+
"pushq %rdx\n\t"
412+
"pushq %rcx\n\t"
413+
"pushq %r8\n\t"
414+
"pushq %r9\n\t"
415+
"pushq %r10\n\t"
416+
"pushq %r11\n\t"
417+
"callq " STR(SYMBOL_FUNCTION_PREFIX) STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL_MEMCMP_WRAPPER) "\n\t"
418+
"popq %r11\n\t"
419+
"popq %r10\n\t"
420+
"popq %r9\n\t"
421+
"popq %r8\n\t"
422+
"popq %rcx\n\t"
423+
"popq %rdx\n\t"
424+
"popq %rsi\n\t"
425+
"popq %rdi\n\t"
426+
"ret\n\t"
427+
#ifndef __MACH__
428+
".size " STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) ", .-" STR(VALGRIND_REPLACEMENT_STRING_EQUAL_VAL) "\n\t"
429+
#endif
430+
);
431+
#else
432+
ZEND_API bool ZEND_FASTCALL VALGRIND_REPLACEMENT_STRING_EQUAL_VAL(zend_string *s1, zend_string *s2)
433+
{
434+
return VALGRIND_REPLACEMENT_STRING_EQUAL_VAL_MEMCMP_WRAPPER(s1, s2);
435+
}
436+
#endif
437+
380438
#if defined(__GNUC__) && defined(__i386__)
381439
ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string *s2)
382440
{

0 commit comments

Comments
 (0)