pxb1988/dex2jar · error · BadOpException

index-out-of-range for

Error message

index-out-of-range for %s index: %d

What it means

DexFileReader throws BadOpException when an instruction references a method/proto/field/type/string index that is out of range of the corresponding ids table (e.g. idx >= method_ids_size or idx2 >= proto_ids_size for invoke-type ops). The library validates indexability before continuing so downstream lookups cannot read past the tables. It indicates a corrupt or deliberately malformed dex.

Solutions

  1. Verify the dex with an official verifier before conversion.
  2. Rebuild or re-extract the dex from a known-good APK.
  3. Use a tool that repairs dex headers/id tables before running d2j.
  4. Catch BadOpException per method/class and skip the invalid one.

Example fix

// before
dexReader.accept(visitor, 0);
// after
try {
    dexReader.accept(visitor, 0);
} catch (BadOpException e) {
    LOG.warn("out-of-range index: " + e.getMessage());
}
Defensive patterns

Strategy: try-catch

Validate before calling

// parse header and ensure id tables look sane before decoding
int methodIdsSize = ByteBuffer.wrap(data, 88, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
if (methodIdsSize < 0 || methodIdsSize > data.length / 8) throw new IllegalArgumentException("implausible method_ids_size");

Try / catch

try {
    dexReader.accept(visitor, 0);
} catch (BadOpException e) {
    LOG.warn("index out of range: " + e.getMessage());
}

Prevention

When it happens

Trigger: Decoding a dex whose instructions contain index operands equal to or larger than method_ids_size/proto_ids_size/etc., detected in the op.indexType switch that sets canContinue = false.

Common situations: Analyzing obfuscated or packed APKs that corrupt index tables to break static tools; fuzzed dex inputs; dex files spliced between versions.

Related errors


AI-assisted analysis of pxb1988/dex2jar@b5bda4fb49 (2026-09-08). Data as JSON: /api/errors/3bc7e4d0469d53e4. Report an issue: GitHub.

Appendix: source

Thrown at dex-reader/src/main/java/com/googlecode/d2j/reader/DexFileReader.java:1299

                canContinue = idx < method_ids_size;
                break;
            case kIndexFieldRef:
                idx = ushort(insns, u1offset + 2);
                canContinue = idx < field_ids_size;
                break;
            case kIndexCallSiteRef:
                idx = ushort(insns, u1offset + 2);
                canContinue = idx < call_site_ids_size;
                break;
            case kIndexMethodAndProtoRef:
                idx = ushort(insns, u1offset + 2);
                int idx2 = ushort(insns, u1offset + 6);
                canContinue = idx < method_ids_size && idx2 < proto_ids_size;
                break;
            default:
            }
            if (!canContinue) {
                throw new BadOpException("index-out-of-range for %s index: %d", op, idx);
            }
        }

        if (canContinue && op.canContinue()) {
            if (op == Op.NOP) {
                switch (insns[u1offset + 1]) {
                case 0x00:
                    q.add(offset + Op.NOP.format.size);
                    break;
                case 0x01: {
                    int size = ushort(insns, u1offset + 2);
                    q.add(offset + (size * 2) + 4);
                    break;
                }
                case 0x02: {
                    int size = ushort(insns, u1offset + 2);
                    q.add(offset + (size * 4) + 2);
                    break;

View on GitHub (pinned to b5bda4fb49)