[CBRD-27229] [Backport-10.2.19] Fix SIGFPE (server crash / SA infinite loop) on MIN / -1 in integer and NUMERIC arithmetic - #7692
Merged
jongmin-won merged 4 commits intoAug 20, 2026
Conversation
…e loop) on MIN / -1 in integer and NUMERIC arithmetic http://jira.cubrid.org/browse/CBRD-27229 Dividing the minimum value of an integer type by -1 (`INT_MIN / -1`, `BIGINT_MIN / -1`) yields a quotient that is not representable in that type, so the machine divide instruction raises a hardware divide exception (SIGFPE). In CS mode `cub_server` terminates abnormally; in SA mode the faulting instruction is re-executed forever, hanging the process. * `object_representation.h`: make `OR_CHECK_MULT_OVERFLOW` decide the `b == -1` case without a division, so `INT_MIN * -1` no longer traps inside the check macro itself. Since the macro runs after the (wrapped) multiplication, `c == a` with `b == -1` holds only for `a == 0` (fine) and `a == MIN` (overflow), so `(a) != 0 && (c) == (a)` is sufficient. The remaining `(c) / (b)` now runs only when `b != 0, -1`. Fixes all 6 call sites at once. * `query_opfunc.c`: check `OR_CHECK_*_DIV_OVERFLOW` before the divide in `qdata_divide_short/int/bigint()` and return `ER_QPROC_OVERFLOW_DIVISION`. In `qdata_divmod_dbval()` return 0 for `MIN % -1` on the `a % b` / `a MOD b` path instead of trapping. Also replace `ER_QPROC_OVERFLOW_ADDITION` with `ER_QPROC_OVERFLOW_DIVISION` for DIV overflow. * `arithmetic.c`: return 0 for `MIN % -1` in each divisor-type branch of `db_mod_int()` / `db_mod_bigint()` (functional `MOD(a, b)`, which computes at the original operand width and therefore trapped even for INTEGER). * `type_checking.c`: match the server behaviour during client-side constant folding — fold `MIN / -1` to an overflow error for `PT_DIVIDE`, and `MIN % -1` to 0 for `PT_MOD`. * `numeric_opfunc.c`: in `numeric_div()`, widen the operands to `DB_BIGINT` when the int fast path would trap, and fall back to `numeric_long_div()` when the BIGINT fast path would trap. Both produce the exact quotient and remainder, which are representable as NUMERIC(38,0), so no error is raised. `MIN % -1` is mathematically 0, so it returns 0 without an error, consistent with the existing `divisor == 0` handling on the MOD path. Clean cherry-pick of the 11.0 backport 8cdb2fc, via the 11.3 backport 7a57a2d and the 11.4 backport 816c712 (CUBRID#7689), originally CUBRID#7687. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
|
Reviews (1): Last reviewed commit: "[CBRD-27229] [Backport-10.2.19] Fix SIGF..." | Re-trigger Greptile |
beyondykk9
approved these changes
Aug 18, 2026
…t dividing http://jira.cubrid.org/browse/CBRD-27255 정수 산술의 SIGFPE 문제를 함께 내보내기 위해 CBRD-27229 백포트와 같은 브랜치에 묶어 반영한다. `OR_CHECK_MULT_OVERFLOW ()` 는 이미 래핑된 곱을 나누어 오버플로를 판정한다. 그래서 `INT_MIN * -1` 을 검사하면 `INT_MIN / -1` 이 실행되고, 몫 2147483648 이 int 범위를 벗어나 하드웨어 나눗셈 예외가 발생했다. 오버플로를 검사하려던 코드가 오버플로로 죽는 셈이다. 앞선 CBRD-27229 커밋이 `b == -1` 을 나눗셈 없이 판정하도록 바꿔 트랩 자체는 이미 막았고, 이 커밋은 곱셈 경로에서 나눗셈을 아예 없앤다. * `query_opfunc.c`: `qdata_multiply_short ()` / `qdata_multiply_int ()` / `qdata_multiply_bigint ()` 가 `__builtin_mul_overflow ()` 로 판정한다. 나눗셈 대신 하드웨어 오버플로 플래그를 읽으므로 트랩이 발생할 여지가 없다. * `type_checking.c`: `pt_evaluate_db_value_expr ()` 의 SHORT / INTEGER / BIGINT 상수 폴딩 분기도 동일하게 바꾼다. 검사를 다시 곱셈으로 되돌리지 못하게 막으려고 두었던 `volatile` 지역 변수는 나눗셈과 함께 사라진다. 피연산자가 컴파일 시점 상수가 아니므로 나눗셈이 없어진 뒤에는 필요하지 않다. 오버플로 판정 결과는 기존 검사가 살아남던 모든 입력에서 같다. 래핑된 곱 `w = a * b - k * 2^N` (k != 0) 은 `|k * 2^N|` 이 나눗셈이 흡수할 수 있는 어떤 `|b|` 보다 크므로 `w / b == a` 를 만족할 수 없고, 범위에 들어간 곱은 정확히 나누어떨어진다. 이 브랜치에 들어있는 매크로와 직접 비교해 SHORT 준전수 스윕 (피승수 전수 × 승수 37 간격), INTEGER 경계값 전조합, INTEGER · BIGINT 무작위 각 400 만 쌍, 총 1 억 2413 만 건에서 판정과 결과값 불일치 0 건을 확인했다. 부수적으로 곱셈마다 하드웨어 나눗셈 1 회와 volatile 로 인한 스택 왕복이 사라진다. `__builtin_mul_overflow ()` 는 GCC 5.0 이상에서 제공된다. 10.2 의 CMakeLists 는 GCC 4.4.7 이상을 허용하므로, 4.x 툴체인으로 빌드하는 환경이 남아 있다면 별도 대응이 필요하다. 이 커밋은 GCC 8.5.0 debug 빌드로 확인했다. CUBRID#7722 수동 백포트. 11.4 1e92dde / 11.3 4b2be8c / 11.0 e321af9 와 내용이 같고, 대상 함수들이 develop 과 동일해 변형 없이 적용된다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…k portable to MSVC http://jira.cubrid.org/browse/CBRD-27255 `__builtin_mul_overflow ()` 는 GCC / clang 확장이라 MSVC 에서 `error C3861: '__builtin_mul_overflow': identifier not found` 로 컴파일이 실패한다. 11.4 의 CircleCI 에는 Windows 잡 (`build-windows`, windows-server-2019, MSVC 2017) 이 있어 실제로 이 에러로 빌드가 깨졌다. 10.2 / 11.0 / 11.3 의 CI 에는 Windows 잡이 없어 드러나지 않았을 뿐, 코드 이식성은 동일하게 깨진 상태였다. `object_representation.h` 에 `OR_MULT_OVERFLOW ()` 를 두고 컴파일러별로 갈라 놓는다. * GCC / clang: `__builtin_mul_overflow ()` 를 그대로 사용한다. 하드웨어 오버플로 플래그로 판정하므로 나눗셈이 없다. * 그 외 (MSVC): 곱한 뒤 `OR_CHECK_MULT_OVERFLOW ()` 로 판정한다. 이 매크로는 CBRD-27229 에서 `b == -1` 을 나눗셈 없이 판정하도록 고쳤으므로 이 경로에도 트랩 조건이 없다. 호출부 6 곳 (`qdata_multiply_short ()` / `qdata_multiply_int ()` / `qdata_multiply_bigint ()`, `pt_evaluate_db_value_expr ()` 의 SHORT / INTEGER / BIGINT 상수 폴딩) 은 매크로 이름만 바뀐다. 두 경로의 판정과 결과값은 동일하다. MSVC 는 `.c` 를 C++ 로 컴파일하므로 C 와 C++ 양쪽으로 대조했고, SHORT 준전수 스윕 (피승수 전수 × 승수 37 간격), INTEGER 경계값 전조합, INTEGER · BIGINT 무작위 각 400 만 쌍, 총 1 억 2413 만 건에서 불일치 0 건이다. GCC 8.5.0 debug 빌드로 확인했다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
http://jira.cubrid.org/browse/CBRD-27229
Purpose
정수 타입의 최솟값을 -1로 나누면(
INT_MIN / -1,BIGINT_MIN / -1) 몫이 해당 타입으로 표현 불가능해 machine divide 명령에서 하드웨어 divide 예외(SIGFPE)가 발생합니다.CS 모드에서는
cub_server가 비정상 종료되고, SA 모드에서는 폴트가 발생한 명령을 반복 실행하며 무한 루프에 빠집니다.결함은 세 가지 형태로 존재합니다.
a / b,a % b,MOD(a, b): MIN / -1 오버플로 검사 없이 machine divide를 실행a * b: 검사 매크로OR_CHECK_MULT_OVERFLOW자체가 나눗셈((c) / (b))을 수행하므로,INT_MIN * -1검증 도중 매크로 내부에서 트랩 발생numeric_div()가 양쪽 피연산자가 int/BIGINT에 들어가면 machine divide 빠른 경로를 타므로, INT_MIN·BIGINT_MIN에 해당하는 NUMERIC 값에서 트랩 발생SHORT는 정수 승격 덕분에 트랩은 없지만,
-32768 / -1이-32768로 잘려 반환되는 값 오류가 있었습니다.Implementation
object_representation.h:OR_CHECK_MULT_OVERFLOW가b == -1케이스를 나눗셈 없이 판정하도록 수정.b == -1일 때c == a가 성립하는 경우는a == 0(정상)과a == MIN(오버플로)뿐이라(a) != 0 && (c) == (a)로 충분합니다.(c) / (b)는b != 0, -1일 때만 실행되어 트랩 조건이 없습니다.__builtin_mul_overflow_p와 4,800만 케이스 대조, 불일치 0건)query_opfunc.cqdata_divide_short/int/bigint(): 나눗셈 전에OR_CHECK_*_DIV_OVERFLOW검사 후ER_QPROC_OVERFLOW_DIVISION반환qdata_divmod_dbval():a % b/a MOD b경로에서 MIN % -1은 트랩 대신 0을 반환.DB_BIGINT로 확장되어 있어 실제로 트랩 가능한 것은 BIGINT 케이스뿐입니다.ER_QPROC_OVERFLOW_ADDITION에서ER_QPROC_OVERFLOW_DIVISION으로 교체arithmetic.c:db_mod_int()/db_mod_bigint()(함수형MOD(a, b), 원래 피연산자 폭으로 계산)의 divisor 타입별 분기에서 MIN % -1 → 0 반환type_checking.c(클라이언트 상수 폴딩):PT_DIVIDE는 MIN / -1을 오버플로 에러로,PT_MOD는 MIN % -1을 0으로 폴딩하여 서버 동작과 일치시킴numeric_opfunc.c(numeric_div()): int 빠른 경로가 트랩 조건이면 피연산자를DB_BIGINT로 넓혀 나눗셈, BIGINT 빠른 경로가 트랩 조건이면numeric_long_div()로 우회.Remarks
a % b는 MOD 토큰으로 렉싱되어a MOD b와 동일하게qdata_divmod_dbval()에서DB_BIGINT폭으로 계산되므로 INTEGER 피연산자는 원래도 안전했습니다.MOD(a, b)는 원래 폭으로 계산하므로 INTEGER에서도 트랩이 발생했습니다.MIN % -1은 수학적으로 0이므로 에러 없이 0을 반환하며, 이는 MOD 경로의 기존divisor == 0처리 방식과 일관됩니다.