postgresql-jdbc.git / summary / log / commit / refs

commit    ec06d5871cd61310fbdc50e275d53565fcd3264e
Author:   Sehrope Sarkuni <sehrope@jackdb.com>
Date:     Thu Jun 11 14:12:59 2026 +0000

    fix: reject out of range and NaN values in PGInterval.setSeconds
    
    PGInterval.setSeconds validated its argument against the long range in
    microseconds, but the wholeSeconds field is an int and the cast after
    division truncated without any check. Values beyond the int range of
    whole seconds, about 68 years, silently wrapped. For example
    new PGInterval(0, 0, 0, 0, 0, 3000000000.0) produced a negative
    interval with no exception. The old error message also described a
    bound that the code never enforced on the stored field.
    
    The whole seconds value is now computed as a long and checked against
    the int range before being stored, so out of range values throw
    IllegalArgumentException instead of wrapping. NaN is rejected
    explicitly because it passed the old comparisons and Math.round mapped
    it to zero, turning NaN input into a zero interval. Infinite values are
    caught by the range check since Math.round saturates at the long
    bounds. The isNull flag is now only cleared after validation succeeds
    so a rejected value no longer mutates the object.


.../src/main/java/org/postgresql/util/PGInterval.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pgjdbc/src/main/java/org/postgresql/util/PGInterval.java b/pgjdbc/src/main/java/org/postgresql/util/PGInterval.java index 076c6be3..4e54ea26 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/PGInterval.java +++ b/pgjdbc/src/main/java/org/postgresql/util/PGInterval.java @@ -427,14 +427,18 @@ public class PGInterval extends PGobject implements Serializable, Cloneable { * @param seconds seconds to set */ public void setSeconds(double seconds) { - isNull = false; - - double micros = seconds * MICROS_IN_SECOND; - if (micros > Long.MAX_VALUE || micros < Long.MIN_VALUE) { - throw new IllegalArgumentException("Number of seconds should be within Long.MIN_VALUE/1000000...Long.MAX_VALUE/1000000"); + if (Double.isNaN(seconds)) { + throw new IllegalArgumentException("Number of seconds must not be NaN"); } - long totalMicros = Math.round(micros); - wholeSeconds = (int) (totalMicros / MICROS_IN_SECOND); + // Math.round saturates at Long.MAX_VALUE / Long.MIN_VALUE so the division below + // cannot overflow even for infinite or extremely large arguments + long totalMicros = Math.round(seconds * MICROS_IN_SECOND); + long newWholeSeconds = totalMicros / MICROS_IN_SECOND; + if (newWholeSeconds < Integer.MIN_VALUE || newWholeSeconds > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Number of whole seconds should be within Integer.MIN_VALUE...Integer.MAX_VALUE"); + } + isNull = false; + wholeSeconds = (int) newWholeSeconds; microSeconds = (int) (totalMicros % MICROS_IN_SECOND); } [parent: bab4cb85d2de]