From 4d7535937294f0b4364b24df3242d53f541f2588 Mon Sep 17 00:00:00 2001 From: nielsdos <7771979+nielsdos@users.noreply.github.com> Date: Tue, 2 May 2023 21:21:01 +0200 Subject: [PATCH] Fix GH-9068: Conditional jump or move depends on uninitialised value(s) This patch preserves the scratch registers of the SysV x86-64 ABI by storing them to 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. For implementation I used a GCC and Clang attribute. A more general approach would be to use inline assembly but that's also less portable and quite hacky. This attributes is supported since GCC 7.x, but the target option is only supported since 11.x. For Clang the target option does not matter. --- Zend/zend_string.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Zend/zend_string.c b/Zend/zend_string.c index 8e6a16c64afb5..e8a01c736575c 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -372,11 +372,26 @@ ZEND_API void zend_interned_strings_switch_storage(bool request) # define I_REPLACE_SONAME_FNNAME_ZU(soname, fnname) _vgr00000ZU_ ## soname ## _ ## fnname #endif -ZEND_API bool ZEND_FASTCALL I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val)(zend_string *s1, zend_string *s2) +/* See GH-9068 */ +#if defined(__GNUC__) && (__GNUC__ >= 11 || defined(__clang__)) && __has_attribute(no_caller_saved_registers) +# define NO_CALLER_SAVED_REGISTERS __attribute__((no_caller_saved_registers)) +# ifndef __clang__ +# pragma GCC push_options +# pragma GCC target ("general-regs-only") +# endif +#else +# define NO_CALLER_SAVED_REGISTERS +#endif + +ZEND_API bool ZEND_FASTCALL NO_CALLER_SAVED_REGISTERS I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val)(zend_string *s1, zend_string *s2) { return !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1)); } +#if defined(__GNUC__) && __GNUC__ >= 11 && !defined(__clang__) && __has_attribute(no_caller_saved_registers) +# pragma GCC pop_options +#endif + #if defined(__GNUC__) && defined(__i386__) ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string *s2) {