{"record":{"id":"14c086491514982f","repo":"NationalSecurityAgency/ghidra","slug":"max-min-min-min-max-max","errorCode":null,"errorMessage":"max < min: min={min},max={max}","messagePattern":"max < min: min=(.+?),max=(.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Lifespan.java","lineNumber":143,"sourceCode":"\t\t\treturn EMPTY;\n\t\t}\n\t\treturn DOMAIN.atMost(DOMAIN.dec(snap));\n\t}\n\n\t/**\n\t * The domain of snapshot keys\n\t */\n\tpublic enum Domain implements Span.Domain<Long, Lifespan> {\n\t\tINSTANCE;\n\n\t\t@Override\n\t\tpublic Lifespan closed(Long min, Long max) {\n\t\t\treturn closed(min.longValue(), max.longValue());\n\t\t}\n\n\t\tpublic Lifespan closed(long min, long max) {\n\t\t\tif (max < min) {\n\t\t\t\tthrow new IllegalArgumentException(\"max < min: min=\" + min + \",max=\" + max);\n\t\t\t}\n\t\t\treturn new Impl(min, max);\n\t\t}\n\n\t\t@Override\n\t\tpublic Lifespan newSpan(Long min, Long max) {\n\t\t\treturn new Impl(min, max);\n\t\t}\n\n\t\tpublic Lifespan value(long n) {\n\t\t\treturn new Impl(n, n);\n\t\t}\n\n\t\t@Override\n\t\tpublic Lifespan atMost(Long max) {\n\t\t\treturn atMost(max.longValue());\n\t\t}\n","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Lifespan.java#L125-L161","documentation":"Thrown by Lifespan.Domain.closed(long min, long max): a lifespan is an inclusive snapshot-key range [min,max], so max < min is an empty/invalid span. Ghidra treats the minimum snapshot key as the lower bound, so an inverted range is a programming error rather than an empty-range request.","triggerScenarios":"Constructing a Lifespan via Domain.INSTANCE.closed(min, max), Lifespan.closed(...), or any code path that builds a span from two keys where the 'max' key is smaller than the 'min' key (e.g. interchanged arguments, or a computed end that came before the start).","commonSituations":"Swapping min/max arguments; computing max from a sub-snapshot's parent where ordering is inverted; passing user-supplied from/to snapshot indices without ordering; off-by-one in span arithmetic.","solutions":["Order the bounds before constructing: long lo = Math.min(a, b), hi = Math.max(a, b); then Lifespan.closed(lo, hi).","Verify the caller's snapshot keys are in ascending order.","If an empty result is intended, handle that case explicitly rather than passing an inverted range.","Add an assertion/unit test on the span constructor inputs."],"exampleFix":"// before\nLifespan span = Lifespan.span(fromSnap, toSnap); // toSnap < fromSnap\n\n// after\nlong lo = Math.min(fromSnap, toSnap);\nlong hi = Math.max(fromSnap, toSnap);\nLifespan span = Lifespan.span(lo, hi);","handlingStrategy":"validation","validationCode":"long lo = Math.min(a, b), hi = Math.max(a, b);\nLifespan span = Lifespan.span(lo, hi);","typeGuard":"static boolean validSpan(long min, long max) { return max >= min; }","tryCatchPattern":null,"preventionTips":["Order snapshot-key bounds before constructing a Lifespan.","Validate ascending order at the boundary where user/external keys enter.","Handle 'empty range' as an explicit case rather than an inverted span."],"tags":["ghidra","trace-modeling","lifespan","span","illegal-argument"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}