Skip to content

Commit 20cfcc6

Browse files
author
Grok Compression
committed
fuzzer: fix billion packet iteration for RPCL progression
1 parent a5ccaa2 commit 20cfcc6

2 files changed

Lines changed: 67 additions & 65 deletions

File tree

src/lib/core/t2/PacketIter.cpp

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,16 @@ void PacketIter::genPrecinctInfo(PacketIterInfoComponent* comp, PacketIterInfoRe
247247
* Preconditions for OPT:
248248
* 1. Decompression (not compression)
249249
* 2. Single progression (no POC)
250-
* 3. Tile origin at (0,0)
251-
* 4. No subsampling (all dx=dy=1)
252-
* 5. All components have the same number of resolutions
253-
* 6. For PCRL/CPRL: projected precinct sizes are non-decreasing as resolution decreases
250+
* 3. No subsampling (all dx=dy=1)
251+
* 4. All components have the same number of resolutions
252+
* 5. For PCRL/CPRL: projected precinct sizes are non-decreasing as resolution decreases
254253
* (ensures the highest-resolution precinct grid covers all lower-resolution precincts)
255254
*
255+
* The OPT path uses per-resolution precinct step sizes for spatial
256+
* progressions (RPCL), avoiding degenerate iteration when tiles have
257+
* large dimensions or many resolution levels combined with small
258+
* global dx/dy.
259+
*
256260
* @return true if OPT path was used, false if caller should use the non-OPT path
257261
*/
258262
bool PacketIter::genPrecinctInfoOPT(void)
@@ -261,9 +265,6 @@ bool PacketIter::genPrecinctInfoOPT(void)
261265
return false;
262266

263267
auto tb = packetManager->getTileBounds();
264-
// tile origin at (0,0) will simplify computations
265-
if(tb.x0 || tb.y0)
266-
return false;
267268
// no subsampling
268269
for(uint16_t compno = 0; compno < numcomps; ++compno)
269270
{
@@ -281,6 +282,11 @@ bool PacketIter::genPrecinctInfoOPT(void)
281282
break;
282283
case GRK_PCRL:
283284
case GRK_CPRL:
285+
// PCRL/CPRL OPT spatial loops use precinct-aligned bounds and bitwise
286+
// alignment checks that assume tile origin falls on a precinct boundary.
287+
// Non-zero tile origins break these assumptions.
288+
if(tb.x0 || tb.y0)
289+
return false;
284290
// if P occurs before R, then we must ensure that for all resolutions, the precinct
285291
// projected onto canvas is a "multiple" of the highest resolution precinct,
286292
// so that the P loops covers all precincts from all resolutions
@@ -823,11 +829,13 @@ bool PacketIter::genPrecinctX0GridPCRL_OPT(ResPrecinctInfo* rpInfo)
823829
}
824830
void PacketIter::genPrecinctY0GridRPCL_OPT(ResPrecinctInfo* rpInfo)
825831
{
826-
py0grid_ = (uint32_t)(ceildivpow2(y, rpInfo->decompLevel_) >> rpInfo->precHeightExp);
832+
py0grid_ = (uint32_t)(ceildivpow2(y, rpInfo->decompLevel_) >> rpInfo->precHeightExp) -
833+
rpInfo->resInPrecGridY0;
827834
}
828835
void PacketIter::genPrecinctX0GridRPCL_OPT(ResPrecinctInfo* rpInfo)
829836
{
830-
px0grid_ = (uint32_t)(ceildivpow2(x, rpInfo->decompLevel_) >> rpInfo->precWidthExp);
837+
px0grid_ = (uint32_t)(ceildivpow2(x, rpInfo->decompLevel_) >> rpInfo->precWidthExp) -
838+
rpInfo->resInPrecGridX0;
831839
}
832840
/**
833841
* Compute the minimum spatial step sizes (dx, dy) across all components and
@@ -984,6 +992,28 @@ bool PacketIter::isWholeTile(void)
984992

985993
bool PacketIter::next(SparseBuffer* compressedPackets)
986994
{
995+
// OPT path: per-resolution precinct info avoids degenerate spatial
996+
// iteration for tiles with large dimensions or many resolution levels.
997+
if(precinctInfoOPT_)
998+
{
999+
switch(prog.progression)
1000+
{
1001+
case GRK_LRCP:
1002+
return next_lrcpOPT();
1003+
case GRK_RLCP:
1004+
return next_rlcpOPT();
1005+
case GRK_PCRL:
1006+
return next_pcrlOPT();
1007+
case GRK_RPCL:
1008+
return next_rpclOPT(compressedPackets);
1009+
case GRK_CPRL:
1010+
return next_cprlOPT(compressedPackets);
1011+
default:
1012+
return false;
1013+
}
1014+
}
1015+
1016+
// Non-OPT fallback: compression, multiple progressions, subsampling, etc.
9871017
switch(prog.progression)
9881018
{
9891019
case GRK_LRCP:
@@ -996,23 +1026,22 @@ bool PacketIter::next(SparseBuffer* compressedPackets)
9961026
// spatial progressions require non-zero step sizes to avoid infinite loops
9971027
if(dx == 0 || dy == 0)
9981028
return false;
999-
if(prog.progression == GRK_PCRL)
1000-
return next_pcrl();
1001-
else if(prog.progression == GRK_RPCL)
1002-
return next_rpcl(compressedPackets);
1003-
else
1004-
return next_cprl(compressedPackets);
1029+
switch(prog.progression)
1030+
{
1031+
case GRK_PCRL:
1032+
return next_pcrl();
1033+
case GRK_RPCL:
1034+
return next_rpcl(compressedPackets);
1035+
default: // GRK_CPRL
1036+
return next_cprl(compressedPackets);
1037+
}
10051038
default:
10061039
return false;
10071040
}
1008-
1009-
return false;
10101041
}
10111042

1012-
bool PacketIter::next_cprl(SparseBuffer* compressedPackets)
1043+
bool PacketIter::next_cprl(SparseBuffer*)
10131044
{
1014-
if(precinctInfoOPT_)
1015-
return next_cprlOPT(compressedPackets);
10161045
for(; compno < prog.comp_e; compno++)
10171046
{
10181047
auto comp = comps + compno;
@@ -1053,8 +1082,6 @@ bool PacketIter::next_cprl(SparseBuffer* compressedPackets)
10531082
}
10541083
bool PacketIter::next_pcrl()
10551084
{
1056-
if(precinctInfoOPT_)
1057-
return next_pcrlOPT();
10581085
for(; y < prog.ty1; y += dyActive, dyActive = dy)
10591086
{
10601087
for(; x < prog.tx1; x += dxActive, dxActive = dx)
@@ -1098,32 +1125,17 @@ bool PacketIter::next_pcrl()
10981125
}
10991126
bool PacketIter::next_lrcp()
11001127
{
1101-
if(precinctInfoOPT_)
1102-
return next_lrcpOPT();
1103-
11041128
for(; layno < prog.lay_e; layno++)
11051129
{
11061130
for(; resno < prog.res_e; resno++)
11071131
{
1108-
uint64_t prec_e = 0;
1109-
if(precinctInfoOPT_)
1110-
{
1111-
if(resno >= comps->numresolutions)
1112-
continue;
1113-
auto res = comps->resolutions + resno;
1114-
prec_e = (uint64_t)res->precinctGridWidth * res->precinctGridHeight;
1115-
}
11161132
for(; compno < prog.comp_e; compno++)
11171133
{
11181134
auto comp = comps + compno;
1119-
if(!precinctInfoOPT_)
1120-
{
1121-
// skip resolutions greater than current component resolution
1122-
if(resno >= comp->numresolutions)
1123-
continue;
1124-
auto res = comp->resolutions + resno;
1125-
prec_e = (uint64_t)res->precinctGridWidth * res->precinctGridHeight;
1126-
}
1135+
if(resno >= comp->numresolutions)
1136+
continue;
1137+
auto res = comp->resolutions + resno;
1138+
uint64_t prec_e = (uint64_t)res->precinctGridWidth * res->precinctGridHeight;
11271139
if(incrementInner)
11281140
precinctIndex++;
11291141
if(precinctIndex < prec_e)
@@ -1144,30 +1156,17 @@ bool PacketIter::next_lrcp()
11441156
}
11451157
bool PacketIter::next_rlcp()
11461158
{
1147-
if(precinctInfoOPT_)
1148-
return next_rlcpOPT();
11491159
for(; resno < prog.res_e; resno++)
11501160
{
1151-
uint64_t prec_e = 0;
1152-
if(precinctInfoOPT_)
1153-
{
1154-
if(resno >= comps->numresolutions)
1155-
continue;
1156-
auto res = comps->resolutions + resno;
1157-
prec_e = (uint64_t)res->precinctGridWidth * res->precinctGridHeight;
1158-
}
11591161
for(; layno < prog.lay_e; layno++)
11601162
{
11611163
for(; compno < prog.comp_e; compno++)
11621164
{
11631165
auto comp = comps + compno;
1164-
if(!precinctInfoOPT_)
1165-
{
1166-
if(resno >= comp->numresolutions)
1167-
continue;
1168-
auto res = comp->resolutions + resno;
1169-
prec_e = (uint64_t)res->precinctGridWidth * res->precinctGridHeight;
1170-
}
1166+
if(resno >= comp->numresolutions)
1167+
continue;
1168+
auto res = comp->resolutions + resno;
1169+
uint64_t prec_e = (uint64_t)res->precinctGridWidth * res->precinctGridHeight;
11711170
if(incrementInner)
11721171
precinctIndex++;
11731172
if(precinctIndex < prec_e)
@@ -1186,11 +1185,8 @@ bool PacketIter::next_rlcp()
11861185

11871186
return false;
11881187
}
1189-
bool PacketIter::next_rpcl(SparseBuffer* compressedPackets)
1188+
bool PacketIter::next_rpcl(SparseBuffer*)
11901189
{
1191-
if(precinctInfoOPT_)
1192-
return next_rpclOPT(compressedPackets);
1193-
11941190
for(; resno < prog.res_e; resno++)
11951191
{
11961192
// if all remaining components have degenerate precinct grid, then
@@ -1538,7 +1534,13 @@ bool PacketIter::next_rpclOPT(SparseBuffer* compressedPackets)
15381534
}
15391535
skippedLeft_ = false;
15401536
}
1541-
y = precInfo->tileBoundsPrecPRJ.y0;
1537+
// Reset spatial position to tile origin for the next resolution.
1538+
// Each resolution's tileBoundsPrecPRJ can differ, so using the current
1539+
// resolution's x0/y0 may place x/y outside the next resolution's range,
1540+
// causing precinct-grid underflow. The tile origin is guaranteed to fall
1541+
// within every resolution's spatial range.
1542+
y = prog.ty0;
1543+
x = prog.tx0;
15421544
}
15431545

15441546
return false;

src/lib/core/t2/PacketIter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ struct PacketIter
485485
Get next packet in component-precinct-resolution-layer order.
486486
@return returns false if pi pointed to the final packet, otherwise true
487487
*/
488-
bool next_cprl(SparseBuffer* compressedPackets);
488+
bool next_cprl(SparseBuffer*);
489489
bool next_cprlOPT(SparseBuffer* compressedPackets);
490490

491491
/**
@@ -511,7 +511,7 @@ struct PacketIter
511511
Get next packet in resolution-precinct-component-layer order.
512512
@return returns false if pi pointed to the final packet, otherwise true
513513
*/
514-
bool next_rpcl(SparseBuffer* compressedPackets);
514+
bool next_rpcl(SparseBuffer*);
515515
bool next_rpclOPT(SparseBuffer* compressedPackets);
516516

517517
bool skipPackets(SparseBuffer* compressedPackets, uint64_t numPackets);

0 commit comments

Comments
 (0)