Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ var TrimTrailingZeros = true
// digits are unknown. With this set to true, that number would be expressed as "1.2E3" instead.
var UseScientificNotation = false

// ExpMaxLimit limits the maximum allowed exponent when parsing or operating on decimals.
// Extremely large exponents can cause memory leaks/OOM panics due to how math/big.Int allocates memory.
// By default, this is set to math.MaxInt32 for backwards compatibility, but it's strongly recommended
// to set this to a lower bound (e.g., 10000) for APIs that accept user input.
var ExpMaxLimit = int32(math.MaxInt32)

// ExpMinLimit limits the minimum allowed exponent when parsing decimals.
var ExpMinLimit = int32(math.MinInt32)
// ExpMaxIterations specifies the maximum number of iterations needed to calculate
// precise natural exponent value using ExpHullAbrham method.
var ExpMaxIterations = 1000
Expand Down Expand Up @@ -269,6 +277,10 @@ func NewFromString(value string) (Decimal, error) {
return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", originalInput)
}

if exp < int64(ExpMinLimit) || exp > int64(ExpMaxLimit) {
return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent out of bounds", originalInput)
}

return Decimal{
value: dValue,
exp: int32(exp),
Expand Down
30 changes: 30 additions & 0 deletions decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3970,3 +3970,33 @@ func ExampleNewFromFloat() {
//0.123123123123123
//-10000000000000
}

func TestNewFromStringExpLimit(t *testing.T) {
oldMax := ExpMaxLimit
oldMin := ExpMinLimit
defer func() {
ExpMaxLimit = oldMax
ExpMinLimit = oldMin
}()

ExpMaxLimit = 10000
ExpMinLimit = -10000

// Should pass
_, err := NewFromString("1e10000")
if err != nil {
t.Fatalf("expected 1e10000 to pass, got %v", err)
}

// Should fail (exceeds max)
_, err = NewFromString("1e10001")
if err == nil {
t.Fatal("expected 1e10001 to fail")
}

// Should fail (exceeds min)
_, err = NewFromString("1e-10001")
if err == nil {
t.Fatal("expected 1e-10001 to fail")
}
}