Nesting STRING Handling Functions

Hi,

The documentation for the STRING Handling functions states that they can only be nested once.

However, in practice, we’ve been able to nest more than two CONCAT functions without any issues - it has always worked reliably for us.
How do you deal with this topic?
Does anyone know the reasoning or background behind this limitation mentioned in the documentation?

The likely reason is stack size, as any function call will take up space on the stack.

It’s a more advanced computer science topic, but if you are familiar with machine language programming or even C programming, you either pass by value (the actual values you are manipulating), or by reference (the address of memory of what you are manipulating). When you pass by value, the stack (the area of memory used for short term memory usage during program execution) has the values you are passing to a function written into it.

CONCAT and the other string functions in the Standard library, are passing by value. There are no limits on a lot of the inputs, only on the outputs (255 characters). So if you
z := CONCAT( CONCAT( x, y), CONCAT( a, CONCAT( b, c))),
and each string is defined as 255 characters + 1 null character, you have now used up likely (6 * 256) 1536 or more bytes of the stack to execute that string manipulation. And if is running in a function within a function block that is running in an action which is called in the PROGRAM _CYCLIC, you are even further into the stack. (i.e. if your function block isn’t using references, pointer to a variable, or raw address inputs, you are using the stack.)

The default stack size for Automation Studio is 65535 bytes, and each cyclic task class has its own stack. Automation Runtime now also has Stack Guarding to make sure Stacks aren’t accidently touched by program code using dynamic variables or raw address manipulations.

2 Likes

Thank you for your detailed response.
For performance reasons, you might consider using brsstrcat, but you should be mindful of the size of the target memory buffer.

I once caused a stack buffer overflow with a recursive function (which was being called recursively within an ACTION). This eventually triggered a hardware watchdog reset and caused the PLC to restart. :smirking_face: