Skip to content

Sometimes, certain illnesses can be cured #299

Description

@m4tosm4

How We Found It

The computation involved converting values from a high-precision intermediate representation into GMP arbitrary-precision integers, then using those integers in further computation. The intermediate values routinely reach magnitudes of 3-4 billion — well beyond the 32-bit signed range.

We isolated the bug by forcing the computation to run exactly once (bypassing its internal retry loop) and comparing the full output byte-by-byte across platforms. The first portion matched perfectly. The divergence started at exactly the point where values were converted to GMP integers via mpz_set_si:

Linux: g[0] = -3784023924 (correct)
Windows: g[0] = -2147483648 (wrong - INT32_MIN)

The Official Workaround

GMP’s recommended solution is mpz_import and mpz_export, which operate on raw byte arrays with explicit size parameters:

static inline void mpz_set_int64(mpz_t rop, int64_t op) {
if (op >= 0) {
uint64_t u = (uint64_t)op;
mpz_import(rop, 1, -1, sizeof(uint64_t), 0, 0, &u);
} else {
uint64_t u = (uint64_t)(-op);
mpz_import(rop, 1, -1, sizeof(uint64_t), 0, 0, &u);
mpz_neg(rop, rop);
}
}

static inline int64_t mpz_get_int64(const mpz_t op) {
uint64_t u = 0;
mpz_export(&u, NULL, -1, sizeof(uint64_t), 0, 0, op);
if (mpz_sgn(op) < 0)
return -(int64_t)u;
return (int64_t)u;
}

Code taken from:
https://www.raykzhao.phd/2026/03/21/gmp-long-type-bug.html

:-)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions