From 2175f5d050743317c563ec9414e0f83a47f7fbc4 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 24 Apr 2023 21:13:18 +0000 Subject: [PATCH] [subset] Fix inefficient ItemVariationStore subsetting w/ retain_gids. ItemVariationStore is relying on the assumption that the inner_map is populated for all output glyphs, this is not true for subsetting operations with retain gids enabled. Fixes fuzzer timeout: https://oss-fuzz.com/testcase-detail/4575222591520768. --- src/hb-bimap.hh | 9 +++++++++ src/hb-ot-layout-common.hh | 14 ++++++-------- src/hb-ot-var-hvar-table.hh | 10 ++++------ ...-minimized-hb-subset-fuzzer-4575222591520768 | Bin 0 -> 91107 bytes .../Fraunces.retain-gids.26,66,69,124,125.ttf | Bin 0 -> 21296 bytes .../variable/Fraunces.retain-gids.61.ttf | Bin 0 -> 4508 bytes test/subset/data/tests/variable.tests | 1 + 7 files changed, 20 insertions(+), 14 deletions(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768 create mode 100644 test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf create mode 100644 test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf diff --git a/src/hb-bimap.hh b/src/hb-bimap.hh index 8e8c98871..9edefd971 100644 --- a/src/hb-bimap.hh +++ b/src/hb-bimap.hh @@ -83,9 +83,15 @@ struct hb_bimap_t unsigned int get_population () const { return forw_map.get_population (); } + protected: hb_map_t forw_map; hb_map_t back_map; + + public: + auto keys () const HB_AUTO_RETURN (+ forw_map.keys()) + auto values () const HB_AUTO_RETURN (+ forw_map.values()) + auto iter () const HB_AUTO_RETURN (+ forw_map.iter()) }; /* Inremental bimap: only lhs is given, rhs is incrementally assigned */ @@ -108,6 +114,9 @@ struct hb_inc_bimap_t : hb_bimap_t hb_codepoint_t skip () { return next_value++; } + hb_codepoint_t skip (unsigned count) + { return next_value += count; } + hb_codepoint_t get_next_value () const { return next_value; } diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 9d1c10582..ad8a6e0be 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -2501,10 +2501,9 @@ struct VarData { for (r = 0; r < src_word_count; r++) { - for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + for (unsigned old_gid : inner_map.keys()) { - unsigned int old = inner_map.backward (i); - int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size); + int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size); if (delta < -65536 || 65535 < delta) { has_long = true; @@ -2521,10 +2520,9 @@ struct VarData bool short_circuit = src_long_words == has_long && src_word_count <= r; delta_sz[r] = kZero; - for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + for (unsigned old_gid : inner_map.keys()) { - unsigned int old = inner_map.backward (i); - int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size); + int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size); if (delta < min_threshold || max_threshold < delta) { delta_sz[r] = kWord; @@ -2585,8 +2583,8 @@ struct VarData { unsigned int region = regionIndices.arrayZ[r]; if (region_indices.has (region)) continue; - for (unsigned int i = 0; i < inner_map.get_next_value (); i++) - if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0) + for (hb_codepoint_t old_gid : inner_map.keys()) + if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0) { region_indices.add (region); break; diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 00a8e1f0b..461b2b9cd 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -185,12 +185,8 @@ struct hvarvvar_subset_plan_t { retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS; outer_map.add (0); - for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) - { - hb_codepoint_t old_gid; - if (plan->old_gid_for_new_gid (gid, &old_gid)) - inner_sets[0]->add (old_gid); - } + for (hb_codepoint_t old_gid : plan->glyphset()->iter()) + inner_sets[0]->add (old_gid); hb_set_union (adv_set, inner_sets[0]); } @@ -202,10 +198,12 @@ struct hvarvvar_subset_plan_t if (retain_adv_map) { for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + { if (inner_sets[0]->has (gid)) inner_maps[0].add (gid); else inner_maps[0].skip (); + } } else { diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768 new file mode 100644 index 0000000000000000000000000000000000000000..a225a279f9d98a1ba7b3fd2f6cfcc87e022e034e GIT binary patch literal 91107 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 K?)*XlqW=f9wTUqR literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf b/test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf new file mode 100644 index 0000000000000000000000000000000000000000..310bc67b78b1f8bd836115e166d53abd04404b38 GIT binary patch literal 21296 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 Nr)%&b%3ws${{w$P+sXg{ literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf b/test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c77d9f16b2a4603248defadab58c91c2cf270ab8 GIT binary patch literal 4508 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