Restored the random stack fill value cleared during thread creation (#732)

Fixes #723

With `TX_ENABLE_STACK_CHECKING` and `TX_ENABLE_RANDOM_NUMBER_STACK_FILLING` both
enabled, `_tx_thread_create` picked a random byte, stored it in
`tx_thread_stack_fill_value`, filled the stack with it -- and then cleared the
whole control block with `TX_MEMSET`. The stack held the pattern while the
control block claimed zero, so `TX_THREAD_STACK_CHECK` and
`_tx_thread_stack_analyze` compared against the wrong value for the entire life
of the thread.

The value is now computed into a local and written back after the clear. The
clear stays where it is, because the module manager's error checking walks the
created list before the control block may be touched.

Fixed in `common/src/tx_thread_create.c`, `common_smp/src/tx_thread_create.c`
and `txm_module_manager_thread_create.c`, where it additionally left a user-mode
module thread's kernel stack filled with zeros.

`threadx_thread_stack_fill_value_test` creates sixteen unstarted threads and
checks each control block against the pattern in its stack, tolerating a random
zero byte without letting that hide the defect. Added to both suites: `ERROR #3`
on `dev` in `stack_checking_rand_fill_build`, green with the fix. Five tx
configurations at 104 tests, five SMP at 117, and all three sources clean under
`-Wall -Wextra` across every combination of the four stack-filling switches.

Assisted-by: Copilot (Opus 5) <noreply@github.com>
This commit is contained in:
Frédéric Desbiens
2026-09-15 16:24:58 -04:00
committed by GitHub
parent 201cc04609
commit 30b3d22adc
9 changed files with 453 additions and 15 deletions
@@ -106,6 +106,9 @@ UCHAR *temp_ptr;
ALIGN_TYPE new_stack_start;
ALIGN_TYPE updated_stack_start;
#endif
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
ULONG stack_fill_value;
#endif
TXM_MODULE_THREAD_ENTRY_INFO *thread_entry_info;
VOID *stack_end;
ULONG i;
@@ -263,13 +266,18 @@ ULONG i;
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
/* Initialize the stack fill value to a 8-bit random value. */
thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
/* Duplicate the random value in each of the 4 bytes of the stack fill value. */
thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
(thread_ptr -> tx_thread_stack_fill_value << 8) |
(thread_ptr -> tx_thread_stack_fill_value << 16) |
(thread_ptr -> tx_thread_stack_fill_value << 24);
stack_fill_value = stack_fill_value |
(stack_fill_value << 8) |
(stack_fill_value << 16) |
(stack_fill_value << 24);
/* Store the fill value in the control block so that the stack fill below picks it up
through the TX_STACK_FILL macro. The control block is cleared further down in this
function, so the value is stored again once that has been done. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif
/* Set the thread stack to a pattern prior to creating the initial
@@ -311,6 +319,14 @@ ULONG i;
/* Initialize thread control block to all zeros. */
TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
/* Clearing the control block reset the stack fill value, so store the value that was
actually used to fill the stack again. Otherwise the stack checking and stack analyze
routines would look for a pattern that is not the one present in the stack. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif
/* Note that TX_ENABLE_STACK_CHECKING is not supported for module threads. A user mode
module thread owns two stacks and the scheduler swaps tx_thread_stack_start,
tx_thread_stack_end and tx_thread_stack_size over to the kernel stack whenever the