{"record":{"id":"a69734779ce3e5e4","repo":"NationalSecurityAgency/ghidra","slug":"datatype-s-has-dynamic-length","errorCode":null,"errorMessage":"DataType %s has dynamic length","messagePattern":"DataType (.+?) has dynamic length","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/emulation/DebuggerEmulateFunctionDialog.java","lineNumber":634,"sourceCode":"\t\tbyte[] addrToBytes(Address address, int length) {\n\t\t\treturn Utils.longToBytes(address.getOffset(), length, language.isBigEndian());\n\t\t}\n\n\t\tvoid allocate(int length) {\n\t\t\t// Extension point\n\t\t}\n\n\t\tabstract T newRow(String name, VarStorage storage, DataType type);\n\n\t\tpublic void addPointerVars(int count) {\n\t\t\tif (!(getBaseDataType(from.getType()) instanceof Pointer ptr)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tDataType dest = ptr.getDataType();\n\t\t\tint length = dest.getLength();\n\t\t\tint alignedLen = dest.getAlignedLength();\n\t\t\tif (length == -1) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"DataType %s has dynamic length\".formatted(dest));\n\t\t\t}\n\t\t\tallocate((alignedLen * (count - 1)) + length);\n\n\t\t\tAddressSpace space = function.getProgram().getLanguage().getDefaultDataSpace();\n\t\t\tint offset = 0;\n\n\t\t\tif (!(DataTypeUtilities.getBaseDataType(dest) instanceof Composite composite)) {\n\t\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\t\tVarStorage deref = from.getStorage().deref(language, space, offset, length);\n\t\t\t\t\tString name = count == 1 // LATER: Cull unnecessary ()s?\n\t\t\t\t\t\t\t? \"*(%s)\".formatted(from.name)\n\t\t\t\t\t\t\t: \"(%s)[%d]\".formatted(from.name, i);\n\t\t\t\t\tfindRow(into, name).ifPresent(into::delete);\n\t\t\t\t\tT row = newRow(name, deref, dest);\n\t\t\t\t\tinto.add(row);\n\t\t\t\t\tadded.add(row);\n","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/emulation/DebuggerEmulateFunctionDialog.java#L616-L652","documentation":"Thrown by InputsTableModel.addPointerVars when the data type pointed to by a pointer argument reports length -1, meaning it is dynamically sized. The function emulator needs a concrete byte count to allocate (and dereference) pointer destination storage; variable-length types like strings or zero-terminated structures cannot be allocated to a fixed size.","triggerScenarios":"Calling addPointerVars(count) on an input row whose base data type is a Pointer, where ptr.getDataType().getLength() returns -1 (e.g., the pointer targets a char* / TerminatedStringDataType, or a variable-length structure).","commonSituations":"Functions taking char*/string arguments; pointers to forward-declared or undefined types Ghidra treats as dynamic; pointer destinations to variable-length composites.","solutions":["Change the argument's declared type from a dynamic type to a fixed-length equivalent (e.g., char* -> a fixed-size byte array type) before emulation.","Resolve the pointer destination to a concrete DataType with a known length in the program's data type manager.","Avoid enabling pointer-variable allocation (the 'count > 0' path) for inputs whose target type is dynamic.","Replace a dynamic string type with a fixed char[ N ] array type for the emulation session."],"exampleFix":"// before\nDataType dest = ptr.getDataType();\nint length = dest.getLength(); // -1 for dynamic types\n// allocate((alignedLen*(count-1))+length) -> underflows / throws\n\n// after\nDataType dest = ptr.getDataType();\nif (dest.getLength() == -1) {\n    Msg.warn(this, \"Skipping dynamic-length pointer dest: \" + dest);\n    return;\n}","handlingStrategy":"validation","validationCode":"DataType dest = ((Pointer) DataTypeUtilities.getBaseDataType(from.getType())).getDataType();\nboolean ok = dest.getLength() != -1;","typeGuard":"static boolean hasFixedLength(Pointer p) {\n    return p.getDataType() != null && p.getDataType().getLength() != -1;\n}","tryCatchPattern":"try {\n    tableModel.addPointerVars(count);\n} catch (IllegalArgumentException e) {\n    Msg.showWarn(this, null, \"Cannot add pointer vars\", e.getMessage());\n}","preventionTips":["Resolve pointer target types to concrete fixed-length types before emulation.","Avoid dynamic types (strings, variable structs) as pointer destinations."],"tags":["emulation","datatype","pointer","dynamic-length"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}