From 9f5f155e6639b4feff177a56f3949265ecbbc688 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 13:29:43 +0000 Subject: [PATCH] fix: avoid integer overflow in `stats/base/dists/hypergeometric` Propagates fix from 493166d37 ("fix: perform support checks before integer narrowing") to sibling packages with the same int32 support-bound arithmetic. The expression `n+K-N` in the C implementations of `pmf`, `logpmf`, and `quantile` was evaluated in int32 arithmetic before conversion to double, overflowing (undefined behavior) for in-domain inputs where `n+K` exceeds the int32 range. Mirror the fixed `cdf` implementation by computing support bounds with double intermediates; in `quantile`, additionally convert the loop variable and bounds to doubles. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_015CyugoNH33WVr8ghD2PhZr --- .../dists/hypergeometric/logpmf/src/main.c | 10 ++++-- .../base/dists/hypergeometric/pmf/src/main.c | 10 ++++-- .../dists/hypergeometric/quantile/src/main.c | 33 ++++++++++--------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c index 887a0c34f430..10934a62a762 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c +++ b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c @@ -43,13 +43,19 @@ double stdlib_base_dists_hypergeometric_logpmf( const double x, const int32_t N, double lnum; double maxs; double mins; + double dn; + double dK; + double dN; if ( stdlib_base_is_nan( x ) || N < 0 || K < 0 || n < 0 || K > N || n > N ) { return 0.0/0.0; // NaN } - mins = stdlib_base_max( 0, n+K-N ); - maxs = stdlib_base_min( K, n ); + dn = (double)n; + dN = (double)N; + dK = (double)K; + mins = stdlib_base_max( 0.0, dn+dK-dN ); + maxs = stdlib_base_min( dK, dn ); if ( stdlib_base_is_nonnegative_integer( x ) && mins <= x && x <= maxs ) { lnum = stdlib_base_factorialln( n ) + stdlib_base_factorialln( K ) + stdlib_base_factorialln( N-n ) + stdlib_base_factorialln( N-K ); diff --git a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/pmf/src/main.c b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/pmf/src/main.c index a131094db848..69b4852701d0 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/pmf/src/main.c +++ b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/pmf/src/main.c @@ -44,13 +44,19 @@ double stdlib_base_dists_hypergeometric_pmf( const double x, const int32_t N, co double lpmf; double maxs; double mins; + double dn; + double dK; + double dN; if ( stdlib_base_is_nan( x ) || N < 0 || K < 0 || n < 0 || K > N || n > N ) { return 0.0/0.0; // NaN } - mins = stdlib_base_max( 0, n+K-N ); - maxs = stdlib_base_min( K, n ); + dn = (double)n; + dN = (double)N; + dK = (double)K; + mins = stdlib_base_max( 0.0, dn+dK-dN ); + maxs = stdlib_base_min( dK, dn ); if ( stdlib_base_is_nonnegative_integer( x ) && mins <= x && x <= maxs ) { lnum = stdlib_base_factorialln( n ) + stdlib_base_factorialln( K ) + stdlib_base_factorialln( N-n ) + stdlib_base_factorialln( N-K ); diff --git a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/quantile/src/main.c b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/quantile/src/main.c index 7f05d02f473b..c83466904001 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/quantile/src/main.c +++ b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/quantile/src/main.c @@ -36,16 +36,14 @@ * double y = stdlib_base_dists_hypergeometric_quantile( 0.4, 40, 20, 10 ); * // returns 5 */ -double stdlib_base_dists_hypergeometric_quantile( - const double p, - const int32_t N, - const int32_t K, - const int32_t n -) { +double stdlib_base_dists_hypergeometric_quantile( const double p, const int32_t N, const int32_t K, const int32_t n ) { + double upper; + double lower; double prob; - int32_t upper; - int32_t lower; - int32_t x; + double dn; + double dK; + double dN; + double x; if ( stdlib_base_is_nan( p ) || @@ -60,23 +58,26 @@ double stdlib_base_dists_hypergeometric_quantile( return 0.0 / 0.0; } - lower = stdlib_base_max( 0, n + K - N ); - upper = stdlib_base_min( n, K ); + dn = (double)n; + dN = (double)N; + dK = (double)K; + lower = stdlib_base_max( 0.0, dn+dK-dN ); + upper = stdlib_base_min( dn, dK ); if ( p == 0.0 ) { - return (double)lower; + return lower; } if ( p == 1.0 ) { - return (double)upper; + return upper; } x = lower; while ( x <= upper ) { - prob = stdlib_base_dists_hypergeometric_cdf( (double)x, N, K, n ); + prob = stdlib_base_dists_hypergeometric_cdf( x, N, K, n ); if ( prob > p ) { break; } - x += 1; + x += 1.0; } - return (double)x; + return x; }