Any SUBSTR reference that you use must be such that its use would not raise the STRINGRANGE condition if that condition were enabled.
If the STRINGRANGE condition is not enabled (and by default, it is not), then a SUBSTR reference that is invalid can cause the compiled code to overwrite storage allocated for other purposes and that, in turn, can lead to data corruptions or abends.
For example, in the following code, if the value in the variable n is larger than 100, then the SUBSTR reference is invalid and the generated code may overwrite storage allocated to other variables.
dcl f ext entry;
dcl a char(100);
call f( 'test' || substr(a,1,n) );
You can easily detect such bad code during test by compiling your programs with the PREFIX(STRINGRANGE) compiler option.
The SUBSTR suboption introduced in V3R8 to the USAGE compiler option can allow some of this incorrect code to be accepted. However, it would be best not to use this option and instead to correct your code by, for example, changing the declare of a above to have a length at least as large as the largest value that n could assume and if the maximum value for n is unknown, then by changing the declare of a to have a length of 32767.
In some situations, the old compiler also generated code for SUBSTR references of the form SUBSTR(X,1,N) where X was CHAR and N was greater than 32767. However, such references are invalid and would have raised STRINGSIZE if it were enabled. The new compiler enforces the restriction that the length of a SUBSTR reference must be less than 32768 for CHAR and BIT references and less than 16384 for GRAPHIC and WIDECHAR references, and you must correct any code that does not conform to these rules.