{"record":{"id":"49f59447a3efbfc6","repo":"NationalSecurityAgency/ghidra","slug":"range-s-x-x-entirely-exceeds-space-min","errorCode":null,"errorMessage":"Range [%s:%x+%x] entirely exceeds space min","messagePattern":"Range \\[(.+?):%x\\+%x\\] entirely exceeds space min","errorType":"exception","errorClass":"AddressOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/OpenTrace.java","lineNumber":174,"sourceCode":"\t\t */\n\t\tlong minOffset = range.getOffset();\n\t\tif (Long.compareUnsigned(minOffset, space.getMinAddress().getOffset()) < 0) {\n\t\t\tMsg.warn(this, \"Range [%s:%x+%x] partially exceeds space min. Clamping.\"\n\t\t\t\t\t.formatted(range.getSpace(), range.getOffset(), range.getExtend()));\n\t\t\tminOffset = space.getMinAddress().getOffset();\n\t\t}\n\t\telse if (Long.compareUnsigned(minOffset, space.getMaxAddress().getOffset()) > 0) {\n\t\t\tthrow new AddressOutOfBoundsException(\"Range [%s:%x+%x] entirely exceeds space max\"\n\t\t\t\t\t.formatted(range.getSpace(), range.getOffset(), range.getExtend()));\n\t\t}\n\t\tlong maxOffset = range.getOffset() + range.getExtend(); // Use the requested offset, not adjusted\n\t\tif (Long.compareUnsigned(maxOffset, space.getMaxAddress().getOffset()) > 0) {\n\t\t\tMsg.warn(this, \"Range [%s:%x+%x] partially exceeds space max. Clamping.\"\n\t\t\t\t\t.formatted(range.getSpace(), range.getOffset(), range.getExtend()));\n\t\t\tmaxOffset = space.getMaxAddress().getOffset();\n\t\t}\n\t\telse if (Long.compareUnsigned(maxOffset, space.getMinAddress().getOffset()) < 0) {\n\t\t\tthrow new AddressOutOfBoundsException(\"Range [%s:%x+%x] entirely exceeds space min\"\n\t\t\t\t\t.formatted(range.getSpace(), range.getOffset(), range.getExtend()));\n\t\t}\n\t\tAddress min = space.getAddress(minOffset);\n\t\tAddress max = space.getAddress(maxOffset);\n\t\treturn new AddressRangeImpl(min, max);\n\t}\n\n\tpublic Register getRegister(String name, boolean required) {\n\t\tRegister register = trace.getBaseLanguage().getRegister(name);\n\t\tif (required && register == null) {\n\t\t\tthrow new InvalidRegisterError(name);\n\t\t}\n\t\treturn register;\n\t}\n}\n","sourceCodeStart":156,"sourceCodeEnd":190,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/OpenTrace.java#L156-L190","documentation":"Thrown by OpenTrace.toRange when translating a client-supplied AddrRange into an AddressRange. The method clamps a range whose start or end partially falls outside the address space, but if the range's computed end (offset+extend) is strictly below the space's minimum address offset, the whole range is entirely below the space and cannot be represented, so it throws AddressOutOfBoundsException. The %s:%x+%x placeholders report the space name, offset, and extend length of the offending range.","triggerScenarios":"A TraceRmi client sends a memory/register range (e.g. via a setValue, putBytes, or memory-state request) whose offset+extend, treated as unsigned, is less than the target AddressSpace.getMinAddress().getOffset(). This can occur when the extend causes a 64-bit unsigned wrap-around (overflow) or when the client sends a near-zero offset for a space whose minimum is high.","commonSituations":"Client computes extend incorrectly and wraps past zero; a debugger backend reports a range for an address space whose bounds differ from the trace's language definition; mismatched register/memory space between backend and Ghidra language; using a negative extend or zero-length range that lands below the space floor.","solutions":["Validate offset and extend against the space bounds before sending the range: ensure offset+extend (unsigned) >= space min and offset (unsigned) <= space max.","Guard against extend that would make offset+extend wrap around unsigned; cap extend at the space's max address minus the offset.","Confirm the AddressSpace name sent by the client exists in the trace's language/compiler spec and that its min/max match the backend's view.","Check that you are not passing a zero or negative extend length when the space minimum is above zero."],"exampleFix":"// before\nlong maxOffset = offset + extend; // can wrap\nAddrRange range = AddrRange.newBuilder().setSpace(\"ram\").setOffset(offset).setExtend(extend).build();\n\n// after\nlong spaceMin = space.getMinAddress().getOffset();\nlong spaceMax = space.getMaxAddress().getOffset();\nif (Long.compareUnsigned(offset, spaceMin) < 0 ||\n    Long.compareUnsigned(offset + extend, spaceMin) < 0 ||\n    Long.compareUnsigned(offset, spaceMax) > 0) {\n    throw new IllegalArgumentException(\"range outside space bounds\");\n}","handlingStrategy":"validation","validationCode":"long spaceMin = space.getMinAddress().getOffset();\nlong spaceMax = space.getMaxAddress().getOffset();\nlong minOffset = range.getOffset();\nlong maxOffset = range.getOffset() + range.getExtend();\nif (Long.compareUnsigned(minOffset, spaceMax) > 0 ||\n    Long.compareUnsigned(maxOffset, spaceMin) < 0) {\n    throw new IllegalArgumentException(\n        \"range entirely outside space \" + range.getSpace());\n}","typeGuard":null,"tryCatchPattern":"try {\n    AddressRange r = openTrace.toRange(range, true);\n} catch (AddressOutOfBoundsException e) {\n    // range entirely outside the space; reject or skip the operation\n}","preventionTips":["Always compute maxOffset as offset+extend and compare unsigned against space min/max before sending.","Guard extend against unsigned wrap-around by capping at (spaceMax - offset).","Confirm the client and trace agree on the address space name and its bounds."],"tags":["address-space","memory-range","trace-rmi","validation"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}