From 806d2e073c1fe67dfe3c5791f4483f44dd991b28 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:39:19 +0200 Subject: [PATCH] Backport GH-16348 Agreed by RM: https://github.com/php/php-src/issues/16168#issuecomment-2525433557 The inline assembly uses labels with the prefix `.L`. On Linux systems this is the local label prefix. It appears that macOS uses `L` as a local prefix, which means that the prefix used in the inline assembly is not local for macOS systems [1]. When combined with inlining, this causes the compiler to get confused and merge a part of the inline assembly between different functions, causing control flow to jump from one function to another function. This is avoided on PHP 8.2 and up by the fact that it uses `zend_never_inline NOIPA`, but nothing guarantees that compiler changes won't affect this as well. To solve this issue, we instead use local labels. These will make the compiler pick the correct prefix, preventing the issue. Additionally, while here, we also change the computation of `delta`. It is undefined behaviour to compute the pointer difference between two different objects. To circumvent this, we cast first to `uintptr_t`. This change is cleanly backportable to 8.1 for vendors to pick up. [1] https://github.com/php/php-src/issues/16168#issuecomment-2404792553 With the help of investigation and testing of @ryandesign. Closes GH-16348. --- Zend/zend_string.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Zend/zend_string.c b/Zend/zend_string.c index 1da3ce52485..c21b4f5d461 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -397,33 +397,33 @@ ZEND_API bool ZEND_FASTCALL NO_CALLER_SAVED_REGISTERS I_REPLACE_SONAME_FNNAME_ZU #if defined(__GNUC__) && defined(__i386__) ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string *s2) { - char *ptr = ZSTR_VAL(s1); - size_t delta = (char*)s2 - (char*)s1; + const char *ptr = ZSTR_VAL(s1); + uintptr_t delta = (uintptr_t) s2 - (uintptr_t) s1; size_t len = ZSTR_LEN(s1); zend_ulong ret; __asm__ ( - ".LL0%=:\n\t" + "0:\n\t" "movl (%2,%3), %0\n\t" "xorl (%2), %0\n\t" - "jne .LL1%=\n\t" + "jne 1f\n\t" "addl $0x4, %2\n\t" "subl $0x4, %1\n\t" - "ja .LL0%=\n\t" + "ja 0b\n\t" "movl $0x1, %0\n\t" - "jmp .LL3%=\n\t" - ".LL1%=:\n\t" + "jmp 3f\n\t" + "1:\n\t" "cmpl $0x4,%1\n\t" - "jb .LL2%=\n\t" + "jb 2f\n\t" "xorl %0, %0\n\t" - "jmp .LL3%=\n\t" - ".LL2%=:\n\t" + "jmp 3f\n\t" + "2:\n\t" "negl %1\n\t" "lea 0x20(,%1,8), %1\n\t" "shll %b1, %0\n\t" "sete %b0\n\t" "movzbl %b0, %0\n\t" - ".LL3%=:\n" + "3:\n" : "=&a"(ret), "+c"(len), "+r"(ptr) @@ -435,33 +435,33 @@ ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string * #elif defined(__GNUC__) && defined(__x86_64__) && !defined(__ILP32__) ZEND_API bool ZEND_FASTCALL zend_string_equal_val(zend_string *s1, zend_string *s2) { - char *ptr = ZSTR_VAL(s1); - size_t delta = (char*)s2 - (char*)s1; + const char *ptr = ZSTR_VAL(s1); + uintptr_t delta = (uintptr_t) s2 - (uintptr_t) s1; size_t len = ZSTR_LEN(s1); zend_ulong ret; __asm__ ( - ".LL0%=:\n\t" + "0:\n\t" "movq (%2,%3), %0\n\t" "xorq (%2), %0\n\t" - "jne .LL1%=\n\t" + "jne 1f\n\t" "addq $0x8, %2\n\t" "subq $0x8, %1\n\t" - "ja .LL0%=\n\t" + "ja 0b\n\t" "movq $0x1, %0\n\t" - "jmp .LL3%=\n\t" - ".LL1%=:\n\t" + "jmp 3f\n\t" + "1:\n\t" "cmpq $0x8,%1\n\t" - "jb .LL2%=\n\t" + "jb 2f\n\t" "xorq %0, %0\n\t" - "jmp .LL3%=\n\t" - ".LL2%=:\n\t" + "jmp 3f\n\t" + "2:\n\t" "negq %1\n\t" "lea 0x40(,%1,8), %1\n\t" "shlq %b1, %0\n\t" "sete %b0\n\t" "movzbq %b0, %0\n\t" - ".LL3%=:\n" + "3:\n" : "=&a"(ret), "+c"(len), "+r"(ptr)