Use built-ins for addition and subtraction on Windows (GH-17472)

For Clang, we just need to define the respective macros, since these
built-ins are available in all supported Clang versions (>= 4.0.0,
currently)[1].

For MSVC (and possibly other compilers) we use the respective APIs of
intsafe.h[2] which are available as of Windows 7/Server 2008 R2.

This avoids the UB due to signed integer overflow that may happen with
our fallback implementations.

We also drop the superfluous SHORT_MAX definition from pdo_firebird.
This shouldn't be defined unconditionally, but since it is apparently
unused, we remove it altogether.

[1] <https://releases.llvm.org/4.0.0/tools/clang/docs/LanguageExtensions.html>
[2] <https://learn.microsoft.com/en-us/windows/win32/api/intsafe/>
This commit is contained in:
Christoph M. Becker 2025-01-15 12:58:12 +01:00 committed by GitHub
parent abfa377fae
commit 7512685767
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 70 additions and 2 deletions

View file

@ -36,6 +36,7 @@
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#include <intsafe.h>
#include <float.h> #include <float.h>
#define strcasecmp(s1, s2) _stricmp(s1, s2) #define strcasecmp(s1, s2) _stricmp(s1, s2)

View file

@ -579,6 +579,22 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL
} else { } else {
Z_LVAL_P(op1) = llresult; Z_LVAL_P(op1) = llresult;
} }
#elif defined(ZEND_WIN32) && SIZEOF_LONG == SIZEOF_ZEND_LONG
long lresult;
if (UNEXPECTED(FAILED(LongAdd(Z_LVAL_P(op1), 1, &lresult)))) {
/* switch to double */
ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
} else {
Z_LVAL_P(op1) = lresult;
}
#elif defined(ZEND_WIN32) && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
long long llresult;
if (UNEXPECTED(FAILED(LongLongAdd(Z_LVAL_P(op1), 1, &llresult)))) {
/* switch to double */
ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
} else {
Z_LVAL_P(op1) = llresult;
}
#else #else
if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) { if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) {
/* switch to double */ /* switch to double */
@ -642,6 +658,22 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL
} else { } else {
Z_LVAL_P(op1) = llresult; Z_LVAL_P(op1) = llresult;
} }
#elif defined(ZEND_WIN32) && SIZEOF_LONG == SIZEOF_ZEND_LONG
long lresult;
if (UNEXPECTED(FAILED(LongSub(Z_LVAL_P(op1), 1, &lresult)))) {
/* switch to double */
ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
} else {
Z_LVAL_P(op1) = lresult;
}
#elif defined(ZEND_WIN32) && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
long long llresult;
if (UNEXPECTED(FAILED(LongLongSub(Z_LVAL_P(op1), 1, &llresult)))) {
/* switch to double */
ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
} else {
Z_LVAL_P(op1) = llresult;
}
#else #else
if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) { if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) {
/* switch to double */ /* switch to double */
@ -724,6 +756,20 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL
} else { } else {
ZVAL_LONG(result, llresult); ZVAL_LONG(result, llresult);
} }
#elif defined(ZEND_WIN32) && SIZEOF_LONG == SIZEOF_ZEND_LONG
long lresult;
if (UNEXPECTED(FAILED(LongAdd(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult)))) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, lresult);
}
#elif defined(ZEND_WIN32) && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
long long llresult;
if (UNEXPECTED(FAILED(LongLongAdd(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult)))) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, llresult);
}
#else #else
/* /*
* 'result' may alias with op1 or op2, so we need to * 'result' may alias with op1 or op2, so we need to
@ -812,6 +858,20 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL
} else { } else {
ZVAL_LONG(result, llresult); ZVAL_LONG(result, llresult);
} }
#elif defined(ZEND_WIN32) && SIZEOF_LONG == SIZEOF_ZEND_LONG
long lresult;
if (UNEXPECTED(FAILED(LongSub(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult)))) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, lresult);
}
#elif defined(ZEND_WIN32) && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
long long llresult;
if (UNEXPECTED(FAILED(LongLongSub(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult)))) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, llresult);
}
#else #else
ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2)); ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2));

View file

@ -33,8 +33,6 @@
#define PDO_FB_DEF_TIME_FMT "%H:%M:%S" #define PDO_FB_DEF_TIME_FMT "%H:%M:%S"
#define PDO_FB_DEF_TIMESTAMP_FMT PDO_FB_DEF_DATE_FMT " " PDO_FB_DEF_TIME_FMT #define PDO_FB_DEF_TIMESTAMP_FMT PDO_FB_DEF_DATE_FMT " " PDO_FB_DEF_TIME_FMT
#define SHORT_MAX (1 << (8*sizeof(short)-1))
#if SIZEOF_ZEND_LONG == 8 && !defined(PHP_WIN32) #if SIZEOF_ZEND_LONG == 8 && !defined(PHP_WIN32)
# define LL_LIT(lit) lit ## L # define LL_LIT(lit) lit ## L
#else #else

View file

@ -370,6 +370,10 @@ if (VS_TOOLSET) {
} }
} }
} else if (CLANG_TOOLSET) { } else if (CLANG_TOOLSET) {
AC_DEFINE("PHP_HAVE_BUILTIN_SADDL_OVERFLOW", 1, "Define to 1 if the compiler supports '__builtin_saddl_overflow'.");
AC_DEFINE("PHP_HAVE_BUILTIN_SADDLL_OVERFLOW", 1, "Define to 1 if the compiler supports '__builtin_saddll_overflow'.");
AC_DEFINE("PHP_HAVE_BUILTIN_SSUBL_OVERFLOW", 1, "Define to 1 if the compiler supports '__builtin_ssubl_overflow'.");
AC_DEFINE("PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW", 1, "Define to 1 if the compiler supports '__builtin_ssubll_overflow'.");
if (PHP_UNCRITICAL_WARN_CHOKE != "no") { if (PHP_UNCRITICAL_WARN_CHOKE != "no") {
ADD_FLAG("CFLAGS", "-Wno-ignored-attributes -Wno-deprecated-declarations -Wno-missing-braces " + ADD_FLAG("CFLAGS", "-Wno-ignored-attributes -Wno-deprecated-declarations -Wno-missing-braces " +
"-Wno-logical-op-parentheses -Wno-msvc-include -Wno-invalid-source-encoding -Wno-unknown-pragmas " + "-Wno-logical-op-parentheses -Wno-msvc-include -Wno-invalid-source-encoding -Wno-unknown-pragmas " +

View file

@ -3318,6 +3318,11 @@ function toolset_setup_common_cflags()
var vc_ver = probe_binary(PATH_PROG('cl', null)); var vc_ver = probe_binary(PATH_PROG('cl', null));
ADD_FLAG("CFLAGS"," -fms-compatibility -fms-compatibility-version=" + vc_ver + " -fms-extensions"); ADD_FLAG("CFLAGS"," -fms-compatibility -fms-compatibility-version=" + vc_ver + " -fms-extensions");
} }
if (!CLANG_TOOLSET) {
/* clang uses __builtin_*() instead */
ADD_FLAG("CFLAGS", "/DENABLE_INTSAFE_SIGNED_FUNCTIONS");
}
} }
function toolset_setup_intrinsic_cflags() function toolset_setup_intrinsic_cflags()