Skip to content

perf: limit memory allocation during Vector deserialization#759

Merged
ivokub merged 29 commits intomasterfrom
perf/vector-readfrom-len
Oct 23, 2025
Merged

perf: limit memory allocation during Vector deserialization#759
ivokub merged 29 commits intomasterfrom
perf/vector-readfrom-len

Conversation

@ivokub
Copy link
Copy Markdown
Collaborator

@ivokub ivokub commented Oct 21, 2025

Description

NB! Should be backported to 0.18.0 and 0.19.0.

We previously allocated the whole Vector (internally []Element) after reading the number of elements in the serialized header. However, as we read the input from a reader we actually don't know if the input really holds that much elements. This PR allocates smaller (up to 4GB) batches from memory.

Additionally, we now avoid allocating memory in case the Vector capacity is large enough to store the elements.

There is performance regression in case of large inputs when we have to allocate several times but this can be mitigated by preallocating the slices.

Added Vector.Equal method for vector equality check.

Benchmarking fr_bn254.Vector implementation between old and new:

goos: linux
goarch: amd64
pkg: github.com/consensys/gnark-crypto/ecc/bn254/fr
cpu: AMD Ryzen 9 7940HS w/ Radeon 780M Graphics     
                                        │ old-all.txt  │             new-all.txt             │
                                        │    sec/op    │    sec/op     vs base               │
VectorReadFrom/size=5/prealloc-16         934.8n ± 31%   745.8n ± 12%  -20.21% (p=0.002 n=6)
VectorReadFrom/size=5/empty-16            927.3n ±  4%   750.6n ±  0%  -19.06% (p=0.002 n=6)
VectorReadFrom/size=10/prealloc-16        28.28µ ±  3%   22.56µ ±  1%  -20.21% (p=0.002 n=6)
VectorReadFrom/size=10/empty-16           27.98µ ±  2%   22.65µ ±  1%  -19.05% (p=0.002 n=6)
VectorReadFrom/size=15/prealloc-16        826.5µ ±  2%   723.6µ ±  1%  -12.44% (p=0.002 n=6)
VectorReadFrom/size=15/empty-16           848.6µ ±  2%   726.7µ ±  0%  -14.37% (p=0.002 n=6)
VectorReadFrom/size=20/prealloc-16        23.48m ±  2%   23.35m ±  1%        ~ (p=0.240 n=6)
VectorReadFrom/size=20/empty-16           23.44m ±  1%   23.27m ±  0%   -0.73% (p=0.004 n=6)
VectorReadFrom/size=24/prealloc-16        416.9m ±  9%   370.8m ±  0%  -11.06% (p=0.002 n=6)
VectorReadFrom/size=24/empty-16           368.2m ±  4%   374.8m ±  0%        ~ (p=0.065 n=6)
VectorReadFrom/size=28/prealloc-16         5.899 ±  2%    5.947 ±  1%        ~ (p=0.132 n=6)
VectorReadFrom/size=28/empty-16            5.831 ±  1%    6.220 ± 17%   +6.68% (p=0.002 n=6)
VectorAsyncReadFrom/size=5/prealloc-16    4.002µ ±  1%   3.576µ ±  1%  -10.65% (p=0.002 n=6)
VectorAsyncReadFrom/size=5/empty-16       3.978µ ±  3%   3.537µ ±  2%  -11.10% (p=0.002 n=6)
VectorAsyncReadFrom/size=10/prealloc-16   25.50µ ±  3%   15.51µ ±  2%  -39.19% (p=0.002 n=6)
VectorAsyncReadFrom/size=10/empty-16      25.43µ ±  2%   15.51µ ±  1%  -38.99% (p=0.002 n=6)
VectorAsyncReadFrom/size=15/prealloc-16   211.2µ ±  2%   155.2µ ±  2%  -26.52% (p=0.002 n=6)
VectorAsyncReadFrom/size=15/empty-16      214.3µ ±  5%   155.9µ ±  3%  -27.25% (p=0.002 n=6)
VectorAsyncReadFrom/size=20/prealloc-16   5.383m ±  4%   4.558m ±  2%  -15.32% (p=0.002 n=6)
VectorAsyncReadFrom/size=20/empty-16      5.441m ±  2%   4.554m ±  1%  -16.30% (p=0.002 n=6)
VectorAsyncReadFrom/size=24/prealloc-16   72.61m ± 53%   62.09m ±  1%  -14.50% (p=0.002 n=6)
VectorAsyncReadFrom/size=24/empty-16      73.58m ±  1%   62.61m ±  4%  -14.91% (p=0.002 n=6)
VectorAsyncReadFrom/size=28/prealloc-16                  940.5m ±  1%
VectorAsyncReadFrom/size=28/empty-16                      1.129 ± 91%
geomean                                   1.234m         1.852m        -15.53%

                                        │    old-all.txt     │              new-all.txt              │
                                        │        B/op        │     B/op       vs base                │
VectorReadFrom/size=5/prealloc-16               1104.00 ± 0%      80.00 ± 0%   -92.75% (p=0.002 n=6)
VectorReadFrom/size=5/empty-16                  1104.00 ± 0%      80.00 ± 0%   -92.75% (p=0.002 n=6)
VectorReadFrom/size=10/prealloc-16             32848.00 ± 0%      80.00 ± 0%   -99.76% (p=0.002 n=6)
VectorReadFrom/size=10/empty-16                32848.00 ± 0%      80.00 ± 0%   -99.76% (p=0.002 n=6)
VectorReadFrom/size=15/prealloc-16           1048666.00 ± 0%      80.00 ± 0%   -99.99% (p=0.002 n=6)
VectorReadFrom/size=15/empty-16               1048666.0 ± 0%      713.0 ± 1%   -99.93% (p=0.002 n=6)
VectorReadFrom/size=20/prealloc-16          33554525.50 ± 0%      80.00 ± 0%  -100.00% (p=0.002 n=6)
VectorReadFrom/size=20/empty-16               32768.1Ki ± 0%    668.8Ki ± 2%   -97.96% (p=0.002 n=6)
VectorReadFrom/size=24/prealloc-16         536871008.00 ± 0%      80.00 ± 0%  -100.00% (p=0.002 n=6)
VectorReadFrom/size=24/empty-16                 512.0Mi ± 0%    170.7Mi ± 0%   -66.67% (p=0.002 n=6)
VectorReadFrom/size=28/prealloc-16        8589940224.00 ± 0%      80.00 ± 0%  -100.00% (p=0.002 n=6)
VectorReadFrom/size=28/empty-16                 8.000Gi ± 0%   13.766Gi ± 0%   +72.07% (p=0.002 n=6)
VectorAsyncReadFrom/size=5/prealloc-16          2.086Ki ± 0%    1.086Ki ± 0%   -47.94% (p=0.002 n=6)
VectorAsyncReadFrom/size=5/empty-16             2.086Ki ± 0%    1.086Ki ± 0%   -47.94% (p=0.002 n=6)
VectorAsyncReadFrom/size=10/prealloc-16        33.088Ki ± 0%    1.086Ki ± 0%   -96.72% (p=0.002 n=6)
VectorAsyncReadFrom/size=10/empty-16           33.088Ki ± 0%    1.086Ki ± 0%   -96.72% (p=0.002 n=6)
VectorAsyncReadFrom/size=15/prealloc-16      1025.124Ki ± 0%    1.086Ki ± 0%   -99.89% (p=0.002 n=6)
VectorAsyncReadFrom/size=15/empty-16         1025.121Ki ± 0%    1.220Ki ± 1%   -99.88% (p=0.002 n=6)
VectorAsyncReadFrom/size=20/prealloc-16     32769.141Ki ± 0%    1.086Ki ± 0%  -100.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=20/empty-16          32769.1Ki ± 0%    124.5Ki ± 1%   -99.62% (p=0.002 n=6)
VectorAsyncReadFrom/size=24/prealloc-16    524289.143Ki ± 0%    1.088Ki ± 0%  -100.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=24/empty-16           512.00Mi ± 0%    26.95Mi ± 6%   -94.74% (p=0.002 n=6)
VectorAsyncReadFrom/size=28/prealloc-16                         1.094Ki ± 0%
VectorAsyncReadFrom/size=28/empty-16                            13.77Gi ± 0%
geomean                                         2.160Mi         7.001Ki        -99.82%

                                        │ old-all.txt  │            new-all.txt            │
                                        │  allocs/op   │ allocs/op   vs base               │
VectorReadFrom/size=5/prealloc-16          3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=5/empty-16             3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=10/prealloc-16         3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=10/empty-16            3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=15/prealloc-16         3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=15/empty-16            3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=20/prealloc-16         3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=20/empty-16            3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=24/prealloc-16         3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=24/empty-16            3.000 ±  0%   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=28/prealloc-16        11.000 ± 55%   2.000 ± 0%  -81.82% (p=0.002 n=6)
VectorReadFrom/size=28/empty-16            3.000 ±  0%   4.000 ± 0%  +33.33% (p=0.002 n=6)
VectorAsyncReadFrom/size=5/prealloc-16     25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=5/empty-16        25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=10/prealloc-16    25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=10/empty-16       25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=15/prealloc-16    25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=15/empty-16       25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=20/prealloc-16    25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=20/empty-16       25.00 ±  0%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=24/prealloc-16    25.00 ±  4%   24.00 ± 0%   -4.00% (p=0.002 n=6)
VectorAsyncReadFrom/size=24/empty-16       26.00 ±  4%   24.00 ± 0%   -7.69% (p=0.002 n=6)
VectorAsyncReadFrom/size=28/prealloc-16                  24.00 ± 0%
VectorAsyncReadFrom/size=28/empty-16                     26.00 ± 0%
geomean                                    8.358         7.155       -23.59%

Different choices for the allocation:

goos: linux
goarch: amd64
pkg: github.com/consensys/gnark-crypto/ecc/bn254/fr
cpu: AMD Ryzen 9 7940HS w/ Radeon 780M Graphics     
                                   │   old.txt    │             new-1gb.txt             │             new-2gb.txt             │             new-4gb.txt             │
                                   │    sec/op    │    sec/op     vs base               │    sec/op     vs base               │    sec/op     vs base               │
VectorReadFrom/size=5/prealloc-16    927.0n ± 25%   742.6n ± 15%  -19.89% (p=0.002 n=6)   741.9n ± 25%  -19.96% (p=0.015 n=6)   743.9n ± 27%  -19.75% (p=0.026 n=6)
VectorReadFrom/size=5/empty-16       930.3n ±  2%   744.6n ±  1%  -19.97% (p=0.002 n=6)   744.2n ±  1%  -20.01% (p=0.002 n=6)   744.4n ±  1%  -19.98% (p=0.002 n=6)
VectorReadFrom/size=10/prealloc-16   28.48µ ±  2%   22.42µ ±  0%  -21.26% (p=0.002 n=6)   22.42µ ±  1%  -21.28% (p=0.002 n=6)   22.34µ ±  0%  -21.55% (p=0.002 n=6)
VectorReadFrom/size=10/empty-16      27.99µ ±  3%   22.59µ ±  1%  -19.27% (p=0.002 n=6)   22.52µ ±  0%  -19.52% (p=0.002 n=6)   22.58µ ±  1%  -19.30% (p=0.002 n=6)
VectorReadFrom/size=15/prealloc-16   832.7µ ±  2%   719.9µ ±  1%  -13.55% (p=0.002 n=6)   718.7µ ±  1%  -13.69% (p=0.002 n=6)   722.0µ ±  3%  -13.29% (p=0.002 n=6)
VectorReadFrom/size=15/empty-16      825.4µ ±  1%   723.8µ ±  0%  -12.31% (p=0.002 n=6)   721.9µ ±  1%  -12.53% (p=0.002 n=6)   721.1µ ±  1%  -12.64% (p=0.002 n=6)
VectorReadFrom/size=20/prealloc-16   23.41m ±  2%   23.09m ±  2%        ~ (p=0.065 n=6)   23.17m ±  1%   -1.04% (p=0.004 n=6)   23.09m ±  1%   -1.39% (p=0.002 n=6)
VectorReadFrom/size=20/empty-16      23.44m ±  0%   23.15m ±  2%        ~ (p=0.310 n=6)   23.24m ±  2%        ~ (p=0.394 n=6)   23.16m ±  1%   -1.18% (p=0.026 n=6)
VectorReadFrom/size=24/prealloc-16   386.5m ±  6%   368.6m ±  1%   -4.64% (p=0.002 n=6)   368.8m ±  0%   -4.59% (p=0.002 n=6)   369.7m ±  1%   -4.35% (p=0.002 n=6)
VectorReadFrom/size=24/empty-16      366.3m ±  1%   373.0m ±  0%   +1.85% (p=0.002 n=6)   372.2m ±  0%   +1.64% (p=0.002 n=6)   372.7m ±  1%   +1.75% (p=0.002 n=6)
VectorReadFrom/size=28/prealloc-16    5.810 ±  2%    5.923 ±  0%        ~ (p=0.065 n=6)    5.918 ±  0%        ~ (p=0.065 n=6)    5.916 ±  1%        ~ (p=0.065 n=6)
VectorReadFrom/size=28/empty-16       5.811 ±  1%    7.909 ± 70%  +36.11% (p=0.002 n=6)    8.578 ± 28%  +47.62% (p=0.002 n=6)    6.208 ± 22%   +6.83% (p=0.002 n=6)
geomean                              3.219m         2.986m         -7.24%                 3.005m         -6.65%                 2.926m         -9.11%

                                   │      old.txt       │              new-1gb.txt               │              new-2gb.txt               │              new-4gb.txt              │
                                   │        B/op        │      B/op       vs base                │      B/op       vs base                │     B/op       vs base                │
VectorReadFrom/size=5/prealloc-16          1104.00 ± 0%      80.00 ±  0%   -92.75% (p=0.002 n=6)      80.00 ±  0%   -92.75% (p=0.002 n=6)      80.00 ± 0%   -92.75% (p=0.002 n=6)
VectorReadFrom/size=5/empty-16             1104.00 ± 0%      80.00 ±  0%   -92.75% (p=0.002 n=6)      80.00 ±  0%   -92.75% (p=0.002 n=6)      80.00 ± 0%   -92.75% (p=0.002 n=6)
VectorReadFrom/size=10/prealloc-16        32848.00 ± 0%      80.00 ±  0%   -99.76% (p=0.002 n=6)      80.00 ±  0%   -99.76% (p=0.002 n=6)      80.00 ± 0%   -99.76% (p=0.002 n=6)
VectorReadFrom/size=10/empty-16           32848.00 ± 0%      80.00 ±  0%   -99.76% (p=0.002 n=6)      80.00 ±  0%   -99.76% (p=0.002 n=6)      80.00 ± 0%   -99.76% (p=0.002 n=6)
VectorReadFrom/size=15/prealloc-16      1048666.00 ± 0%      80.00 ±  0%   -99.99% (p=0.002 n=6)      80.00 ±  0%   -99.99% (p=0.002 n=6)      80.00 ± 0%   -99.99% (p=0.002 n=6)
VectorReadFrom/size=15/empty-16          1048666.0 ± 0%      712.5 ±  2%   -99.93% (p=0.002 n=6)      721.5 ±  2%   -99.93% (p=0.002 n=6)      711.5 ± 2%   -99.93% (p=0.002 n=6)
VectorReadFrom/size=20/prealloc-16     33554526.00 ± 0%      80.00 ±  0%  -100.00% (p=0.002 n=6)      80.00 ±  0%  -100.00% (p=0.002 n=6)      80.00 ± 0%  -100.00% (p=0.002 n=6)
VectorReadFrom/size=20/empty-16          32768.1Ki ± 0%    669.1Ki ±  6%   -97.96% (p=0.002 n=6)    668.8Ki ±  7%   -97.96% (p=0.002 n=6)    675.8Ki ± 5%   -97.94% (p=0.002 n=6)
VectorReadFrom/size=24/prealloc-16    536871008.00 ± 0%      80.00 ±  0%  -100.00% (p=0.002 n=6)      80.00 ±  0%  -100.00% (p=0.002 n=6)      80.00 ± 0%  -100.00% (p=0.002 n=6)
VectorReadFrom/size=24/empty-16            512.0Mi ± 0%    170.7Mi ±  0%   -66.67% (p=0.002 n=6)    170.7Mi ±  0%   -66.67% (p=0.002 n=6)    170.7Mi ± 0%   -66.67% (p=0.002 n=6)
VectorReadFrom/size=28/prealloc-16   8589937520.00 ± 0%      80.00 ± 20%  -100.00% (p=0.002 n=6)      80.00 ± 20%  -100.00% (p=0.002 n=6)      80.00 ± 0%  -100.00% (p=0.002 n=6)
VectorReadFrom/size=28/empty-16            8.000Gi ± 0%   29.981Gi ±  0%  +274.76% (p=0.002 n=6)   24.049Gi ±  0%  +200.61% (p=0.002 n=6)   13.766Gi ± 0%   +72.07% (p=0.002 n=6)
geomean                                    4.052Mi         3.514Ki         -99.92%                  3.454Ki         -99.92%                  3.296Ki        -99.92%

                                   │   old.txt   │             new-1gb.txt              │             new-2gb.txt             │            new-4gb.txt            │
                                   │  allocs/op  │  allocs/op    vs base                │  allocs/op   vs base                │ allocs/op   vs base               │
VectorReadFrom/size=5/prealloc-16    3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=5/empty-16       3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=10/prealloc-16   3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=10/empty-16      3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=15/prealloc-16   3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=15/empty-16      3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=20/prealloc-16   3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=20/empty-16      3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=24/prealloc-16   3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=24/empty-16      3.000 ±  0%    2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ±  0%   -33.33% (p=0.002 n=6)   2.000 ± 0%  -33.33% (p=0.002 n=6)
VectorReadFrom/size=28/prealloc-16   8.500 ± 41%    2.000 ± 50%   -76.47% (p=0.002 n=6)   2.000 ± 50%   -76.47% (p=0.002 n=6)   2.000 ± 0%  -76.47% (p=0.002 n=6)
VectorReadFrom/size=28/empty-16      3.000 ±  0%   10.000 ± 60%  +233.33% (p=0.002 n=6)   8.500 ± 65%  +183.33% (p=0.002 n=6)   4.000 ± 0%  +33.33% (p=0.002 n=6)
geomean                              3.272          2.287         -30.10%                 2.256         -31.04%                 2.119       -35.24%

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How has this been tested?

  • TestReadMismatchLength
  • TestReadLargeHeader
  • TestReuseSliceDeserialization
  • TestVectorEqualityLarge

How has this been benchmarked?

  • BenchmarkVectorReadFrom
  • BenchmarkVectorAsyncReadFrom

Checklist:

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • I did not modify files generated from templates
  • golangci-lint does not output errors locally
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Note

Refactors Vector deserialization to read in bounded chunks and reuse capacity, adds Vector.Equal, improves errors/docs, and introduces targeted tests and benchmarks across all fields/curves.

  • Vector deserialization (all fields/curves):
    • ReadFrom/AsyncReadFrom now read in bounded chunks (≤4GB; 1GB on 32‑bit) to prevent large allocations and OOM.
    • Reuse existing slice capacity; handle zero-length and extra-bytes cases; return total bytes read.
    • Improved error messages (e.g., unexpected EOF with element counts) and updated docs/comments.
    • New Vector.Equal via slices.Equal.
  • Tests & Benchmarks:
    • Replace reflect.DeepEqual with Vector.Equal.
    • Add tests: mismatch length, very large header (skipped), reuse preallocated slice, large-equality (skipped).
    • Add benchmarks for ReadFrom and AsyncReadFrom (prealloc vs empty).
  • Codegen templates:
    • Mirror the new deserialization logic, equality method, tests, and benchmarks in generator templates.

Written by Cursor Bugbot for commit 44fa25c. This will update automatically on new commits. Configure here.

@ivokub ivokub added this to the v0.19.N milestone Oct 21, 2025
@ivokub ivokub requested review from Copilot and gbotrel October 21, 2025 14:47
@ivokub ivokub self-assigned this Oct 21, 2025
@ivokub ivokub added type: bug Something isn't working type: new feature type: consolidate strengthen an existing feature type: sec Issue related to a security flaw priority: P1-high Issue priority: high labels Oct 21, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR optimizes vector deserialization to prevent out-of-memory (OOM) issues when handling tampered or malicious input with excessively large headers. The implementation introduces batched memory allocation (up to 4GB chunks) instead of allocating the entire vector upfront, and reuses existing slice capacity when available.

Key changes:

  • Modified ReadFrom and AsyncReadFrom to allocate memory in smaller batches
  • Added Vector.Equal method for vector equality checking
  • Enhanced error handling with more descriptive messages

Reviewed Changes

Copilot reviewed 48 out of 48 changed files in this pull request and generated 12 comments.

File Description
field/generator/internal/templates/element/vector.go Template file implementing batched allocation logic and Equal method
field/generator/internal/templates/element/tests_vector.go Template for test cases validating new deserialization behavior
field/*/vector.go Generated implementation files from template
field/*/vector_test.go Generated test files validating error handling and capacity reuse
Comments suppressed due to low confidence (7)

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@ivokub ivokub marked this pull request as ready for review October 21, 2025 23:16
gbotrel
gbotrel previously approved these changes Oct 22, 2025
Copy link
Copy Markdown
Collaborator

@gbotrel gbotrel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, couldn't find any issue 👍

@cursor
Copy link
Copy Markdown

cursor bot commented Oct 23, 2025

Bug: Incorrect EOF Handling in ReadFrom Method

The ReadFrom method incorrectly checks for io.EOF when io.ReadFull returns an error. io.ReadFull signals insufficient data with io.ErrUnexpectedEOF, so ReadFrom won't properly detect truncated input or tampered headers. AsyncReadFrom handles this correctly.

Additional Locations (1)

Fix in Cursor Fix in Web

@ivokub ivokub requested a review from gbotrel October 23, 2025 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: P1-high Issue priority: high type: bug Something isn't working type: consolidate strengthen an existing feature type: new feature type: sec Issue related to a security flaw

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants