Created
October 30, 2025 02:13
-
-
Save iskakaushik/7de6192a075916c78166d7cbcdf1ae9c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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