{"record":{"id":"92c5997e45b49b39","repo":"YunaiV/ruoyi-vue-pro","slug":"createdecodeparser-92c599","errorCode":null,"errorMessage":"[createDecodeParser][解析异常]","messagePattern":"\\[createDecodeParser\\]\\[解析异常\\]","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/codec/length/IotTcpLengthFieldFrameCodec.java","lineNumber":106,"sourceCode":"                }\n\n                // 【重要】切换到读取消息体模式\n                bodyLength.set(frameBodyLength);\n                parser.fixedSizeMode(frameBodyLength);\n            } else {\n                // 阶段 2: 读取消息体，组装完整帧\n                Buffer frame = processFrame(headerBuffer.get(), buffer);\n                // 重置状态，准备读取下一帧\n                bodyLength.set(null);\n                headerBuffer.set(null);\n                parser.fixedSizeMode(headerLength);\n\n                // 【重要】处理完整消息\n                handler.handle(frame);\n            }\n        });\n        parser.exceptionHandler(ex -> {\n            throw new RuntimeException(\"[createDecodeParser][解析异常]\", ex);\n        });\n        return parser;\n    }\n\n    @Override\n    public Buffer encode(byte[] data) {\n        Buffer buffer = Buffer.buffer();\n        // 计算要写入的长度值\n        int lengthValue = data.length - lengthAdjustment;\n        // 写入偏移量前的填充字节（如果有）\n        for (int i = 0; i < lengthFieldOffset; i++) {\n            buffer.appendByte((byte) 0);\n        }\n        // 写入长度字段\n        writeLength(buffer, lengthValue, lengthFieldLength);\n        // 写入消息体\n        buffer.appendBytes(data);\n        return buffer;","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/YunaiV/ruoyi-vue-pro/blob/0418084e222612af2fc1141f566af454f9236ab1/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/codec/length/IotTcpLengthFieldFrameCodec.java#L88-L124","documentation":"The Vert.x RecordParser.exceptionHandler for the length-field codec rethrows any parser error as RuntimeException. Unlike the delimiter codec, the length-field codec also performs its own state-machine throws (errors 54/55), but those throw directly inside the handler, not via exceptionHandler. This handler catches Vert.x parser-level errors — typically a record exceeding MAX_FRAME_LENGTH (64KB) when the decoded body length is huge.","triggerScenarios":"A malformed length field causes the parser to switch to a huge fixedSizeMode that crosses 64KB (maxRecordSize) and the parser fires its exception handler; a device sends a deliberately oversized length (DoS); parser internal error.","commonSituations":"Length field misread (wrong offset/length) yielding a giant body size; malicious oversized-length attack; the negative/zero guards (errors 54/55) pass but the value is still unreasonably large.","solutions":["Add an UPPER bound check on frameBodyLength (e.g. > MAX_FRAME_LENGTH) before calling parser.fixedSizeMode(frameBodyLength), so oversized frames are rejected explicitly instead of letting the parser error.","Verify lengthFieldOffset/lengthFieldLength/lengthAdjustment match the device spec.","Log the cause and close the socket rather than rethrowing on the event loop."],"exampleFix":"// before: only negative/zero checked; huge length slips through to the parser\nparser.fixedSizeMode(frameBodyLength);\n\n// after: also bound the maximum\nif (frameBodyLength > MAX_FRAME_LENGTH) {\n    throw new IllegalStateException(\"frame body too large: \" + frameBodyLength);\n}\nparser.fixedSizeMode(frameBodyLength);","handlingStrategy":"try-catch","validationCode":"// bound the decoded body length before switching the parser mode\nif (frameBodyLength < 0) { throw new IllegalStateException(\"帧长度异常: \" + frameBodyLength); }\nif (frameBodyLength == 0) { throw new IllegalStateException(\"消息体不能为空\"); }\nif (frameBodyLength > MAX_FRAME_LENGTH) {\n    throw new IllegalStateException(\"帧长度超过上限: \" + frameBodyLength);\n}","typeGuard":null,"tryCatchPattern":"// log + close the socket instead of rethrowing on the event loop\nparser.exceptionHandler(ex -> {\n    log.error(\"[createDecodeParser][解析异常]\", ex);\n    socket.close();\n});","preventionTips":["Add an upper-bound check on frameBodyLength so a misread/malicious huge length is rejected explicitly, not by the parser.","Verify lengthFieldOffset/lengthFieldLength/lengthAdjustment match the device spec.","Do not rethrow inside exceptionHandler; log and close the offending socket.","Monitor parse failures per connection to detect DoS or misconfigured devices."],"tags":["tcp","codec","vertx","length-field"],"backgroundTag":null,"analyzedSha":"0418084e222612af2fc1141f566af454f9236ab1","analyzedAt":"2026-08-14T00:56:18.412Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}