From e76a68dcb816568b5bdecf8f6fdf4868722ae42a 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] Fix GH-16168: php 8.1 and earlier crash immediately when compiled with Xcode 16 clang on macOS 15 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]. This causes the compiler to get confused and move part of the inline assembly into 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 --- Zend/zend_string.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Zend/zend_string.c b/Zend/zend_string.c index 5e0fbea529b7e..c90af6e28884c 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -392,32 +392,32 @@ ZEND_API bool ZEND_FASTCALL I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_va ZEND_API zend_never_inline NOIPA bool ZEND_FASTCALL zend_string_equal_val(const zend_string *s1, const zend_string *s2) { const char *ptr = ZSTR_VAL(s1); - size_t delta = (const char*)s2 - (const char*)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) @@ -430,32 +430,32 @@ ZEND_API zend_never_inline NOIPA bool ZEND_FASTCALL zend_string_equal_val(const ZEND_API zend_never_inline NOIPA bool ZEND_FASTCALL zend_string_equal_val(const zend_string *s1, const zend_string *s2) { const char *ptr = ZSTR_VAL(s1); - size_t delta = (const char*)s2 - (const char*)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)