{"record":{"id":"ad9801c5ccf37d2d","repo":"NationalSecurityAgency/ghidra","slug":"gnu-disassembler-process-died-unexpectedly","errorCode":null,"errorMessage":"GNU disassembler process died unexpectedly.","messagePattern":"GNU disassembler process died unexpectedly\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java","lineNumber":672,"sourceCode":"\n\t\t\t\tString instructionMetadataLine = buffReader.readLine();\n\t\t\t\tif (!instructionMetadataLine.startsWith(\"Info: \")) {\n\t\t\t\t\t// TODO, throw an \"ExternalDisassemblerInterfaceException\"\n\t\t\t\t\t// or some such\n\t\t\t\t\terror = true; // still need to consume remainder of input\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tString[] metadata = instructionMetadataLine.substring(\"Info: \".length()).split(\",\");\n\t\t\t\tresults.add(new GnuDisassembledInstruction(instructionLine.replace('\\t', ' '),\n\t\t\t\t\tInteger.parseInt(metadata[0]), \"1\".equals(metadata[1]),\n\t\t\t\t\tInteger.parseInt(metadata[2]), Integer.parseInt(metadata[3]),\n\t\t\t\t\tInteger.parseInt(metadata[4])));\n\t\t\t}\n\t\t}\n\t\twhile (instructionLine != null && !instructionLine.equals(ENDING_STRING));\n\n\t\tif (!disassemblerProcess.isAlive()) {\n\t\t\tthrow new IOException(\"GNU disassembler process died unexpectedly.\");\n\t\t}\n\n\t\tif (error) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn results;\n\t}\n\n\tprivate String getBytes(ByteProvider byteProvider, int size) throws IOException {\n\t\tStringBuffer byteString = new StringBuffer();\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\tbyteString.append(formatHexString(byteProvider.readByte(i)));\n\t\t}\n\t\treturn byteString.toString();\n\t}\n\n\tprivate String getBytes(MemBuffer mem, int size) {","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java#L654-L690","documentation":"After reading back the full disassembly result loop, GNUExternalDisassembler checks disassemblerProcess.isAlive() and throws if the gdis process has terminated during the read. Unlike [641] which catches the IOException during write/read, this fires when the read loop completed without exception but the process is no longer running — indicating it died mid-response (possibly after emitting partial data). This signals the external disassembler is in a bad state and future calls will fail.","triggerScenarios":"Reaching the post-loop check in getDisassembledInstruction() where instructionLine reached ENDING_STRING or null, but disassemblerProcess.isAlive() returns false. The read loop exited normally but the process exited during or right after the read.","commonSituations":"The gdis process hit a fatal error on the current instruction and exited after writing a partial/terminal response; the OS killed the process (OOM killer, resource limits) between the write and the read completion; a signal was delivered to the child process; the gdis binary has a bug causing crash on certain valid instruction encodings.","solutions":["Check OS-level logs (dmesg, syslog) for evidence of the gdis process being killed (OOM, signal).","Run the gdis binary manually with the same input bytes to reproduce the crash and capture its stderr/exit code.","Restart the disassembler session or reload the configuration to spawn a fresh gdis process.","If the crash is input-specific, skip or annotate the problematic address range and continue disassembly elsewhere.","Update or rebuild the gdis tool if the crash indicates a binary bug."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Check process liveness before relying on results\nif (!disassemblerProcess.isAlive()) {\n    // Process died — do not trust partial results\n    throw new IOException(\"GNU disassembler process is not alive before read.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return getDisassembledInstruction();\n} catch (IOException e) {\n    if (e.getMessage().contains(\"died unexpectedly\")) {\n        restartDisassembler();\n        return getDisassembledInstruction(); // single retry\n    }\n    throw e;\n}","preventionTips":["Check process liveness before AND after the read loop to detect mid-response death.","Capture gdis stderr output to a log for post-crash diagnosis.","Resource-limit the gdis process (ulimit) to prevent it from consuming all host memory.","Test new gdis binaries against known-crashing instruction sequences before deployment."],"tags":["gdis","external-process","process-death","disassembler"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}