String Index Always Out Of Bounds
ID |
java.string_index_out_of_bounds |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
reliability |
Description
Reports a narrow, literal-only subset of String index calls (charAt, substring,
codePointAt, the two-argument indexOf/lastIndexOf, and setCharAt on
StringBuilder/StringBuffer) that always throw StringIndexOutOfBoundsException: a negative
literal index, a substring(a, b) with both literal and a > b, or an index that is the same
string’s own length() (or length() plus a literal offset that is still out of range).
This is a subset of the defect by design: no value is tracked through a variable, so
charAt(i) for a plain variable i is never reported, and a call on a different receiver
than the one whose length() is used (a.charAt(b.length())) is never decided. Upstream’s own
check additionally tracks a literal string receiver’s exact length ("str".substring(25)) and a
handful of further methods (codePointCount, getChars, subSequence,
offsetByCodePoints); this rule reports neither.
|
Rationale
Every one of these calls throws unconditionally once the index is out of range — there is no partial result, only an exception. One example per reported category:
String speech = "Lorem ipsum dolor sit amet";
char none = speech.charAt(-1); // (1) negative literal index
String tail = speech.substring(9, 4); // (2) substring(a, b), both literal, a > b
char last = speech.charAt(speech.length()); // (3) the receiver's own length() as an index
Because the index is a literal, or a literal offset from the very string being indexed, the crash is guaranteed on every execution path that reaches the line — it is not a corner case that only shows up with unusual input.
Remediation
Use an index that is provably within 0 and length() - 1 (or length() itself for
`substring’s end index):
String speech = "Lorem ipsum dolor sit amet";
char first = speech.charAt(0); // Compliant
String tail = speech.substring(4, 9); // Compliant - begin before end
char last = speech.charAt(speech.length() - 1); // Compliant
String whole = speech.substring(0, speech.length()); // Compliant - length() is a valid end index