{"record":{"id":"e7fc668094313445","repo":"NationalSecurityAgency/ghidra","slug":"min-must-precede-max","errorCode":null,"errorMessage":"min must precede max","messagePattern":"min must precede max","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java","lineNumber":512,"sourceCode":"\t\tif (forward) {\n\t\t\tAddress max = all.getMaxAddress();\n\t\t\treturn factory.getAddressSet(start, max);\n\t\t}\n\t\tAddress min = all.getMinAddress();\n\t\treturn factory.getAddressSet(min, start);\n\t}\n\n\t/**\n\t * Create an address range, checking the endpoints\n\t * \n\t * @param min the min address, which must be less than or equal to max\n\t * @param max the max address, which must be greater than or equal to min\n\t * @return the range\n\t * @throws IllegalArgumentException if max is less than min\n\t */\n\tpublic static AddressRange toRange(Address min, Address max) {\n\t\tif (min.compareTo(max) > 0) {\n\t\t\tthrow new IllegalArgumentException(\"min must precede max\");\n\t\t}\n\t\treturn new AddressRangeImpl(min, max);\n\t}\n}\n","sourceCodeStart":494,"sourceCodeEnd":517,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java#L494-L517","documentation":"DBTraceUtils.toRange(min, max) constructs an AddressRange after validating endpoint ordering. It throws IllegalArgumentException(\"min must precede max\") when min.compareTo(max) > 0, i.e. min is strictly greater than max. Equality is allowed (produces a single-address range). This is a precondition guard ensuring the range is well-formed before delegating to AddressRangeImpl, which itself assumes min <= max.","triggerScenarios":"Calling DBTraceUtils.toRange(Address, Address) where the first argument's compareTo is greater than the second. Happens when min/max are swapped, when selection bounds come back reversed (user dragged a selection backwards), or when the two addresses belong to address spaces whose cross-space compareTo ordering is unexpected.","commonSituations":"Plugins deriving ranges from cursor/selection where start can be after end; snapshot/loop code that computes from/to in the wrong order; passing addresses from distinct address spaces (overlay vs base) where the comparison surprises the caller.","solutions":["Normalize the two addresses before calling: assign the smaller to min via a.compareTo(b) > 0 swap.","If you only have logical from/to that may be reversed, swap them explicitly when from.compareTo(to) > 0.","Guard the call site: if (a.compareTo(b) > 0) handle the degenerate/empty case instead of calling toRange."],"exampleFix":"// before\nAddressRange r = DBTraceUtils.toRange(start, end);\n\n// after\nif (start.compareTo(end) > 0) {\n    Address t = start; start = end; end = t;\n}\nAddressRange r = DBTraceUtils.toRange(start, end);","handlingStrategy":"validation","validationCode":"static AddressRange safeRange(Address a, Address b) {\n    if (a.compareTo(b) > 0) { Address t = a; a = b; b = t; }\n    return DBTraceUtils.toRange(a, b);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always derive min/max via compareTo rather than assuming call-site order.","Treat from/to as unordered selection bounds and normalize before constructing a range.","Unit-test range construction with reversed and equal endpoints."],"tags":["address-range","argument-validation","precondition"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}