Skip to content

Instantly share code, notes, and snippets.

@iskakaushik
Created October 30, 2025 02:13
Show Gist options
  • Select an option

  • Save iskakaushik/7de6192a075916c78166d7cbcdf1ae9c to your computer and use it in GitHub Desktop.

Select an option

Save iskakaushik/7de6192a075916c78166d7cbcdf1ae9c to your computer and use it in GitHub Desktop.
func TestNumericCodecIssue2415(t *testing.T) {
// Direct binary decoding tests with problematic binary format
// These test cases use crafted binary data with large weight and small dscale values
// that caused integer overflow and excessive loops in the old code
t.Run("binary decode large weight 5462 small dscale 1", func(t *testing.T) {
// Binary format: ndigits=1, weight=5462, sign=0, dscale=1
// Digit: 1
// Old code: dscale (1) < fracDecimalDigits (4), causing divCount=3, exp goes from 21852 to 21855
// This creates a number like 10000...000 with 21850+ zeros
src := []byte{
0x00, 0x01, // ndigits = 1
0x15, 0x56, // weight = 5462
0x00, 0x00, // sign = 0 (positive)
0x00, 0x01, // dscale = 1
0x00, 0x01, // digit = 1
}
var n pgtype.Numeric
scanner := pgtype.NumericCodec{}
plan := scanner.PlanScan(nil, pgtype.NumericOID, pgtype.BinaryFormatCode, &n)
require.NotNil(t, plan)
err := plan.Scan(src, &n)
require.NoError(t, err)
require.True(t, n.Valid)
require.Equal(t, big.NewInt(1), n.Int)
require.Equal(t, int32(21848), n.Exp) // (5462 - 1 + 1) * 4 = 21848
})
t.Run("binary decode zero with large weight", func(t *testing.T) {
// Binary format: ndigits=1, weight=5000, sign=0, dscale=1
// Digit 0 with positive exp would infinite loop in old code without the zero guard
src := []byte{
0x00, 0x01, // ndigits = 1
0x13, 0x88, // weight = 5000
0x00, 0x00, // sign = 0
0x00, 0x01, // dscale = 1
0x00, 0x00, // digit = 0
}
var n pgtype.Numeric
scanner := pgtype.NumericCodec{}
plan := scanner.PlanScan(nil, pgtype.NumericOID, pgtype.BinaryFormatCode, &n)
require.NotNil(t, plan)
err := plan.Scan(src, &n)
require.NoError(t, err)
require.True(t, n.Valid)
require.Equal(t, big.NewInt(0), n.Int)
// With fix: zero guard prevents infinite loop, exp stays at (5000-1+1)*4 = 20000
// 0 * 10^20000 is still 0, so exp value doesn't matter for zero
require.Equal(t, int32(20000), n.Exp)
})
t.Run("binary decode weight 5462 with dscale 2", func(t *testing.T) {
// Binary format: ndigits=2, weight=5462, sign=0, dscale=2
// Tests multiple digits with large weight
src := []byte{
0x00, 0x02, // ndigits = 2
0x15, 0x56, // weight = 5462
0x00, 0x00, // sign = 0
0x00, 0x02, // dscale = 2
0x00, 0x7B, // digit = 123
0x0D, 0xE5, // digit = 3557
}
var n pgtype.Numeric
scanner := pgtype.NumericCodec{}
plan := scanner.PlanScan(nil, pgtype.NumericOID, pgtype.BinaryFormatCode, &n)
require.NotNil(t, plan)
err := plan.Scan(src, &n)
require.NoError(t, err)
require.True(t, n.Valid)
// 123 * 10000 + 3557 = 1233557
require.Equal(t, big.NewInt(1233557), n.Int)
})
t.Run("binary decode maximum safe weight", func(t *testing.T) {
// Binary format: ndigits=1, weight=32767 (max int16), sign=0, dscale=1
// With dscale=1, this would cause massive overflow in old code
src := []byte{
0x00, 0x01, // ndigits = 1
0x7F, 0xFF, // weight = 32767 (max int16)
0x00, 0x00, // sign = 0
0x00, 0x01, // dscale = 1
0x00, 0x01, // digit = 1
}
var n pgtype.Numeric
scanner := pgtype.NumericCodec{}
plan := scanner.PlanScan(nil, pgtype.NumericOID, pgtype.BinaryFormatCode, &n)
require.NotNil(t, plan)
err := plan.Scan(src, &n)
require.NoError(t, err)
require.True(t, n.Valid)
require.Equal(t, big.NewInt(1), n.Int)
require.Equal(t, int32(131068), n.Exp) // (32767 - 1 + 1) * 4 = 131068
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment