Analysis of the consequences of array subscript exceeding the limit

 

Because array subscript overflow may cause Page Faults and other potential problems.The CheckBounds error code used to handle Page Faults also applies in this article.
TwinCAT users are familiar with the issue of non-BOOL values appearing in BOOL variables, as the red variable values are quite eye-catching in the Login state.

This article takes the testing of a piece of client program code as an example to analyze the principle of individualBOOL variable values becoming invalid due to array subscript overflow.Based on this principle, it derives other possible consequences caused by array subscript overflow, and proposes suggestions for avoiding subscript overflow.
1. Test process:
Usually, when customers find this kind of problem, the program has already been written and the machine is already being debugged or running.Unless they take over remotely or go directly to the customer's site, they can only give some suggestions without seeing the program.Even if they can see the program, it is already quite large and it is difficult to understand it in a short time without developing the code themselves.Fortunately, the customer extracted a program version specifically for reproducing the problem, so I was able to test it on my computer.
Because it was not a page fault, I first did not think of an array overflow, but assumed it was an automatic address conflict.In the past, when I encountered this situation, renaming the variable or setting a fixed address for the variable usually worked.However, I never found the root cause, so the solution was only temporary.
To find the root cause, it is necessary to manually locate the line of code that assigns an incorrect value to the BOOL variable.To do this, set breakpoints in the MAIN program and monitor the erroring BOOL variable to identify the subroutine that causes the illegal value.By analogy, set breakpoints in subroutines in segments to find the first line of code that causes the illegal value.
The test found that in the following code segment, when I=16#1D, that is, 29, the BOOL variable appears with a red invalid value.This indicates that when I=28, an invalid value was assigned to the BOOL variable.

Looking at the code, we found that the array index did indeed exceed the limit:


MessageToSend is a 32-element array, but the code allows the range of values for the subscripts [2*i] and [2*I-1] to be 1-64.
So why does the operation of MessageToSend[56] always affect these variables, but not other variables?
Use the pointer to extract the memory addresses of MessageToSend, the three affected exception variables, and the two unaffected variables:

From the above figure, it can be found that the offset between the affected variable memory address and the array variable head address is a multiple of 10.
Let's look at the structure of the struct again:

The CobID operated in the code is located in the first and second bytes of the structure.However, MessageToSend has 32 elements, each of which occupies 10 bytes of the structure, so the array occupies a total of 320 bytes.When the array index exceeds the limit, for example:
The offset between the first address of MessageToSend[33] and the first address of MessageToSend is 320,
When I=28 in the code, the subscripts [2*i] and [2*I-1] are 56 and 55, respectively, which means that the CobID values assigned to MessageToSend[55] and MessageToSend[56] are actually the addresses of MessageToSend starting at offset 540 and 550 bytes.From the variable address offsets obtained from nOffset, it can be seen that this offset is exactly the value of nOffset[2] and nOffset[3], which is why it always affects these variables and not others.
2. Possible consequences of array subscript out of bounds
From the above analysis, it can be seen that array index overflow causes the program to "legally and unexpectedly" operate on addresses outside the array memory, and those addresses may be other boolean variables, or other integer or floating-point variables.During online monitoring, only the BOOL variable will report that the current value is invalid and be marked in bold red. However, other types of variables will not be prompted when they are changed by the overflowed array.
When some bytes of a floating-point number are unexpectedly changed, a large or small value may appear.
The value of an integer or double-integer may not fall within a reasonable range.
If the variables representing the status bits and status words are accidentally changed, then each bit appears to be reasonable, and the system will make inexplicable judgments, resulting in the device not acting or acting inappropriately.
In this way, it can be understood why changing the variable name or setting a fixed address can prevent these variables from being affected.It is because it only avoids the original affected memory address.As for the rules for PLC assigning memory addresses to internal variables, such as the order of variable names and addresses, they are not the root of the problem.
At the same time, it can also be understood that modifying variable names or setting fixed addresses only avoids known consequences, while other undetected variables that may be affected completely are not addressed, and potential problems still exist.
3. It is necessary to check whether there is an array index out of bounds
Because array subscript out-of-bounds does not cause immediate PLC crash like zero division or pointer error, this problem is more hidden.However, once it occurs, the consequences may be serious.Therefore, regardless of whether there is a problem with the device, the CheckBounds function should be added at the beginning of program debugging to check for out-of-bounds conditions.
If the device has experienced inexplicable problems, this function should be used first to check.
For specific methods, see the document CheckBounds for positioning error codes
4. Suggestions for avoiding array index out of bounds (please add)


Use constants more often and values less often in variable declarations and program code.
When declaring an array, use constants for the upper and lower indices as much as possible.For example:
Define constants first: IMaxEL1889:INT:=5;
Redefine the array: AEL1889: ARRAY[1.. IMaxEL1889] OF WORD;
When operating on arrays in programs, constants are also used instead of numbers
FOR I:=1 TO IMaxEL2889 DO
……
……
END_FOR
In this way, when the program is modified or transplanted, if the size of the array needs to be changed, it is not necessary to modify every reference in the program code.Otherwise, if a mistake is made, it is easy for the array to overflow.
b. When operating array subscripts, add a judgment.
For example: J:=LIMIT(min, I, max)