{"record":{"id":"c71087941b8c01d6","repo":"NationalSecurityAgency/ghidra","slug":"gdis-execution-error","errorCode":null,"errorMessage":"gdis execution error","messagePattern":"gdis execution error","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java","lineNumber":639,"sourceCode":"\t\t\tdisassemblyRequest += '\\n';\n\t\t}\n\t\telse {\n\t\t\tdisassemblyRequest += OPTIONS_SEPARATOR + disassemblerOptions + SEPARATOR_CHARACTER;\n\t\t}\n\n\t\ttry {\n\t\t\toutputWriter.write(disassemblyRequest);\n\t\t\toutputWriter.flush();\n\t\t\treturn getDisassembledInstruction();\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\t// force a restart of the disassembler on next call to this function\n\t\t\t// TODO: Should we not do this to avoid repeated failure and severe slowdown?\n\t\t\t// User must exit or switch configs/programs to retry after failure\n\t\t\t//disassemblerProcess.destroy();\n\t\t\t//disassemblerProcess = null; // assumes process exit\n\t\t\tMsg.error(this, \"Last gdis request failed: \" + disassemblyRequest);\n\t\t\tthrow new IOException(\"gdis execution error\", e);\n\t\t}\n\t}\n\n\tprivate List<GnuDisassembledInstruction> getDisassembledInstruction() throws IOException {\n\n\t\tList<GnuDisassembledInstruction> results = new ArrayList<>();\n\t\tString instructionLine;\n\n\t\tboolean error = false;\n\t\tdo {\n\t\t\tinstructionLine = buffReader.readLine();\n\t\t\tif (!error && instructionLine != null && !instructionLine.equals(ENDING_STRING) &&\n\t\t\t\t(instructionLine.indexOf(ADDRESS_OUT_OF_BOUNDS) < 0) &&\n\t\t\t\t!instructionLine.startsWith(\"Usage:\") && !instructionLine.startsWith(\"Debug:\")) {\n\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\"","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java#L621-L657","documentation":"Thrown when the GNU external disassembler (gdis) process encounters an IOException while writing the disassembly request to the process's stdin or while reading back the result. The error wraps the underlying IOException. The code logs the last request that failed and then re-throws, forcing the caller to handle the broken pipe / I/O failure. A TODO comment notes the process is intentionally not destroyed to avoid repeated failures, so subsequent calls may also fail until the process recovers or the config is reloaded.","triggerScenarios":"Calling the disassembly method that writes disassemblyRequest to outputWriter and calls getDisassembledInstruction(); any IOException during outputWriter.write/flush or during the subsequent read triggers this. Commonly a broken pipe because the gdis process crashed between requests.","commonSituations":"The gdis binary crashed or was killed (OOM, segfault); the pipe between JVM and the native gdis process broke; the gdis executable is mismatched with the expected protocol version; the host system is under memory pressure causing the child process to die; a corrupt or unexpectedly long instruction stream causes gdis to error out and close its stdout.","solutions":["Check the application log for the preceding 'Last gdis request failed' message — it shows the exact request that broke the pipe.","Verify the gdis executable path and version configured for this language match a working binary (run it manually with the same input).","Restart the Ghidra session or switch/reload the disassembler configuration to force a fresh gdis process spawn.","If the crash is reproducible, isolate the specific instruction bytes in the request and test them against gdis directly to find the offending input.","Check system resources (memory, file descriptors) — native child processes may be killed by the OS under pressure."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before sending a request, verify the process is alive\nif (disassemblerProcess == null || !disassemblerProcess.isAlive()) {\n    // restart the gdis process\n    startDisassembler();\n}","typeGuard":null,"tryCatchPattern":"try {\n    return disassemble(...);\n} catch (IOException e) {\n    if (\"gdis execution error\".equals(e.getMessage())) {\n        // reset process state and retry once\n        resetDisassemblerProcess();\n        return disassemble(...);\n    }\n    throw e;\n}","preventionTips":["Monitor the gdis process health (isAlive) before each disassembly request.","Log the failing request bytes so crashes are reproducible.","Keep the gdis binary version matched to the expected protocol.","Watch system memory — native child processes are OOM-kill candidates."],"tags":["gdis","external-process","io","pipe","disassembler"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}