summaryrefslogtreecommitdiff
path: root/common_smp/src/tx_thread_stack_analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'common_smp/src/tx_thread_stack_analyze.c')
-rw-r--r--common_smp/src/tx_thread_stack_analyze.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/common_smp/src/tx_thread_stack_analyze.c b/common_smp/src/tx_thread_stack_analyze.c
index 080d0052..ecd7ee13 100644
--- a/common_smp/src/tx_thread_stack_analyze.c
+++ b/common_smp/src/tx_thread_stack_analyze.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -70,6 +72,10 @@ TX_INTERRUPT_SAVE_AREA
ULONG *stack_ptr;
ULONG *stack_lowest;
ULONG *stack_highest;
+ULONG *probe_ptr;
+ULONG *stack_limit;
+ULONG probe_count;
+UINT fill_present;
ULONG size;
@@ -94,10 +100,16 @@ ULONG size;
/* Pickup the highest stack pointer. */
stack_highest = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr);
- /* Determine if the pointer is null. */
- if (stack_highest != TX_NULL)
+ /* Determine if the pointer is null or if the highest stack pointer is not above the
+ start of the stack. The latter indicates a stack overflow or a corrupted thread
+ control block, and the unsigned pointer arithmetic in the binary search below would
+ wrap around and never converge, hanging the caller. */
+ if ((stack_highest != TX_NULL) && (stack_highest > stack_lowest))
{
+ /* Remember the upper bound of the search so the scan below cannot run past it. */
+ stack_limit = stack_highest;
+
/* Restore interrupts. */
TX_RESTORE
@@ -110,8 +122,49 @@ ULONG size;
size = (ULONG) (TX_ULONG_POINTER_DIF(stack_highest, stack_lowest))/((ULONG) 2);
stack_ptr = TX_ULONG_POINTER_ADD(stack_lowest, size);
- /* Determine if the pattern is still there. */
- if (*stack_ptr != TX_STACK_FILL)
+ /* Determine if the pattern is still there. To avoid stopping on an
+ unwritten hole inside an otherwise used region, require several
+ consecutive fill words, working towards the lowest address. The scan
+ stops at the lowest known fill location, since everything at or below
+ that point is already known to hold the fill pattern. */
+ fill_present = TX_TRUE;
+ probe_ptr = stack_ptr;
+ probe_count = TX_THREAD_STACK_ANALYZE_FILL_WORDS;
+ while (probe_count != ((ULONG) 0))
+ {
+
+ /* Determine if this word still holds the fill pattern. */
+ if (*probe_ptr != TX_STACK_FILL)
+ {
+
+ /* No, the probe location is in use. */
+ fill_present = TX_FALSE;
+ probe_count = ((ULONG) 0);
+ }
+ else
+ {
+
+ /* Yes, account for this word. */
+ probe_count--;
+
+ /* Determine if the lowest known fill location has been reached. */
+ if (probe_ptr <= stack_lowest)
+ {
+
+ /* Yes, nothing further to check. */
+ probe_count = ((ULONG) 0);
+ }
+ else
+ {
+
+ /* Position to the previous word in the stack. */
+ probe_ptr = TX_ULONG_POINTER_SUB(probe_ptr, 1);
+ }
+ }
+ }
+
+ /* Determine if the probe location is in use. */
+ if (fill_present == TX_FALSE)
{
/* Update the stack highest, since we need to look in the upper half now. */
@@ -127,7 +180,7 @@ ULONG size;
} while(size > ((ULONG) 1));
/* Position to first used word - at this point we are within a few words. */
- while (*stack_ptr == TX_STACK_FILL)
+ while ((stack_ptr < stack_limit) && (*stack_ptr == TX_STACK_FILL))
{
/* Position to next word in stack. */