From 92d0aff08b49c1c79e08f2c32f8db65b149a8635 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 27 Jul 2017 10:33:47 +0200 Subject: [PATCH] Bug 1384862 - Update WOFF2 code to latest upstream. r=sylvestre --- modules/woff2/README.mozilla | 6 +-- modules/woff2/brotli-0.6.0-api-change.patch | 43 ------------------- modules/woff2/redefine-unique_ptr.patch | 2 +- modules/woff2/src/buffer.h | 10 ++--- modules/woff2/src/convert_woff2ttf_fuzzer.cc | 13 ++++++ .../src/convert_woff2ttf_fuzzer_new_entry.cc | 12 ++++++ modules/woff2/src/font.cc | 13 +++++- modules/woff2/src/glyph.cc | 32 +++++++------- modules/woff2/src/normalize.cc | 9 ++-- modules/woff2/src/port.h | 11 +++++ modules/woff2/src/store_bytes.h | 23 +++++----- modules/woff2/src/variable_length.cc | 4 +- modules/woff2/src/woff2_common.cc | 11 ++--- modules/woff2/src/woff2_dec.cc | 12 ++++-- modules/woff2/src/woff2_enc.cc | 41 +++++++++--------- 15 files changed, 121 insertions(+), 121 deletions(-) delete mode 100644 modules/woff2/brotli-0.6.0-api-change.patch create mode 100644 modules/woff2/src/convert_woff2ttf_fuzzer.cc create mode 100644 modules/woff2/src/convert_woff2ttf_fuzzer_new_entry.cc diff --git a/modules/woff2/README.mozilla b/modules/woff2/README.mozilla index cb44641073c8..7e4a54669c1f 100644 --- a/modules/woff2/README.mozilla +++ b/modules/woff2/README.mozilla @@ -11,12 +11,8 @@ The in-tree copy is updated by running sh update.sh from within the modules/woff2 directory. -Current version: [commit 63b8fb6d0d797f04e77ee825fd8fcf7ea6205aac]. +Current version: [commit e580ebc30a54becf69a75f6e6d6008536ae0c0b4]. redefine-unique_ptr.patch redefines the class std::unique_ptr to workaround a build issue with missing C++11 features. See https://bugzilla.mozilla.org/show_bug.cgi?id=1227058 - -brotli-0.6.0-api-change.patch adjusts the WOFF2 code to match Brotli API -changes in the 0.6.0 release. (Will be superseded by next WOFF2 update.) -See https://bugzilla.mozilla.org/show_bug.cgi?id=1340910 diff --git a/modules/woff2/brotli-0.6.0-api-change.patch b/modules/woff2/brotli-0.6.0-api-change.patch deleted file mode 100644 index 2fe46362f492..000000000000 --- a/modules/woff2/brotli-0.6.0-api-change.patch +++ /dev/null @@ -1,43 +0,0 @@ -diff --git a/modules/woff2/src/woff2_dec.cc b/modules/woff2/src/woff2_dec.cc ---- a/modules/woff2/src/woff2_dec.cc -+++ b/modules/woff2/src/woff2_dec.cc -@@ -31,17 +31,17 @@ - namespace std - { - using mozilla::DefaultDelete; - using mozilla::UniquePtr; - #define default_delete DefaultDelete - #define unique_ptr UniquePtr - } - --#include "./decode.h" -+#include "brotli/decode.h" - #include "./buffer.h" - #include "./port.h" - #include "./round.h" - #include "./store_bytes.h" - #include "./table_tags.h" - #include "./variable_length.h" - #include "./woff2_common.h" - -@@ -746,18 +746,18 @@ bool ReconstructTransformedHmtx(const ui - } - - return true; - } - - bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size, - const uint8_t* src_buf, size_t src_size) { - size_t uncompressed_size = dst_size; -- int ok = BrotliDecompressBuffer(src_size, src_buf, -- &uncompressed_size, dst_buf); -+ int ok = BrotliDecoderDecompress(src_size, src_buf, -+ &uncompressed_size, dst_buf); - if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) { - return FONT_COMPRESSION_FAILURE(); - } - return true; - } - - bool ReadTableDirectory(Buffer* file, std::vector* tables, - size_t num_tables) { diff --git a/modules/woff2/redefine-unique_ptr.patch b/modules/woff2/redefine-unique_ptr.patch index 888ed8cc1f58..dd03b34bd522 100644 --- a/modules/woff2/redefine-unique_ptr.patch +++ b/modules/woff2/redefine-unique_ptr.patch @@ -19,7 +19,7 @@ diff --git a/modules/woff2/src/woff2_dec.cc b/modules/woff2/src/woff2_dec.cc + #define unique_ptr UniquePtr +} + - #include "./decode.h" + #include "./brotli/decode.h" #include "./buffer.h" #include "./port.h" #include "./round.h" diff --git a/modules/woff2/src/buffer.h b/modules/woff2/src/buffer.h index 588ac0d3399c..08681a6fcbfe 100644 --- a/modules/woff2/src/buffer.h +++ b/modules/woff2/src/buffer.h @@ -65,8 +65,8 @@ inline bool Failure(const char *f, int l, const char *fn) { // ----------------------------------------------------------------------------- class Buffer { public: - Buffer(const uint8_t *buffer, size_t len) - : buffer_(buffer), + Buffer(const uint8_t *data, size_t len) + : buffer_(data), length_(len), offset_(0) { } @@ -74,7 +74,7 @@ class Buffer { return Read(NULL, n_bytes); } - bool Read(uint8_t *buffer, size_t n_bytes) { + bool Read(uint8_t *data, size_t n_bytes) { if (n_bytes > 1024 * 1024 * 1024) { return FONT_COMPRESSION_FAILURE(); } @@ -82,8 +82,8 @@ class Buffer { (offset_ > length_ - n_bytes)) { return FONT_COMPRESSION_FAILURE(); } - if (buffer) { - std::memcpy(buffer, buffer_ + offset_, n_bytes); + if (data) { + std::memcpy(data, buffer_ + offset_, n_bytes); } offset_ += n_bytes; return true; diff --git a/modules/woff2/src/convert_woff2ttf_fuzzer.cc b/modules/woff2/src/convert_woff2ttf_fuzzer.cc new file mode 100644 index 000000000000..3fdd15bc2d05 --- /dev/null +++ b/modules/woff2/src/convert_woff2ttf_fuzzer.cc @@ -0,0 +1,13 @@ +#include +#include + +#include "woff2_dec.h" + +// Entry point for LibFuzzer. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::string buf; + woff2::WOFF2StringOut out(&buf); + out.SetMaxSize(30 * 1024 * 1024); + woff2::ConvertWOFF2ToTTF(data, size, &out); + return 0; +} diff --git a/modules/woff2/src/convert_woff2ttf_fuzzer_new_entry.cc b/modules/woff2/src/convert_woff2ttf_fuzzer_new_entry.cc new file mode 100644 index 000000000000..75114a91b1e5 --- /dev/null +++ b/modules/woff2/src/convert_woff2ttf_fuzzer_new_entry.cc @@ -0,0 +1,12 @@ +#include +#include "woff2_dec.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t data_size) { + // Decode using newer entry pattern. + // Same pattern as woff2_decompress. + std::string output(std::min(woff2::ComputeWOFF2FinalSize(data, data_size), + woff2::kDefaultMaxSize), 0); + woff2::WOFF2StringOut out(&output); + woff2::ConvertWOFF2ToTTF(data, data_size, &out); + return 0; +} diff --git a/modules/woff2/src/font.cc b/modules/woff2/src/font.cc index 06067300524a..8dc10438251e 100644 --- a/modules/woff2/src/font.cc +++ b/modules/woff2/src/font.cc @@ -105,6 +105,12 @@ bool ReadTrueTypeFont(Buffer* file, const uint8_t* data, size_t len, last_offset = i.first + i.second; } + // Sanity check key tables + const Font::Table* head_table = font->FindTable(kHeadTableTag); + if (head_table != NULL && head_table->length < 52) { + return FONT_COMPRESSION_FAILURE(); + } + return true; } @@ -325,8 +331,11 @@ int NumGlyphs(const Font& font) { return 0; } int index_fmt = IndexFormat(font); - int num_glyphs = (loca_table->length / (index_fmt == 0 ? 2 : 4)) - 1; - return num_glyphs; + int loca_record_size = (index_fmt == 0 ? 2 : 4); + if (loca_table->length < loca_record_size) { + return 0; + } + return (loca_table->length / loca_record_size) - 1; } int IndexFormat(const Font& font) { diff --git a/modules/woff2/src/glyph.cc b/modules/woff2/src/glyph.cc index 1dadafcb7001..4c6b60a14470 100644 --- a/modules/woff2/src/glyph.cc +++ b/modules/woff2/src/glyph.cc @@ -118,25 +118,27 @@ bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) { // Read the run-length coded flags. std::vector > flags(num_contours); - uint8_t flag = 0; - uint8_t flag_repeat = 0; - for (int i = 0; i < num_contours; ++i) { - flags[i].resize(glyph->contours[i].size()); - for (size_t j = 0; j < glyph->contours[i].size(); ++j) { - if (flag_repeat == 0) { - if (!buffer.ReadU8(&flag)) { - return FONT_COMPRESSION_FAILURE(); - } - if (flag & kFLAG_REPEAT) { - if (!buffer.ReadU8(&flag_repeat)) { + { + uint8_t flag = 0; + uint8_t flag_repeat = 0; + for (int i = 0; i < num_contours; ++i) { + flags[i].resize(glyph->contours[i].size()); + for (size_t j = 0; j < glyph->contours[i].size(); ++j) { + if (flag_repeat == 0) { + if (!buffer.ReadU8(&flag)) { return FONT_COMPRESSION_FAILURE(); } + if (flag & kFLAG_REPEAT) { + if (!buffer.ReadU8(&flag_repeat)) { + return FONT_COMPRESSION_FAILURE(); + } + } + } else { + flag_repeat--; } - } else { - flag_repeat--; + flags[i][j] = flag; + glyph->contours[i][j].on_curve = flag & kFLAG_ONCURVE; } - flags[i][j] = flag; - glyph->contours[i][j].on_curve = flag & kFLAG_ONCURVE; } } diff --git a/modules/woff2/src/normalize.cc b/modules/woff2/src/normalize.cc index b538b91a89f5..1af3b7db66b6 100644 --- a/modules/woff2/src/normalize.cc +++ b/modules/woff2/src/normalize.cc @@ -52,7 +52,7 @@ bool WriteNormalizedLoca(int index_fmt, int num_glyphs, Font* font) { loca_table->buffer.resize(Round4(num_glyphs + 1) * glyph_sz); loca_table->length = (num_glyphs + 1) * glyph_sz; - uint8_t* glyf_dst = &glyf_table->buffer[0]; + uint8_t* glyf_dst = num_glyphs ? &glyf_table->buffer[0] : NULL; uint8_t* loca_dst = &loca_table->buffer[0]; uint32_t glyf_offset = 0; size_t loca_offset = 0; @@ -78,16 +78,13 @@ bool WriteNormalizedLoca(int index_fmt, int num_glyphs, Font* font) { } glyf_offset += glyf_dst_size; } - if (glyf_offset == 0) { - return false; - } StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst); glyf_table->buffer.resize(glyf_offset); - glyf_table->data = &glyf_table->buffer[0]; + glyf_table->data = glyf_offset ? &glyf_table->buffer[0] : NULL; glyf_table->length = glyf_offset; - loca_table->data = &loca_table->buffer[0]; + loca_table->data = loca_offset ? &loca_table->buffer[0] : NULL; return true; } diff --git a/modules/woff2/src/port.h b/modules/woff2/src/port.h index bac47a93a612..b302d6c4959b 100644 --- a/modules/woff2/src/port.h +++ b/modules/woff2/src/port.h @@ -60,4 +60,15 @@ inline int Log2Floor(uint32 n) { #define PREDICT_TRUE(x) (x) #endif +#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \ + (defined(M_ARM) && (M_ARM == 7)) || \ + defined(__aarch64__) || defined(__ARM64_ARCH_8__) || defined(__i386) || \ + defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) +#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define WOFF_LITTLE_ENDIAN +#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define WOFF_BIG_ENDIAN +#endif /* endianness */ +#endif /* CPU whitelist */ + #endif // WOFF2_PORT_H_ diff --git a/modules/woff2/src/store_bytes.h b/modules/woff2/src/store_bytes.h index e026cd33acaa..82c1bd84acef 100644 --- a/modules/woff2/src/store_bytes.h +++ b/modules/woff2/src/store_bytes.h @@ -22,6 +22,8 @@ #include #include +#include "./port.h" + namespace woff2 { inline size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) { @@ -33,12 +35,11 @@ inline size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) { } inline size_t Store16(uint8_t* dst, size_t offset, int x) { -#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - uint16_t v = ((x & 0xFF) << 8) | ((x & 0xFF00) >> 8); - memcpy(dst + offset, &v, 2); -#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - uint16_t v = static_cast(x); - memcpy(dst + offset, &v, 2); +#if defined(WOFF_LITTLE_ENDIAN) + *reinterpret_cast(dst + offset) = + ((x & 0xFF) << 8) | ((x & 0xFF00) >> 8); +#elif defined(WOFF_BIG_ENDIAN) + *reinterpret_cast(dst + offset) = static_cast(x); #else dst[offset] = x >> 8; dst[offset + 1] = x; @@ -54,14 +55,12 @@ inline void StoreU32(uint32_t val, size_t* offset, uint8_t* dst) { } inline void Store16(int val, size_t* offset, uint8_t* dst) { -#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - uint16_t v = ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8); - memcpy(dst + *offset, &v, 2); +#if defined(WOFF_LITTLE_ENDIAN) + *reinterpret_cast(dst + *offset) = ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8); *offset += 2; -#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - uint16_t v = static_cast(val); - memcpy(dst + *offset, &v, 2); +#elif defined(WOFF_BIG_ENDIAN) + *reinterpret_cast(dst + *offset) = static_cast(val); *offset += 2; #else dst[(*offset)++] = val >> 8; diff --git a/modules/woff2/src/variable_length.cc b/modules/woff2/src/variable_length.cc index 944a17f2e289..264eb0a1603c 100644 --- a/modules/woff2/src/variable_length.cc +++ b/modules/woff2/src/variable_length.cc @@ -49,8 +49,8 @@ void Write255UShort(std::vector* out, int value) { void Store255UShort(int val, size_t* offset, uint8_t* dst) { std::vector packed; Write255UShort(&packed, val); - for (uint8_t val : packed) { - dst[(*offset)++] = val; + for (uint8_t packed_byte : packed) { + dst[(*offset)++] = packed_byte; } } diff --git a/modules/woff2/src/woff2_common.cc b/modules/woff2/src/woff2_common.cc index 9dc7cbd5ce22..c19acdbd9ce4 100644 --- a/modules/woff2/src/woff2_common.cc +++ b/modules/woff2/src/woff2_common.cc @@ -18,6 +18,8 @@ #include "./woff2_common.h" +#include "./port.h" + namespace woff2 { @@ -25,13 +27,12 @@ uint32_t ComputeULongSum(const uint8_t* buf, size_t size) { uint32_t checksum = 0; size_t aligned_size = size & ~3; for (size_t i = 0; i < aligned_size; i += 4) { - uint32_t v; - memcpy(&v, buf + i, 4); -#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#if defined(WOFF_LITTLE_ENDIAN) + uint32_t v = *reinterpret_cast(buf + i); checksum += (((v & 0xFF) << 24) | ((v & 0xFF00) << 8) | ((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24)); -#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - checksum += v; +#elif defined(WOFF_BIG_ENDIAN) + checksum += *reinterpret_cast(buf + i); #else checksum += (buf[i] << 24) | (buf[i + 1] << 16) | (buf[i + 2] << 8) | buf[i + 3]; diff --git a/modules/woff2/src/woff2_dec.cc b/modules/woff2/src/woff2_dec.cc index a2851196ed0a..23ce8e49531d 100644 --- a/modules/woff2/src/woff2_dec.cc +++ b/modules/woff2/src/woff2_dec.cc @@ -36,7 +36,7 @@ namespace std #define unique_ptr UniquePtr } -#include "brotli/decode.h" +#include "./brotli/decode.h" #include "./buffer.h" #include "./port.h" #include "./round.h" @@ -751,9 +751,10 @@ bool ReconstructTransformedHmtx(const uint8_t* transformed_buf, bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size, const uint8_t* src_buf, size_t src_size) { size_t uncompressed_size = dst_size; - int ok = BrotliDecoderDecompress(src_size, src_buf, - &uncompressed_size, dst_buf); - if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) { + BrotliDecoderResult result = BrotliDecoderDecompress( + src_size, src_buf, &uncompressed_size, dst_buf); + if (PREDICT_FALSE(result != BROTLI_DECODER_RESULT_SUCCESS || + uncompressed_size != dst_size)) { return FONT_COMPRESSION_FAILURE(); } return true; @@ -1307,6 +1308,9 @@ bool ConvertWOFF2ToTTF(const uint8_t* data, size_t length, const uint8_t* src_buf = data + hdr.compressed_offset; std::vector uncompressed_buf(hdr.uncompressed_size); + if (PREDICT_FALSE(hdr.uncompressed_size < 1)) { + return FONT_COMPRESSION_FAILURE(); + } if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0], hdr.uncompressed_size, src_buf, hdr.compressed_length))) { diff --git a/modules/woff2/src/woff2_enc.cc b/modules/woff2/src/woff2_enc.cc index d100ad51b730..4e83a674f7e2 100644 --- a/modules/woff2/src/woff2_enc.cc +++ b/modules/woff2/src/woff2_enc.cc @@ -23,7 +23,7 @@ #include #include -#include "./compressor.h" +#include "./brotli/encode.h" #include "./buffer.h" #include "./font.h" #include "./normalize.h" @@ -34,7 +34,6 @@ #include "./variable_length.h" #include "./woff2_common.h" - namespace woff2 { namespace { @@ -47,16 +46,11 @@ using std::vector; const size_t kWoff2HeaderSize = 48; const size_t kWoff2EntrySize = 20; - -bool Compress(const uint8_t* data, const size_t len, - uint8_t* result, uint32_t* result_len, - brotli::BrotliParams::Mode mode, int quality) { +bool Compress(const uint8_t* data, const size_t len, uint8_t* result, + uint32_t* result_len, BrotliEncoderMode mode, int quality) { size_t compressed_len = *result_len; - brotli::BrotliParams params; - params.mode = mode; - params.quality = quality; - if (brotli::BrotliCompressBuffer(params, len, data, &compressed_len, result) - == 0) { + if (BrotliEncoderCompress(quality, BROTLI_DEFAULT_WINDOW, mode, len, data, + &compressed_len, result) == 0) { return false; } *result_len = compressed_len; @@ -67,14 +61,14 @@ bool Woff2Compress(const uint8_t* data, const size_t len, uint8_t* result, uint32_t* result_len, int quality) { return Compress(data, len, result, result_len, - brotli::BrotliParams::MODE_FONT, quality); + BROTLI_MODE_FONT, quality); } bool TextCompress(const uint8_t* data, const size_t len, uint8_t* result, uint32_t* result_len, int quality) { return Compress(data, len, result, result_len, - brotli::BrotliParams::MODE_TEXT, quality); + BROTLI_MODE_TEXT, quality); } int KnownTableIndex(uint32_t tag) { @@ -111,7 +105,8 @@ size_t TableEntrySize(const Table& table) { size_t ComputeWoff2Length(const FontCollection& font_collection, const std::vector
& tables, - std::map index_by_offset, + std::map, uint16_t> + index_by_tag_offset, size_t compressed_data_length, size_t extended_metadata_length) { size_t size = kWoff2HeaderSize; @@ -134,7 +129,8 @@ size_t ComputeWoff2Length(const FontCollection& font_collection, // no collection entry for xform table if (table.tag & 0x80808080) continue; - uint16_t table_index = index_by_offset[table.offset]; + std::pair tag_offset(table.tag, table.offset); + uint16_t table_index = index_by_tag_offset[tag_offset]; size += Size255UShort(table_index); // 255UInt16 index entry } } @@ -326,7 +322,7 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length, } std::vector
tables; - std::map index_by_offset; + std::map, uint16_t> index_by_tag_offset; for (const auto& font : font_collection.fonts) { @@ -336,8 +332,9 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length, continue; } - if (index_by_offset.find(src_table.offset) == index_by_offset.end()) { - index_by_offset[src_table.offset] = tables.size(); + std::pair tag_offset(src_table.tag, src_table.offset); + if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) { + index_by_tag_offset[tag_offset] = tables.size(); } else { return false; } @@ -362,7 +359,8 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length, } size_t woff2_length = ComputeWoff2Length(font_collection, tables, - index_by_offset, total_compressed_length, compressed_metadata_buf_length); + index_by_tag_offset, total_compressed_length, + compressed_metadata_buf_length); if (woff2_length > *result_length) { #ifdef FONT_COMPRESSION_BIN fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n", @@ -435,14 +433,15 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length, table.IsReused() ? table.reuse_of->offset : table.offset; uint32_t table_length = table.IsReused() ? table.reuse_of->length : table.length; - if (index_by_offset.find(table_offset) == index_by_offset.end()) { + std::pair tag_offset(table.tag, table_offset); + if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) { #ifdef FONT_COMPRESSION_BIN fprintf(stderr, "Missing table index for offset 0x%08x\n", table_offset); #endif return FONT_COMPRESSION_FAILURE(); } - uint16_t index = index_by_offset[table_offset]; + uint16_t index = index_by_tag_offset[tag_offset]; Store255UShort(index, &offset, result); }