{"record":{"id":"f7acb2a2f2078306","repo":"oracle/graal","slug":"got-illegal-fromindex-value-d-fromindex-must-be-f7acb2","errorCode":null,"errorMessage":"got illegal fromIndex value: %d. fromIndex must be >= 0 and <= input length (%d)","messagePattern":"got illegal fromIndex value: (.+?)\\. fromIndex must be >= 0 and <= input length \\((.+?)\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexExecNode.java","lineNumber":114,"sourceCode":"            if (toIndexLong < fromIndex || toIndexLong > regionToLong) {\n                CompilerDirectives.transferToInterpreterAndInvalidate();\n                throw new IllegalArgumentException(String.format(\"got illegal toIndex value: %d. toIndex must be >= fromIndex (%d) and <= regionTo (%d)\", toIndexLong, fromIndex, regionToLong));\n            }\n            if (toIndexLong != regionToLong) {\n                CompilerDirectives.transferToInterpreterAndInvalidate();\n                throw new UnsupportedOperationException(String.format(\"got non-equal toIndex (%d) and regionTo (%d), support for this is not implemented yet\", toIndexLong, regionToLong));\n            }\n            toIndex = (int) toIndexLong;\n            regionFrom = (int) regionFromLong;\n            regionTo = (int) regionToLong;\n        } else {\n            assert args.length == 2;\n            toIndex = length;\n            regionFrom = 0;\n            regionTo = length;\n            if (fromIndex < 0 || fromIndex > length) {\n                CompilerDirectives.transferToInterpreterAndInvalidate();\n                throw new IllegalArgumentException(String.format(\"got illegal fromIndex value: %d. fromIndex must be >= 0 and <= input length (%d)\", fromIndex, length));\n            }\n        }\n        return execute(frame, input, adjustFromIndex(input, (int) fromIndex, regionFrom, regionTo), toIndex, regionFrom, regionTo);\n    }\n\n    private int adjustFromIndex(TruffleString input, int fromIndex, int regionFrom, int regionTo) {\n        if (mustCheckUTF16Surrogates && fromIndex > regionFrom && fromIndex < regionTo) {\n            assert getEncoding().isUTF16();\n            if (Character.isLowSurrogate((char) inputRead(input, fromIndex)) && Character.isHighSurrogate((char) inputRead(input, fromIndex - 1))) {\n                return fromIndex - 1;\n            }\n        }\n        return fromIndex;\n    }\n\n    public final int inputRead(TruffleString input, int i) {\n        if (charAtNode == null) {\n            CompilerDirectives.transferToInterpreterAndInvalidate();","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexExecNode.java#L96-L132","documentation":"In the 2-argument form (input, fromIndex), RegexExecNode defaults region to the whole string and only validates fromIndex; it must be within [0, inputLength]. A negative start index or one past the end throws IllegalArgumentException.","triggerScenarios":"Calling the 2-arg regex exec with fromIndex < 0 (e.g. an uninitialized -1 'last match end') or fromIndex > input.length() (e.g. start index carried over from a longer previous input).","commonSituations":"Search loops that keep a nextIndex variable initialized to -1 and forget to reset it to 0; passing UTF-16 index computed on a differently encoded string whose code-point length exceeds UTF-16 length.","solutions":["Clamp fromIndex: fromIndex = Math.max(0, Math.min(fromIndex, inputLength)).","Initialize and reset lastIndex to 0 for each new input string.","When converting code-point indices to UTF-16 indices, re-check the bound against the actual string length."],"exampleFix":"// before\nif (m.find()) idx = m.end(); ... exec(input, idx); // idx may exceed new input's length\n\n// after\nidx = Math.max(0, Math.min(idx, input.length()));\nexec(input, idx);","handlingStrategy":"validation","validationCode":"static boolean validFromIndex2Arg(long fromIndex, int inputLength) {\n    return fromIndex >= 0 && fromIndex <= inputLength;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Initialize search-loop indices to 0, not -1.","Clamp carried-over indices against the current input length before each exec.","When working in code points, convert to UTF-16 indices and re-check bounds."],"tags":["regex","truffle","graalvm","argument-validation","bounds"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}