{"record":{"id":"7a6a42ab17fddd49","repo":"NationalSecurityAgency/ghidra","slug":"length-would-cause-address-overflow-in-trace","errorCode":null,"errorMessage":"Length would cause address overflow in trace","messagePattern":"Length would cause address overflow in trace","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java","lineNumber":128,"sourceCode":"\t\t\tboolean truncateExisting) throws TraceConflictedMappingException {\n\t\tProgram tp = to.getProgram();\n\t\tif (tp instanceof TraceProgramView) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\"Mapping destination cannot be a \" + TraceProgramView.class.getSimpleName());\n\t\t}\n\t\tTraceStaticMappingManager manager = from.getTrace().getStaticMappingManager();\n\t\tURL toURL = ProgramURLUtils.getUrlFromProgram(tp);\n\t\tif (toURL == null) {\n\t\t\tnoProject(DebuggerStaticMappingUtils.class);\n\t\t}\n\t\tAddress fromAddress = from.getAddress();\n\t\tAddress toAddress = to.getByteAddress();\n\t\tlong maxFromLengthMinus1 =\n\t\t\tfromAddress.getAddressSpace().getMaxAddress().subtract(fromAddress);\n\t\tlong maxToLengthMinus1 =\n\t\t\ttoAddress.getAddressSpace().getMaxAddress().subtract(toAddress);\n\t\tif (Long.compareUnsigned(length - 1, maxFromLengthMinus1) > 0) {\n\t\t\tthrow new IllegalArgumentException(\"Length would cause address overflow in trace\");\n\t\t}\n\t\tif (Long.compareUnsigned(length - 1, maxToLengthMinus1) > 0) {\n\t\t\tthrow new IllegalArgumentException(\"Length would cause address overflow in program\");\n\t\t}\n\t\tAddress end = fromAddress.addWrap(length - 1);\n\t\t// Also check end in the destination\n\t\tAddressRangeImpl range = new AddressRangeImpl(fromAddress, end);\n\t\tLifespan fromLifespan = from.getLifespan();\n\t\tif (truncateExisting) {\n\t\t\tlong truncEnd = fromLifespan.lmin() - 1;\n\t\t\tfor (TraceStaticMapping existing : List\n\t\t\t\t\t.copyOf(manager.findAllOverlapping(range, fromLifespan))) {\n\t\t\t\texisting.delete();\n\t\t\t\tif (fromLifespan.minIsFinite() &&\n\t\t\t\t\tLifespan.DOMAIN.compare(existing.getStartSnap(), truncEnd) <= 0) {\n\t\t\t\t\tmanager.add(existing.getTraceAddressRange(),\n\t\t\t\t\t\tLifespan.span(existing.getStartSnap(), truncEnd),\n\t\t\t\t\t\texisting.getStaticProgramURL(), existing.getStaticAddress());","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java#L110-L146","documentation":"addMapping() validates that fromAddress + (length-1) does not exceed the maximum address of the source trace's address space (unsigned comparison). If length would run the source range past the trace space's max address, it throws IllegalArgumentException(\"Length would cause address overflow in trace\"). The length is interpreted as an unsigned byte count.","triggerScenarios":"Passing a very large length (or a length computed from a wrong unit, e.g. an address offset instead of a byte count). Mapping near the top of a small address space with a length that wraps past max. Negative length interpreted as a huge unsigned value.","commonSituations":"Computing length as end.subtract(start) without subtracting/adding correctly, yielding an off-by-one overflow. Mapping whole segments whose declared length exceeds the trace space. Using a module length that includes padding beyond the space.","solutions":["Clamp length so fromAddress + (length-1) stays within fromAddress.getAddressSpace().getMaxAddress().","Recompute length as a correct unsigned byte count (toAddress/end - fromAddress/start + 1) and verify against the space maximum.","If you intended a partial range, intersect the desired range with the trace address space before calling addMapping."],"exampleFix":"// before\nlong length = moduleEnd - moduleStart; // possibly off / huge\nDebuggerStaticMappingUtils.addMapping(from, to, length, false);\n\n// after\nAddress maxFrom = from.getAddress().getAddressSpace().getMaxAddress();\nlong maxLen = maxFrom.subtract(from.getAddress()) + 1;\nlong length = Math.min(desiredLength, maxLen);\nDebuggerStaticMappingUtils.addMapping(from, to, length, false);","handlingStrategy":"validation","validationCode":"// Clamp length to the source trace address space before addMapping\nAddress fromAddr = from.getAddress();\nlong maxLenFrom = fromAddr.getAddressSpace().getMaxAddress().subtract(fromAddr) + 1;\nlong safeLength = Math.min(length, maxLenFrom);\nif (Long.compareUnsigned(length - 1, maxLenFrom - 1) > 0) {\n    length = safeLength; // or throw with a clear message\n}","typeGuard":"public static boolean lengthFitsTrace(Address fromAddr, long length) {\n    long maxLen = fromAddr.getAddressSpace().getMaxAddress().subtract(fromAddr) + 1;\n    return Long.compareUnsigned(length, maxLen) <= 0;\n}","tryCatchPattern":"try {\n    DebuggerStaticMappingUtils.addMapping(from, to, length, false);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"overflow in trace\")) {\n        long maxLen = from.getAddress().getAddressSpace().getMaxAddress()\n            .subtract(from.getAddress()) + 1;\n        DebuggerStaticMappingUtils.addMapping(from, to, Math.min(length, maxLen), false);\n    } else throw e;\n}","preventionTips":["Compute length as an unsigned byte count and intersect with the trace address space.","Off-by-one: ensure end = start + length - 1 stays <= max.","Validate both source and destination spaces before calling addMapping."],"tags":["static-mapping","address-overflow","validation","arithmetic"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}