[CBRD-27255] Detect multiplication overflow without dividing - #7722
Closed
soheejung-cs wants to merge 1 commit into
Closed
soheejung-cs wants to merge 1 commit into
soheejung-cs wants to merge 1 commit into
Conversation
SELECT CAST (-2147483648 AS INTEGER) * CAST (-1 AS INTEGER) kills cub_server with SIGFPE, and the BIGINT form does the same. The overflow check is what crashes: OR_CHECK_MULT_OVERFLOW () verifies a product by dividing it back, so it computes the wrapped result first and then evaluates INT_MIN / -1, whose quotient is not representable. The integer multiply sites now ask the compiler instead. __builtin_mul_overflow () reports overflow from the flags without a division, so the trapping quotient never happens, and the volatile locals that existed only to stop the optimizer from turning the check back into a multiplication are no longer needed. Every multiply site that used the macro is converted, in the interpreted path (qdata_multiply_short/int/bigint) and in the parser's constant folding (pt_fold_arith on SHORT/INTEGER/BIGINT). SHORT never trapped -- its operands promote to int, so SHRT_MIN / -1 is representable -- but it carried the same division and is converted with the others. Detection is unchanged for every input the old check survived: a wrapped product w = a * b - k * 2^N with k != 0 always fails w / b == a, since |k * 2^N| exceeds any |b| the division could absorb, and a product that did fit divides back exactly. Verified over the SHORT/INTEGER boundary values and 40M random INTEGER and BIGINT pairs with no disagreement. Verified: the two statements above now return ER_QPROC_OVERFLOW_MULTIPLICATION with the server still running; ordinary multiplications keep their results; TPC-H SF10 22/22 byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MM9r6xzNDx7MM6hixiQc4Q # 제목: 변경 요약 (50자 이내) (refactor, hotfix, feature) # 본문: 변경 사항에 대한 자세한 설명 # - 주요 변경 사항 1 # - 주요 변경 사항 2 # 참고: 이 라인 아래의 내용은 커밋 메시지에서 제거됩니다.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
✅ TC Merge Gate — Merge AllowedAll TC PRs are merged, closed, or not present. TC Repositories & Branches:
|
🧪 TC Test Environment ReadyCircleCI Testing:
TC Repositories & Branches:
Next Steps:
|
Contributor
|
Reviews (1): Last reviewed commit: "[CBRD-27255] Detect multiplication overf..." | Re-trigger Greptile |
| short stmp; | ||
|
|
||
| if (OR_CHECK_MULT_OVERFLOW (s1, s2, stmp)) | ||
| if (__builtin_mul_overflow (s1, s2, &stmp)) |
Contributor
|
🗑️ TC Branch Finalized for Engine PR was closed (not merged). Cleanup Results:
TC base branch is ready for the next PR. |
|
🗑️ TC Branch Finalized for Engine PR was closed (not merged). Cleanup Results:
TC base branch is ready for the next PR. |
jongmin-won
added a commit
to jongmin-won/cubrid
that referenced
this pull request
Aug 19, 2026
http://jira.cubrid.org/browse/CBRD-27255 Bundled into this CBRD-27229 backport branch so that both integer arithmetic SIGFPE issues ship together. `OR_CHECK_MULT_OVERFLOW ()` decides overflow by dividing the already wrapped product, so checking `INT_MIN * -1` executed `INT_MIN / -1` and the machine divide instruction raised a hardware divide exception: the code meant to check for overflow died of overflow. The preceding CBRD-27229 commit stopped the trap by deciding the `b == -1` case without dividing; this commit removes the division from the multiplication path altogether. * `query_opfunc.c`: `qdata_multiply_short ()` / `qdata_multiply_int ()` / `qdata_multiply_bigint ()` decide with `__builtin_mul_overflow ()`, which reads the hardware overflow flag instead of dividing. * `type_checking.c`: same for the SHORT / INTEGER / BIGINT constant folding branches of `pt_evaluate_db_value_expr ()`. The `volatile` locals that existed only to keep the optimizer from turning the division check back into a multiplication go away with the division. The verdict is unchanged on every input the old check survived: a wrapped product `w = a * b - k * 2^N` (k != 0) cannot satisfy `w / b == a`, because `|k * 2^N|` exceeds any `|b|` the division could absorb, while an in-range product divides exactly. Compared against the macro as this branch ships it over an exhaustive SHORT sweep, all INTEGER boundary pairs, and 4 million random pairs each for INTEGER and BIGINT: 124 million comparisons, zero verdict or value mismatches. Multiplication also loses one hardware division and the volatile stack round-trip per operation. Manual backport of CUBRID#7722 (closed on develop, patched here as part of this bundle). The multiplication sites were identical to develop, so no adaptation was needed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jongmin-won
added a commit
to jongmin-won/cubrid
that referenced
this pull request
Aug 19, 2026
… 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 로 인한 스택 왕복이 사라진다. CUBRID#7722 수동 백포트. 11.4 백포트 1e92dde 와 내용이 같고, 대상 함수들이 develop 과 동일해 변형 없이 적용된다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jongmin-won
added a commit
to jongmin-won/cubrid
that referenced
this pull request
Aug 19, 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 로 인한 스택 왕복이 사라진다. CUBRID#7722 수동 백포트. 11.4 1e92dde / 11.3 4b2be8c 와 내용이 같고, 대상 함수들이 develop 과 동일해 변형 없이 적용된다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jongmin-won
added a commit
to jongmin-won/cubrid
that referenced
this pull request
Aug 19, 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>
jongmin-won
added a commit
that referenced
this pull request
Aug 20, 2026
…e loop) on MIN / -1 in integer and NUMERIC arithmetic (#7692) http://jira.cubrid.org/browse/CBRD-27229 http://jira.cubrid.org/browse/CBRD-27255 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. It happens on `a / b`, `a % b`, `MOD(a, b)`, `a * b` (the division inside the overflow check macro), and NUMERIC (the machine divide fast path of `numeric_div()`). The division paths now check for overflow before dividing and return `ER_QPROC_OVERFLOW_DIVISION`, and `MIN % -1` returns 0. For NUMERIC, the operands are widened or the computation falls back to `numeric_long_div()`, which returns the exact quotient without an error. For multiplication, `OR_CHECK_MULT_OVERFLOW` now decides the `b == -1` case without dividing, which fixes all 6 call sites at once. Client-side constant folding was aligned with the server behaviour, and DIV overflow is now reported in the division context instead of the addition context. The fix for CBRD-27255 (#7722) is included as well: the multiplication overflow check moves to `__builtin_mul_overflow ()`, removing the division from the multiplication path altogether. Please refer to the PRs and the Jira issues for details.
jongmin-won
added a commit
that referenced
this pull request
Aug 20, 2026
…e loop) on MIN / -1 in integer and NUMERIC arithmetic (#7691) http://jira.cubrid.org/browse/CBRD-27229 http://jira.cubrid.org/browse/CBRD-27255 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. It happens on `a / b`, `a % b`, `MOD(a, b)`, `a * b` (the division inside the overflow check macro), and NUMERIC (the machine divide fast path of `numeric_div()`). The division paths now check for overflow before dividing and return `ER_QPROC_OVERFLOW_DIVISION`, and `MIN % -1` returns 0. For NUMERIC, the operands are widened or the computation falls back to `numeric_long_div()`, which returns the exact quotient without an error. For multiplication, `OR_CHECK_MULT_OVERFLOW` now decides the `b == -1` case without dividing, which fixes all 6 call sites at once. Client-side constant folding was aligned with the server behaviour, and DIV overflow is now reported in the division context instead of the addition context. The fix for CBRD-27255 (#7722) is included as well: the multiplication overflow check moves to `__builtin_mul_overflow ()`, removing the division from the multiplication path altogether. Please refer to the PRs and the Jira issues for details.
jongmin-won
added a commit
that referenced
this pull request
Aug 20, 2026
… loop) on MIN / -1 in integer and NUMERIC arithmetic (#7690) http://jira.cubrid.org/browse/CBRD-27229 http://jira.cubrid.org/browse/CBRD-27255 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. It happens on `a / b`, `a % b`, `MOD(a, b)`, `a * b` (the division inside the overflow check macro), and NUMERIC (the machine divide fast path of `numeric_div()`). The division paths now check for overflow before dividing and return `ER_QPROC_OVERFLOW_DIVISION`, and `MIN % -1` returns 0. For NUMERIC, the operands are widened or the computation falls back to `numeric_long_div()`, which returns the exact quotient without an error. For multiplication, `OR_CHECK_MULT_OVERFLOW` now decides the `b == -1` case without dividing, which fixes all 6 call sites at once. Client-side constant folding was aligned with the server behaviour, and DIV overflow is now reported in the division context instead of the addition context. The fix for CBRD-27255 (#7722) is included as well: the multiplication overflow check moves to `__builtin_mul_overflow ()`, removing the division from the multiplication path altogether. Please refer to the PRs and the Jira issues for details.
jongmin-won
added a commit
that referenced
this pull request
Aug 20, 2026
… loop) on MIN / -1 in integer and NUMERIC arithmetic (#7689) http://jira.cubrid.org/browse/CBRD-27229 http://jira.cubrid.org/browse/CBRD-27255 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. It happens on `a / b`, `a % b`, `MOD(a, b)`, `a * b` (the division inside the overflow check macro), and NUMERIC (the machine divide fast path of `numeric_div()`). The division paths now check for overflow before dividing and return `ER_QPROC_OVERFLOW_DIVISION`, and `MIN % -1` returns 0. For NUMERIC, the operands are widened or the computation falls back to `numeric_long_div()`, which returns the exact quotient without an error. For multiplication, `OR_CHECK_MULT_OVERFLOW` now decides the `b == -1` case without dividing, which fixes all 6 call sites at once. Client-side constant folding was aligned with the server behaviour, and DIV overflow is now reported in the division context instead of the addition context. The fix for CBRD-27255 (#7722) is included as well: the multiplication overflow check moves to `__builtin_mul_overflow ()`, removing the division from the multiplication path altogether. Please refer to the PRs and the Jira issues for details.
jongmin-won
added a commit
that referenced
this pull request
Aug 20, 2026
… in integer and NUMERIC arithmetic (#7687) http://jira.cubrid.org/browse/CBRD-27229 http://jira.cubrid.org/browse/CBRD-27255 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. It happens on `a / b`, `a % b`, `MOD(a, b)`, `a * b` (the division inside the overflow check macro), and NUMERIC (the machine divide fast path of `numeric_div()`). The division paths now check for overflow before dividing and return `ER_QPROC_OVERFLOW_DIVISION`, and `MIN % -1` returns 0. For NUMERIC, the operands are widened or the computation falls back to `numeric_long_div()`, which returns the exact quotient without an error. For multiplication, `OR_CHECK_MULT_OVERFLOW` now decides the `b == -1` case without dividing, which fixes all 6 call sites at once. Client-side constant folding was aligned with the server behaviour, and DIV overflow is now reported in the division context instead of the addition context. The fix for CBRD-27255 (#7722) is included as well: the multiplication overflow check moves to `__builtin_mul_overflow ()`, removing the division from the multiplication path altogether. Please refer to the PRs and the Jira issues for details.
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-27255
문제
아래 한 문장으로 cub_server 가 SIGFPE 로 종료됩니다. BIGINT 도 동형입니다.
클라이언트에는 "Your transaction has been aborted by the system due to server failure or mode change." 만 보입니다. upstream/develop (198b42a) 릴리스 빌드에서 재현했습니다.
원인
곱셈 오버플로 검사가 나눗셈으로 이루어집니다.
호출부는 곱을 먼저 계산해 래핑된 값을 얻은 뒤 이 매크로를 적용합니다.
INT_MIN * -1은 래핑되어INT_MIN이 되고, 매크로가INT_MIN / -1을 실행합니다. 몫 2147483648 이 int 범위를 벗어나 x86-64 의 idiv 가 #DE 를 발생시킵니다. 즉 오버플로를 검사하려던 코드가 오버플로로 죽습니다.수정
정수 곱셈 지점을
__builtin_mul_overflow ()로 바꿉니다. 플래그로 판정하므로 나눗셈이 사라지고, 따라서 트랩이 발생할 여지가 없어집니다. 검사를 다시 곱셈으로 되돌리지 못하게 막으려고 두었던volatile지역 변수도 함께 제거됩니다.매크로를 쓰던 곱셈 지점을 모두 전환했습니다.
qdata_multiply_short/qdata_multiply_int/qdata_multiply_bigintpt_fold_arith의 SHORT / INTEGER / BIGINT 상수 폴딩SHORT 는 트랩이 나지 않습니다. 피연산자가 int 로 승격되어
SHRT_MIN / -1이 표현 가능하기 때문입니다. 다만 같은 나눗셈 비용을 지고 있어 함께 전환했습니다.판정 동일성
오버플로 판정 결과는 기존 검사가 살아남던 모든 입력에서 같습니다. 래핑된 곱
w = a * b - k * 2^N(k != 0) 은w / b == a를 만족할 수 없습니다.|k * 2^N|이 나눗셈이 흡수할 수 있는 어떤|b|보다 크기 때문입니다. 반대로 범위에 들어간 곱은 정확히 나누어떨어집니다.SHORT/INTEGER 경계값 전수와 INTEGER·BIGINT 무작위 4천만 쌍에서 판정과 결과값 불일치 0 건을 확인했습니다.
검증
ER_QPROC_OVERFLOW_MULTIPLICATION을 반환합니다.7 * 6,-3 * -4,100000 * 100000등).2000000000 * 2,-32768 * -1SHORT).부수적으로 곱셈마다 하드웨어 나눗셈 1 회와 volatile 로 인한 스택 왕복이 사라집니다.