LibGfx/JBIG2: Don't assert on unexpected OOB values in the bitstream

This should only happen on either invalid inputs or if our code has
a bug (gasp!). Printing an error instead of asserting seems nicer.
This commit is contained in:
Nico Weber 2024-03-26 08:08:31 -04:00 committed by Tim Flynn
parent b3c423e4ca
commit a2a5fc76aa
Notes: sideshowbarker 2024-07-17 21:11:12 +09:00

View file

@ -224,6 +224,9 @@ public:
// Returns OptionalNone for OOB.
Optional<i32> decode();
// Returns Error for OOB.
ErrorOr<i32> decode_non_oob();
private:
ArithmeticDecoder& m_decoder;
u16 PREV { 0 };
@ -290,6 +293,14 @@ Optional<int> ArithmeticIntegerDecoder::decode()
return S ? -V : V;
}
ErrorOr<i32> ArithmeticIntegerDecoder::decode_non_oob()
{
auto result = decode();
if (!result.has_value())
return Error::from_string_literal("ArithmeticIntegerDecoder: Unexpected OOB");
return result.value();
}
class ArithmeticIntegerIDDecoder {
public:
ArithmeticIntegerIDDecoder(ArithmeticDecoder&, u32 code_length);
@ -1200,8 +1211,8 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// If SBHUFF is 0, decode a value using the IADT integer arithmetic decoding procedure (see Annex A) and multiply the resulting value by SBSTRIPS."
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder delta_t_integer_decoder(decoder);
auto read_delta_t = [&]() -> i32 {
return delta_t_integer_decoder.decode().value() * inputs.size_of_symbol_instance_strips;
auto read_delta_t = [&]() -> ErrorOr<i32> {
return TRY(delta_t_integer_decoder.decode_non_oob()) * inputs.size_of_symbol_instance_strips;
};
// 6.4.7 First symbol instance S coordinate
@ -1209,8 +1220,8 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// If SBHUFF is 0, decode a value using the IAFS integer arithmetic decoding procedure (see Annex A)."
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder first_s_integer_decoder(decoder);
auto read_first_s = [&]() -> i32 {
return first_s_integer_decoder.decode().value();
auto read_first_s = [&]() -> ErrorOr<i32> {
return first_s_integer_decoder.decode_non_oob();
};
// 6.4.8 Subsequent symbol instance S coordinate
@ -1229,10 +1240,10 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// • If SBHUFF is 0, decode a value using the IAIT integer arithmetic decoding procedure (see Annex A)."
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder instance_t_integer_decoder(decoder);
auto read_instance_t = [&]() -> i32 {
auto read_instance_t = [&]() -> ErrorOr<i32> {
if (inputs.size_of_symbol_instance_strips == 1)
return 0;
return instance_t_integer_decoder.decode().value();
return instance_t_integer_decoder.decode_non_oob();
};
// 6.4.10 Symbol instance symbol ID
@ -1246,29 +1257,29 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// 6.4.11.1 Symbol instance refinement delta width
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder refinement_delta_width_decoder(decoder);
auto read_refinement_delta_width = [&]() -> i32 {
return refinement_delta_width_decoder.decode().value();
auto read_refinement_delta_width = [&]() -> ErrorOr<i32> {
return refinement_delta_width_decoder.decode_non_oob();
};
// 6.4.11.2 Symbol instance refinement delta width
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder refinement_delta_height_decoder(decoder);
auto read_refinement_delta_height = [&]() -> i32 {
return refinement_delta_height_decoder.decode().value();
auto read_refinement_delta_height = [&]() -> ErrorOr<i32> {
return refinement_delta_height_decoder.decode_non_oob();
};
// 6.4.11.3 Symbol instance refinement X offset
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder refinement_x_offset_decoder(decoder);
auto read_refinement_x_offset = [&]() -> i32 {
return refinement_x_offset_decoder.decode().value();
auto read_refinement_x_offset = [&]() -> ErrorOr<i32> {
return refinement_x_offset_decoder.decode_non_oob();
};
// 6.4.11.4 Symbol instance refinement Y offset
// FIXME: Implement support for SBHUFF = 1.
JBIG2::ArithmeticIntegerDecoder refinement_y_offset_decoder(decoder);
auto read_refinement_y_offset = [&]() -> i32 {
return refinement_y_offset_decoder.decode().value();
auto read_refinement_y_offset = [&]() -> ErrorOr<i32> {
return refinement_y_offset_decoder.decode_non_oob();
};
// 6.4.11 Symbol instance bitmap
@ -1287,16 +1298,16 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// "• If SBHUFF is 1, then read one bit and set RI to the value of that bit.
// • If SBHUFF is 0, then decode one bit using the IARI integer arithmetic decoding procedure and set RI to the value of that bit."
// FIXME: Implement support for SBHUFF = 1.
has_refinement_image = has_refinement_image_decoder.decode().value();
has_refinement_image = TRY(has_refinement_image_decoder.decode_non_oob());
}
if (!has_refinement_image)
return &symbol;
auto refinement_delta_width = read_refinement_delta_width();
auto refinement_delta_height = read_refinement_delta_height();
auto refinement_x_offset = read_refinement_x_offset();
auto refinement_y_offset = read_refinement_y_offset();
auto refinement_delta_width = TRY(read_refinement_delta_width());
auto refinement_delta_height = TRY(read_refinement_delta_height());
auto refinement_x_offset = TRY(read_refinement_x_offset());
auto refinement_y_offset = TRY(read_refinement_y_offset());
// FIXME: This is missing some steps needed for the SBHUFF = 1 case.
dbgln_if(JBIG2_DEBUG, "refinement delta width: {}, refinement delta height: {}, refinement x offset: {}, refinement y offset: {}", refinement_delta_width, refinement_delta_height, refinement_x_offset, refinement_y_offset);
@ -1325,7 +1336,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// "2) Decode the initial STRIPT value as described in 6.4.6. Negate the decoded value and assign this negated value to the variable STRIPT.
// Assign the value 0 to FIRSTS. Assign the value 0 to NINSTANCES."
i32 strip_t = -read_delta_t();
i32 strip_t = -TRY(read_delta_t());
i32 first_s = 0;
u32 n_instances = 0;
@ -1339,7 +1350,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
while (n_instances < inputs.number_of_instances) {
// "b) Decode the strip's delta T value as described in 6.4.6. Let DT be the decoded value. Set:
// STRIPT = STRIPT + DT"
i32 delta_t = read_delta_t();
i32 delta_t = TRY(read_delta_t());
strip_t += delta_t;
i32 cur_s;
@ -1357,7 +1368,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// CURS = CURS + IDS + SBDSOFFSET"
// Implementor's note: The spec means "proceed to step 4 d)" in 4c ii).
if (is_first_symbol) {
i32 delta_first_s = read_first_s();
i32 delta_first_s = TRY(read_first_s());
first_s += delta_first_s;
cur_s = first_s;
is_first_symbol = false;
@ -1371,7 +1382,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
// "iii) Decode the symbol instance's T coordinate as described in 6.4.9. Let CURT be the decoded value. Set:
// TI = STRIPT + CURT"
i32 cur_t = read_instance_t();
i32 cur_t = TRY(read_instance_t());
i32 t_instance = strip_t + cur_t;
// "iv) Decode the symbol instance's symbol ID as described in 6.4.10. Let IDI be the decoded value."
@ -1508,9 +1519,8 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
// If SDHUFF is 0, decode a value using the IADH integer arithmetic decoding procedure (see Annex A)."
// FIXME: Implement support for SDHUFF = 1.
JBIG2::ArithmeticIntegerDecoder delta_height_integer_decoder(decoder);
auto read_delta_height = [&]() -> i32 {
// No OOB values for delta height.
return delta_height_integer_decoder.decode().value();
auto read_delta_height = [&]() -> ErrorOr<i32> {
return delta_height_integer_decoder.decode_non_oob();
};
// 6.5.7 Delta width
@ -1532,10 +1542,10 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
// If SDHUFF is 0, decode a value using the IAAI integer arithmetic decoding procedure (see Annex A).
// FIXME: Implement support for SDHUFF = 1.
Optional<JBIG2::ArithmeticIntegerDecoder> number_of_symbol_instances_decoder;
auto read_number_of_symbol_instances = [&]() -> i32 {
auto read_number_of_symbol_instances = [&]() -> ErrorOr<i32> {
if (!number_of_symbol_instances_decoder.has_value())
number_of_symbol_instances_decoder = JBIG2::ArithmeticIntegerDecoder(decoder);
return number_of_symbol_instances_decoder->decode().value();
return number_of_symbol_instances_decoder->decode_non_oob();
};
// 6.5.8.1 Direct-coded symbol bitmap
@ -1569,7 +1579,7 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
// 6.5.8.2 Refinement/aggregate-coded symbol bitmap
// "1) Decode the number of symbol instances contained in the aggregation, as specified in 6.5.8.2.1. Let REFAGGNINST be the value decoded."
auto number_of_symbol_instances = read_number_of_symbol_instances(); // "REFAGGNINST" in spec.
auto number_of_symbol_instances = TRY(read_number_of_symbol_instances()); // "REFAGGNINST" in spec.
dbgln_if(JBIG2_DEBUG, "Number of symbol instances: {}", number_of_symbol_instances);
if (number_of_symbol_instances > 1) {
@ -1595,11 +1605,11 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
if (!refinement_x_offset_decoder.has_value())
refinement_x_offset_decoder = JBIG2::ArithmeticIntegerDecoder(decoder);
i32 refinement_x_offset = refinement_x_offset_decoder->decode().value();
i32 refinement_x_offset = TRY(refinement_x_offset_decoder->decode_non_oob());
if (!refinement_y_offset_decoder.has_value())
refinement_y_offset_decoder = JBIG2::ArithmeticIntegerDecoder(decoder);
i32 refinement_y_offset = refinement_y_offset_decoder->decode().value();
i32 refinement_y_offset = TRY(refinement_y_offset_decoder->decode_non_oob());
if (symbol_id >= inputs.input_symbols.size() && symbol_id - inputs.input_symbols.size() >= new_symbols.size())
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Refinement/aggregate symbol ID out of range");
@ -1641,7 +1651,7 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
// SYMWIDTH = 0
// TOTWIDTH = 0
// HCFIRSTSYM = NSYMSDECODED"
i32 delta_height = read_delta_height();
i32 delta_height = TRY(read_delta_height());
height_class_height += delta_height;
u32 symbol_width = 0;
u32 total_width = 0;
@ -1703,7 +1713,7 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
// "2) Decode a value using Table B.1 if SDHUFF is 1, or the IAEX integer arithmetic decoding procedure if
// SDHUFF is 0. Let EXRUNLENGTH be the decoded value."
// FIXME: Implement support for SDHUFF = 1.
i32 export_run_length = export_integer_decoder.decode().value(); // No OOB value.
i32 export_run_length = TRY(export_integer_decoder.decode_non_oob());
// "3) Set EXFLAGS[EXINDEX] through EXFLAGS[EXINDEX + EXRUNLENGTH 1] to CUREXFLAG.
// If EXRUNLENGTH = 0, then this step does not change any values."