JesusFreke / smali

smali/baksmali
6.29k stars 1.07k forks source link

dexlib2: MutableMethodImplementation corrupts exception table. #809

Closed melkonyan closed 3 years ago

melkonyan commented 3 years ago

Code

 for (TryBlock<? extends ExceptionHandler> tryBlock: methodImplementation.getTryBlocks()) {
            Label startLabel = newLabel(codeAddressToIndex, tryBlock.getStartCodeAddress());
            Label endLabel = newLabel(codeAddressToIndex, tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount());

            for (ExceptionHandler exceptionHandler: tryBlock.getExceptionHandlers()) {
                tryBlocks.add(new BuilderTryBlock(startLabel, endLabel,
                        exceptionHandler.getExceptionTypeReference(),
                        newLabel(codeAddressToIndex, exceptionHandler.getHandlerCodeAddress())));
            }
        }

creates a new exception table with one handler per try block. I presume that's done to simplify bookkeeping when new catch blocks are added.

However, when converting to ImmutableMethodImplementation, I expect exception table to be converted back to proper format (namely, into non-overlapping try blocks with multiple handlers).

What is the best way to do it?

JesusFreke commented 3 years ago

The try blocks in dexlib2 are a bit more relaxed than specified in the dex format. From the MethodImplementation.getTryBlocks javadoc

Try blocks may overlap freely, and do not need to be strictly nested, as in java. This is a more relaxed
requirement than specified by the dex format, where try blocks may not overlap, and must be specified in
ascending order. When writing to a dex file, the try blocks will be massaged into the appropriate format.

The transformed try blocks/exception handlers in MutableMethodImplementation should be functionally equivalent to the original.

The conversion back into the stricter dex style happens in DexWriter. In particular by the TryListBuilder class.

melkonyan commented 3 years ago

Thanks Jesus,

I'll think we'll convert try blocks manually using TryListBuilder then.

Cheers Alex