From 481b5abf85aba09174ded51f48dcbb471fd6eb88 Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 18 Mar 2022 14:19:08 +0000 Subject: [PATCH] fix(debugger): handle stream end and partial reads (#1412) --- .../gui/device/debugger/SmaliDebugger.java | 84 ++++++++++++------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java index c8d57118..33a0f365 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java @@ -17,6 +17,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.atomic.AtomicInteger; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,7 +72,6 @@ import io.github.hqktech.JDWP.VirtualMachine.AllThreads.AllThreadsReplyData; import io.github.hqktech.JDWP.VirtualMachine.AllThreads.AllThreadsReplyDataThreads; import io.github.hqktech.JDWP.VirtualMachine.CreateString.CreateStringReplyData; import io.reactivex.annotations.NonNull; -import io.reactivex.annotations.Nullable; import jadx.api.plugins.input.data.AccessFlags; import jadx.gui.device.debugger.smali.RegisterInfo; @@ -152,7 +152,7 @@ public class SmaliDebugger { debugger.initPools(); return debugger; } catch (IOException e) { - throw new SmaliDebuggerException(e); + throw new SmaliDebuggerException("Attach failed", e); } } @@ -617,8 +617,8 @@ public class SmaliDebugger { Packet res = readPacket(inputStream); tryThrowError(res); if (res.isReplyPacket() && res.getID() == 1) { - outputStream.write(JDWP.IDSizes.encode().setPacketID(1).getBytes()); // get id sizes for decoding & encoding of jdwp - // packets. + // get id sizes for decoding & encoding of jdwp packets. + outputStream.write(JDWP.IDSizes.encode().setPacketID(1).getBytes()); res = readPacket(inputStream); tryThrowError(res); if (res.isReplyPacket() && res.getID() == 1) { @@ -632,13 +632,14 @@ public class SmaliDebugger { throw new SmaliDebuggerException("Failed to init JDWP."); } + @SuppressWarnings("ResultOfMethodCallIgnored") private static void handShake(OutputStream outputStream, InputStream inputStream) throws SmaliDebuggerException { byte[] buf = new byte[14]; try { outputStream.write(JDWP.encodeHandShakePacket()); - inputStream.read(buf, 0, 14); + inputStream.read(buf); } catch (Exception e) { - throw new SmaliDebuggerException("jdwp handshake failed, " + e.getMessage()); + throw new SmaliDebuggerException("jdwp handshake failed", e); } if (!JDWP.decodeHandShakePacket(buf)) { throw new SmaliDebuggerException("jdwp handshake failed."); @@ -661,23 +662,19 @@ public class SmaliDebugger { return idGenerator.getAndAdd(1); } - private static byte[] appendBytes(byte[] buf1, byte[] buf2) { - byte[] tempBuf = new byte[buf1.length + buf2.length]; - System.arraycopy(buf1, 0, tempBuf, 0, buf1.length); - System.arraycopy(buf2, 0, tempBuf, buf1.length, buf2.length); - return tempBuf; - } - /** * Read & decode packets from Socket connection */ private void decodingLoop() { Executors.newSingleThreadExecutor().execute(() -> { boolean errFromCallback; - for (;;) { + while (true) { errFromCallback = false; try { Packet res = readPacket(inputStream); + if (res == null) { + break; + } suspendInfo.nextRound(); ICommandResult callback = callbackMap.remove(res.getID()); if (callback != null) { @@ -1129,28 +1126,48 @@ public class SmaliDebugger { /** * Reads a JDWP packet. */ + @Nullable private static Packet readPacket(InputStream inputStream) throws SmaliDebuggerException { - byte[] bytes = new byte[JDWP.PACKET_HEADER_SIZE]; try { - if (inputStream.read(bytes, 0, bytes.length) == bytes.length) { - int len = JDWP.getPacketLength(bytes, 0) - JDWP.PACKET_HEADER_SIZE; - if (len > 0) { - byte[] payload = new byte[len]; - int readSize = 0; - do { - readSize += inputStream.read(payload, readSize, len - readSize); - if (readSize == len) { - bytes = appendBytes(bytes, payload); - break; - } - } while (true); - } - return Packet.make(bytes); + byte[] header = readBytes(inputStream, JDWP.PACKET_HEADER_SIZE); + if (header == null) { + // stream ended + return null; } + int bodyLength = JDWP.getPacketLength(header, 0) - JDWP.PACKET_HEADER_SIZE; + if (bodyLength <= 0) { + return Packet.make(header); + } + byte[] body = readBytes(inputStream, bodyLength); + if (body == null) { + throw new SmaliDebuggerException("Stream truncated"); + } + return Packet.make(concatBytes(header, body)); } catch (IOException e) { - throw new SmaliDebuggerException(e); + throw new SmaliDebuggerException("Read packer error", e); } - throw new SmaliDebuggerException("read packet failed."); + } + + private static byte[] readBytes(InputStream inputStream, int len) throws IOException { + byte[] payload = new byte[len]; + int readSize = 0; + while (true) { + int read = inputStream.read(payload, readSize, len - readSize); + if (read == -1) { + return null; + } + readSize += read; + if (readSize == len) { + return payload; + } + } + } + + private static byte[] concatBytes(byte[] buf1, byte[] buf2) { + byte[] tempBuf = new byte[buf1.length + buf2.length]; + System.arraycopy(buf1, 0, tempBuf, 0, buf1.length); + System.arraycopy(buf2, 0, tempBuf, buf1.length, buf2.length); + return tempBuf; } private static void tryThrowError(Packet res) throws SmaliDebuggerException { @@ -1498,6 +1515,11 @@ public class SmaliDebugger { this.errCode = -1; } + public SmaliDebuggerException(String message, Throwable cause) { + super(message, cause); + this.errCode = -1; + } + public SmaliDebuggerException(String msg, int errCode) { super(msg); this.errCode = errCode; -- GitLab