std/jpeg: tighten decoder workbuf_len worst case
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4e1c680..e667f57 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -8648,7 +8648,7 @@
// ---------------- Public Consts
-#define WUFFS_JPEG__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE 274877906944
+#define WUFFS_JPEG__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE 17184063744
// ---------------- Struct Declarations
@@ -8809,7 +8809,8 @@
uint8_t f_components_h[4];
uint8_t f_components_v[4];
uint8_t f_components_tq[4];
- uint32_t f_components_workbuf_strides[4];
+ uint32_t f_components_workbuf_widths[4];
+ uint32_t f_components_workbuf_heights[4];
uint64_t f_components_workbuf_offsets[5];
uint32_t f_scan_num_components;
uint8_t f_scan_comps_cselector[4];
@@ -37756,10 +37757,6 @@
bool v_has_h3 = false;
bool v_has_v24 = false;
bool v_has_v3 = false;
- uint64_t v_workbuf_fragment_length0 = 0;
- uint64_t v_workbuf_fragment_length1 = 0;
- uint64_t v_workbuf_fragment_length2 = 0;
- uint64_t v_workbuf_fragment_length3 = 0;
const uint8_t* iop_a_src = NULL;
const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
@@ -37991,31 +37988,33 @@
} else {
self->private_impl.f_height_in_mcus = ((self->private_impl.f_height + 31) / 32);
}
- self->private_impl.f_components_workbuf_strides[0] = (8 * ((uint32_t)(self->private_impl.f_width_in_mcus)) * ((uint32_t)(self->private_impl.f_components_h[0])));
- self->private_impl.f_components_workbuf_strides[1] = (8 * ((uint32_t)(self->private_impl.f_width_in_mcus)) * ((uint32_t)(self->private_impl.f_components_h[1])));
- self->private_impl.f_components_workbuf_strides[2] = (8 * ((uint32_t)(self->private_impl.f_width_in_mcus)) * ((uint32_t)(self->private_impl.f_components_h[2])));
- self->private_impl.f_components_workbuf_strides[3] = (8 * ((uint32_t)(self->private_impl.f_width_in_mcus)) * ((uint32_t)(self->private_impl.f_components_h[3])));
- v_workbuf_fragment_length0 = (8 *
- ((uint64_t)(self->private_impl.f_components_workbuf_strides[0])) *
- ((uint64_t)(self->private_impl.f_height_in_mcus)) *
- ((uint64_t)(self->private_impl.f_components_v[0])));
- v_workbuf_fragment_length1 = (8 *
- ((uint64_t)(self->private_impl.f_components_workbuf_strides[1])) *
- ((uint64_t)(self->private_impl.f_height_in_mcus)) *
- ((uint64_t)(self->private_impl.f_components_v[1])));
- v_workbuf_fragment_length2 = (8 *
- ((uint64_t)(self->private_impl.f_components_workbuf_strides[2])) *
- ((uint64_t)(self->private_impl.f_height_in_mcus)) *
- ((uint64_t)(self->private_impl.f_components_v[2])));
- v_workbuf_fragment_length3 = (8 *
- ((uint64_t)(self->private_impl.f_components_workbuf_strides[3])) *
- ((uint64_t)(self->private_impl.f_height_in_mcus)) *
- ((uint64_t)(self->private_impl.f_components_v[3])));
+ v_i = 0;
+ while (v_i < self->private_impl.f_num_components) {
+ if (self->private_impl.f_components_h[v_i] == 1) {
+ self->private_impl.f_components_workbuf_widths[v_i] = (((self->private_impl.f_width + 7) / 8) * 8);
+ } else if (self->private_impl.f_components_h[v_i] == 2) {
+ self->private_impl.f_components_workbuf_widths[v_i] = (((self->private_impl.f_width + 15) / 16) * 16);
+ } else if (self->private_impl.f_components_h[v_i] == 3) {
+ self->private_impl.f_components_workbuf_widths[v_i] = (((self->private_impl.f_width + 23) / 24) * 24);
+ } else {
+ self->private_impl.f_components_workbuf_widths[v_i] = (((self->private_impl.f_width + 31) / 32) * 32);
+ }
+ if (self->private_impl.f_components_v[v_i] == 1) {
+ self->private_impl.f_components_workbuf_heights[v_i] = (((self->private_impl.f_height + 7) / 8) * 8);
+ } else if (self->private_impl.f_components_v[v_i] == 2) {
+ self->private_impl.f_components_workbuf_heights[v_i] = (((self->private_impl.f_height + 15) / 16) * 16);
+ } else if (self->private_impl.f_components_v[v_i] == 3) {
+ self->private_impl.f_components_workbuf_heights[v_i] = (((self->private_impl.f_height + 23) / 24) * 24);
+ } else {
+ self->private_impl.f_components_workbuf_heights[v_i] = (((self->private_impl.f_height + 31) / 32) * 32);
+ }
+ v_i += 1;
+ }
self->private_impl.f_components_workbuf_offsets[0] = 0;
- self->private_impl.f_components_workbuf_offsets[1] = (self->private_impl.f_components_workbuf_offsets[0] + v_workbuf_fragment_length0);
- self->private_impl.f_components_workbuf_offsets[2] = (self->private_impl.f_components_workbuf_offsets[1] + v_workbuf_fragment_length1);
- self->private_impl.f_components_workbuf_offsets[3] = (self->private_impl.f_components_workbuf_offsets[2] + v_workbuf_fragment_length2);
- self->private_impl.f_components_workbuf_offsets[4] = (self->private_impl.f_components_workbuf_offsets[3] + v_workbuf_fragment_length3);
+ self->private_impl.f_components_workbuf_offsets[1] = (self->private_impl.f_components_workbuf_offsets[0] + (((uint64_t)(self->private_impl.f_components_workbuf_widths[0])) * ((uint64_t)(self->private_impl.f_components_workbuf_heights[0]))));
+ self->private_impl.f_components_workbuf_offsets[2] = (self->private_impl.f_components_workbuf_offsets[1] + (((uint64_t)(self->private_impl.f_components_workbuf_widths[1])) * ((uint64_t)(self->private_impl.f_components_workbuf_heights[1]))));
+ self->private_impl.f_components_workbuf_offsets[3] = (self->private_impl.f_components_workbuf_offsets[2] + (((uint64_t)(self->private_impl.f_components_workbuf_widths[2])) * ((uint64_t)(self->private_impl.f_components_workbuf_heights[2]))));
+ self->private_impl.f_components_workbuf_offsets[4] = (self->private_impl.f_components_workbuf_offsets[3] + (((uint64_t)(self->private_impl.f_components_workbuf_widths[3])) * ((uint64_t)(self->private_impl.f_components_workbuf_heights[3]))));
goto ok;
ok:
@@ -38852,7 +38851,7 @@
v_csel = self->private_impl.f_scan_comps_cselector[self->private_impl.f_mcu_blocks_sselector[v_b]];
v_h = ((uint64_t)(self->private_impl.f_components_h[v_csel]));
v_v = ((uint64_t)(self->private_impl.f_components_v[v_csel]));
- v_stride = ((uint64_t)(self->private_impl.f_components_workbuf_strides[v_csel]));
+ v_stride = ((uint64_t)(self->private_impl.f_components_workbuf_widths[v_csel]));
v_offset = (self->private_impl.f_components_workbuf_offsets[v_csel] + (8 * (((v_h * ((uint64_t)(v_mx))) + ((uint64_t)(self->private_impl.f_scan_comps_bx_offset[v_b]))) + (((v_v * ((uint64_t)(v_my))) + ((uint64_t)(self->private_impl.f_scan_comps_by_offset[v_b]))) * v_stride))));
if (v_offset <= ((uint64_t)(a_workbuf.len))) {
wuffs_jpeg__decoder__decode_idct(self,
@@ -39347,7 +39346,7 @@
v_dst = wuffs_base__slice_u8__subslice_j(v_dst, v_dst_length);
}
wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(&self->private_impl.f_swizzler, v_dst, wuffs_base__pixel_buffer__palette_or_else(a_dst, wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024)), a_workbuf);
- v_stride = ((uint64_t)(self->private_impl.f_components_workbuf_strides[0]));
+ v_stride = ((uint64_t)(self->private_impl.f_components_workbuf_widths[0]));
if (v_stride <= ((uint64_t)(a_workbuf.len))) {
a_workbuf = wuffs_base__slice_u8__subslice_i(a_workbuf, v_stride);
} else {
@@ -39400,18 +39399,18 @@
v_src1,
v_src2,
v_src3,
- (8 * self->private_impl.f_width_in_mcus * ((uint32_t)(self->private_impl.f_components_h[0]))),
- (8 * self->private_impl.f_width_in_mcus * ((uint32_t)(self->private_impl.f_components_h[1]))),
- (8 * self->private_impl.f_width_in_mcus * ((uint32_t)(self->private_impl.f_components_h[2]))),
- (8 * self->private_impl.f_width_in_mcus * ((uint32_t)(self->private_impl.f_components_h[3]))),
- (8 * self->private_impl.f_height_in_mcus * ((uint32_t)(self->private_impl.f_components_v[0]))),
- (8 * self->private_impl.f_height_in_mcus * ((uint32_t)(self->private_impl.f_components_v[1]))),
- (8 * self->private_impl.f_height_in_mcus * ((uint32_t)(self->private_impl.f_components_v[2]))),
- (8 * self->private_impl.f_height_in_mcus * ((uint32_t)(self->private_impl.f_components_v[3]))),
- self->private_impl.f_components_workbuf_strides[0],
- self->private_impl.f_components_workbuf_strides[1],
- self->private_impl.f_components_workbuf_strides[2],
- self->private_impl.f_components_workbuf_strides[3],
+ self->private_impl.f_components_workbuf_widths[0],
+ self->private_impl.f_components_workbuf_widths[1],
+ self->private_impl.f_components_workbuf_widths[2],
+ self->private_impl.f_components_workbuf_widths[3],
+ self->private_impl.f_components_workbuf_heights[0],
+ self->private_impl.f_components_workbuf_heights[1],
+ self->private_impl.f_components_workbuf_heights[2],
+ self->private_impl.f_components_workbuf_heights[3],
+ self->private_impl.f_components_workbuf_widths[0],
+ self->private_impl.f_components_workbuf_widths[1],
+ self->private_impl.f_components_workbuf_widths[2],
+ self->private_impl.f_components_workbuf_widths[3],
self->private_impl.f_components_h[0],
self->private_impl.f_components_h[1],
self->private_impl.f_components_h[2],
diff --git a/std/jpeg/decode_jpeg.wuffs b/std/jpeg/decode_jpeg.wuffs
index 33793fd..65a4461 100644
--- a/std/jpeg/decode_jpeg.wuffs
+++ b/std/jpeg/decode_jpeg.wuffs
@@ -35,7 +35,7 @@
pri status "#internal error: inconsistent decoder state"
-pub const DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE : base.u64 = 0x40_0000_0000
+pub const DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE : base.u64 = 0x4_0040_0100
pub struct decoder? implements base.image_decoder(
width : base.u32[..= 0xFFFF],
@@ -62,14 +62,15 @@
// components_workbuf_offsets, indexed by (b) and (b + 1), is the i and
// j bounds in the workbuf[i .. j] slice holding the post-IDCT values.
- // components_workbuf_strides[b] is the stride between its rows.
+ // components_workbuf_widths[b] is the row width, which is also the row
+ // stride (there is no slack).
//
// For example, a 4:2:0 chroma-subsampled, 36 pixels wide × 28 pixels
// high image has 6 blocks (4 Y, 1 Cb, 1 Cr; 8×8 samples each) per MCU.
// Each MCU is 16×16 pixels. The image is 3 MCUs wide × 2 MCUs high.
// The post-IDCT image dimensions round up to 48 × 32 pixels.
//
- // The components_workbuf_strides array is:
+ // The components_workbuf_widths array is:
// 0: 0x30 = 48 // Y
// 1: 0x18 = 24 // Cb
// 2: 0x18 = 24 // Cr
@@ -81,8 +82,9 @@
// 2: 0x790 = 1920 = previous + (24 * 16)
// 3: 0x900 = 2304 = previous + (24 * 16)
// 4: 0x900 = 2304 = previous + ( 0 * 0)
- components_workbuf_strides : array[4] base.u32[..= 0x4_0000],
- components_workbuf_offsets : array[5] base.u64[..= 0x40_0000_0000],
+ components_workbuf_widths : array[4] base.u32[..= 0x1_0008],
+ components_workbuf_heights : array[4] base.u32[..= 0x1_0008],
+ components_workbuf_offsets : array[5] base.u64[..= 0x4_0040_0100], // 4 * 0x1_0008 * 0x1_0008.
scan_num_components : base.u32[..= 4],
scan_comps_cselector : array[4] base.u8[..= 3],
@@ -374,11 +376,6 @@
var has_v24 : base.bool
var has_v3 : base.bool
- var workbuf_fragment_length0 : base.u64[..= 0x10_0000_0000]
- var workbuf_fragment_length1 : base.u64[..= 0x10_0000_0000]
- var workbuf_fragment_length2 : base.u64[..= 0x10_0000_0000]
- var workbuf_fragment_length3 : base.u64[..= 0x10_0000_0000]
-
if this.payload_length < 6 {
return "#bad SOF marker"
}
@@ -501,29 +498,42 @@
this.height_in_mcus = (this.height + 0x1F) / 0x20
}
- this.components_workbuf_strides[0] = 8 *
- (this.width_in_mcus as base.u32) * (this.components_h[0] as base.u32)
- this.components_workbuf_strides[1] = 8 *
- (this.width_in_mcus as base.u32) * (this.components_h[1] as base.u32)
- this.components_workbuf_strides[2] = 8 *
- (this.width_in_mcus as base.u32) * (this.components_h[2] as base.u32)
- this.components_workbuf_strides[3] = 8 *
- (this.width_in_mcus as base.u32) * (this.components_h[3] as base.u32)
+ i = 0
+ while i < this.num_components {
+ assert i < 4 via "a < b: a < c; c <= b"(c: this.num_components)
- workbuf_fragment_length0 = 8 * (this.components_workbuf_strides[0] as base.u64) *
- (this.height_in_mcus as base.u64) * (this.components_v[0] as base.u64)
- workbuf_fragment_length1 = 8 * (this.components_workbuf_strides[1] as base.u64) *
- (this.height_in_mcus as base.u64) * (this.components_v[1] as base.u64)
- workbuf_fragment_length2 = 8 * (this.components_workbuf_strides[2] as base.u64) *
- (this.height_in_mcus as base.u64) * (this.components_v[2] as base.u64)
- workbuf_fragment_length3 = 8 * (this.components_workbuf_strides[3] as base.u64) *
- (this.height_in_mcus as base.u64) * (this.components_v[3] as base.u64)
+ if this.components_h[i] == 1 {
+ this.components_workbuf_widths[i] = ((this.width + 0x07) / 0x08) * 0x08
+ } else if this.components_h[i] == 2 {
+ this.components_workbuf_widths[i] = ((this.width + 0x0F) / 0x10) * 0x10
+ } else if this.components_h[i] == 3 {
+ this.components_workbuf_widths[i] = ((this.width + 0x17) / 0x18) * 0x18
+ } else {
+ this.components_workbuf_widths[i] = ((this.width + 0x1F) / 0x20) * 0x20
+ }
+
+ if this.components_v[i] == 1 {
+ this.components_workbuf_heights[i] = ((this.height + 0x07) / 0x08) * 0x08
+ } else if this.components_v[i] == 2 {
+ this.components_workbuf_heights[i] = ((this.height + 0x0F) / 0x10) * 0x10
+ } else if this.components_v[i] == 3 {
+ this.components_workbuf_heights[i] = ((this.height + 0x17) / 0x18) * 0x18
+ } else {
+ this.components_workbuf_heights[i] = ((this.height + 0x1F) / 0x20) * 0x20
+ }
+
+ i += 1
+ } endwhile
this.components_workbuf_offsets[0] = 0
- this.components_workbuf_offsets[1] = this.components_workbuf_offsets[0] + workbuf_fragment_length0
- this.components_workbuf_offsets[2] = this.components_workbuf_offsets[1] + workbuf_fragment_length1
- this.components_workbuf_offsets[3] = this.components_workbuf_offsets[2] + workbuf_fragment_length2
- this.components_workbuf_offsets[4] = this.components_workbuf_offsets[3] + workbuf_fragment_length3
+ this.components_workbuf_offsets[1] = this.components_workbuf_offsets[0] +
+ ((this.components_workbuf_widths[0] as base.u64) * (this.components_workbuf_heights[0] as base.u64))
+ this.components_workbuf_offsets[2] = this.components_workbuf_offsets[1] +
+ ((this.components_workbuf_widths[1] as base.u64) * (this.components_workbuf_heights[1] as base.u64))
+ this.components_workbuf_offsets[3] = this.components_workbuf_offsets[2] +
+ ((this.components_workbuf_widths[2] as base.u64) * (this.components_workbuf_heights[2] as base.u64))
+ this.components_workbuf_offsets[4] = this.components_workbuf_offsets[3] +
+ ((this.components_workbuf_widths[3] as base.u64) * (this.components_workbuf_heights[3] as base.u64))
}
pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
@@ -991,7 +1001,7 @@
csel = this.scan_comps_cselector[this.mcu_blocks_sselector[b]]
h = this.components_h[csel] as base.u64
v = this.components_v[csel] as base.u64
- stride = this.components_workbuf_strides[csel] as base.u64
+ stride = this.components_workbuf_widths[csel] as base.u64
offset = this.components_workbuf_offsets[csel] + (8 *
((((h * (mx as base.u64)) + (this.scan_comps_bx_offset[b] as base.u64))) +
((((v * (my as base.u64)) + (this.scan_comps_by_offset[b] as base.u64))) * stride)))
@@ -1360,7 +1370,7 @@
dst: dst,
dst_palette: args.dst.palette_or_else(fallback: this.dst_palette[..]),
src: args.workbuf)
- stride = this.components_workbuf_strides[0] as base.u64
+ stride = this.components_workbuf_widths[0] as base.u64
if stride <= args.workbuf.length() {
args.workbuf = args.workbuf[stride ..]
} else {
@@ -1407,18 +1417,18 @@
src1: src1,
src2: src2,
src3: src3,
- width0: 8 * this.width_in_mcus * (this.components_h[0] as base.u32),
- width1: 8 * this.width_in_mcus * (this.components_h[1] as base.u32),
- width2: 8 * this.width_in_mcus * (this.components_h[2] as base.u32),
- width3: 8 * this.width_in_mcus * (this.components_h[3] as base.u32),
- height0: 8 * this.height_in_mcus * (this.components_v[0] as base.u32),
- height1: 8 * this.height_in_mcus * (this.components_v[1] as base.u32),
- height2: 8 * this.height_in_mcus * (this.components_v[2] as base.u32),
- height3: 8 * this.height_in_mcus * (this.components_v[3] as base.u32),
- stride0: this.components_workbuf_strides[0],
- stride1: this.components_workbuf_strides[1],
- stride2: this.components_workbuf_strides[2],
- stride3: this.components_workbuf_strides[3],
+ width0: this.components_workbuf_widths[0],
+ width1: this.components_workbuf_widths[1],
+ width2: this.components_workbuf_widths[2],
+ width3: this.components_workbuf_widths[3],
+ height0: this.components_workbuf_heights[0],
+ height1: this.components_workbuf_heights[1],
+ height2: this.components_workbuf_heights[2],
+ height3: this.components_workbuf_heights[3],
+ stride0: this.components_workbuf_widths[0],
+ stride1: this.components_workbuf_widths[1],
+ stride2: this.components_workbuf_widths[2],
+ stride3: this.components_workbuf_widths[3],
h0: this.components_h[0],
h1: this.components_h[1],
h2: this.components_h[2],