Skip to content

fix(getclass): reach non-BMP class names by encoding the query as MUTF-8 - #46

Merged
MG1937 merged 1 commit into
MG1937:dev-0.1.0from
dhtzs:fix/mutf8-class-lookup
Oct 11, 2026
Merged

MG1937 merged 1 commit into
MG1937:dev-0.1.0from
dhtzs:fix/mutf8-class-lookup

Conversation

@dhtzs

@dhtzs dhtzs commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

ApkHandler.get_class_dex encoded its query with .encode("utf-8"), but dex string_data_item is MUTF-8: a code point above the BMP is stored as a surrogate pair (CESU-8). For ASCII and BMP names the two encodings are byte-identical, so nothing showed — but an astral class name could never match, and the lookup reported "class not found" before decompilation ever ran.

Measured against _find_type_idx directly:

query encoding Ll/\U00010000; (astral) Ll/\u06e1; (BMP) Lexample/Test;
UTF-8 (before) not found found found
MUTF-8 (after) found found found

Encoding the query the way the dex stores it is the whole fix. No linear fallback is needed: CESU-8 preserves UTF-16 code-unit ordering, so the binary search over the type table stays valid.

Scope

Only names containing a code point above the BMP change behaviour — ASCII and BMP names encode identically both ways, so their byte-for-byte path is untouched. I compared both encodings against each other before switching.

The encoder is mutf8 (already a dependency, used by dex_builder), a compiled extension costing ~19ms to import. It is imported only for a name that actually needs it, so ordinary lookups pay nothing, and a successful astral lookup is net-zero anyway since decompilation loads mutf8 moments later on the same path.

Verification

  • python tests/run_tests.py --require-decompiler → 107 tests, OK.
  • The full chain now resolves end to end: decompile_class(apk, "Ll/𐀀;") returns source, and every name from a class listing feeds back into decompile_class.
  • Startup unchanged within noise: 108.40ms before → 109.27ms after (benchmark_startup.py, 9 samples; this machine reads 108–111ms with or without the change, over the 100ms Linux-CI budget either way).

Tests

Nothing in the tree covers this path today. tests/test_mutf8_strings.py is the natural home — it already owns the MUTF-8 cases — e.g. a fixture whose descriptors are sorted by UTF-16 code units with an astral entry, asserting get_class_dex resolves it. Happy to add that to this PR, or as a follow-up if you'd rather keep the change minimal.

Copilot AI balanced review requested due to automatic review settings October 11, 2026 09:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@dhtzs
dhtzs changed the base branch from main to dev-0.1.0 October 11, 2026 09:51
@MG1937
MG1937 merged commit 7c96a31 into MG1937:dev-0.1.0 Oct 11, 2026
2 checks passed
@dhtzs
dhtzs deleted the fix/mutf8-class-lookup branch October 12, 2026 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants