mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
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:
@@ -9,6 +9,8 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
**************************************************************************/
|
||||
|
||||
// Some portions generated by Copilot (Opus 5).
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
@@ -93,18 +95,26 @@ 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
|
||||
|
||||
#ifndef TX_DISABLE_STACK_FILLING
|
||||
#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
|
||||
@@ -150,6 +160,14 @@ ALIGN_TYPE updated_stack_start;
|
||||
/* 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
|
||||
|
||||
/* Place the supplied parameters into the thread's control block. */
|
||||
thread_ptr -> tx_thread_name = name_ptr;
|
||||
thread_ptr -> tx_thread_entry = entry_function;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
**************************************************************************/
|
||||
|
||||
// Some portions generated by Copilot (Opus 5).
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
@@ -93,19 +95,27 @@ 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
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_STACK_FILLING
|
||||
#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
|
||||
@@ -143,6 +153,14 @@ ALIGN_TYPE updated_stack_start;
|
||||
/* 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
|
||||
|
||||
/* Place the supplied parameters into the thread's control block. */
|
||||
thread_ptr -> tx_thread_name = name_ptr;
|
||||
thread_ptr -> tx_thread_entry = entry_function;
|
||||
|
||||
@@ -114,6 +114,7 @@ set(regression_test_cases
|
||||
${SOURCE_DIR}/threadx_thread_sleep_for_100ticks_test.c
|
||||
${SOURCE_DIR}/threadx_thread_sleep_terminate_test.c
|
||||
${SOURCE_DIR}/threadx_thread_stack_checking_test.c
|
||||
${SOURCE_DIR}/threadx_thread_stack_fill_value_test.c
|
||||
${SOURCE_DIR}/threadx_thread_terminate_delete_test.c
|
||||
${SOURCE_DIR}/threadx_thread_exit_callback_transition_test.c
|
||||
${SOURCE_DIR}/threadx_smp_thread_exit_callback_remote_test.c
|
||||
|
||||
@@ -255,6 +255,7 @@ void threadx_thread_create_preemption_threshold_application_define(void *);
|
||||
void threadx_thread_information_application_define(void *);
|
||||
void threadx_thread_reset_application_define(void *);
|
||||
void threadx_thread_stack_checking_application_define(void *);
|
||||
void threadx_thread_stack_fill_value_application_define(void *);
|
||||
|
||||
void threadx_time_get_set_application_define(void *);
|
||||
|
||||
@@ -403,6 +404,7 @@ TEST_ENTRY test_control_tests[] =
|
||||
threadx_thread_information_application_define,
|
||||
threadx_thread_reset_application_define,
|
||||
threadx_thread_stack_checking_application_define,
|
||||
threadx_thread_stack_fill_value_application_define,
|
||||
|
||||
threadx_time_get_set_application_define,
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/***************************************************************************/
|
||||
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||
/* */
|
||||
/* This program and the accompanying materials are made available under */
|
||||
/* the terms of the MIT License which is available at */
|
||||
/* https://opensource.org/licenses/MIT. */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/***************************************************************************/
|
||||
|
||||
// Some portions generated by Copilot (Opus 5).
|
||||
|
||||
/* This test checks that the stack fill value recorded in a thread control block is the
|
||||
value that was actually written into that thread's stack. The two used to disagree
|
||||
when TX_ENABLE_RANDOM_NUMBER_STACK_FILLING was enabled, because the control block was
|
||||
cleared after the random value had been chosen and the stack had been filled with it,
|
||||
which left the stack checking and stack analyze routines looking for a pattern that is
|
||||
not the one present in the stack. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "tx_api.h"
|
||||
|
||||
|
||||
/* Number of probe threads created. A random fill value can legitimately come out as zero,
|
||||
which hides the defect for that one thread, so several threads are created and at least
|
||||
one of them is required to have produced a non-zero pattern. */
|
||||
|
||||
#define TEST_PROBE_THREADS 16
|
||||
|
||||
|
||||
static unsigned long thread_0_counter = 0;
|
||||
static TX_THREAD thread_0;
|
||||
|
||||
static TX_THREAD probe_thread;
|
||||
static ULONG probe_stack[TX_MINIMUM_STACK / sizeof(ULONG)];
|
||||
|
||||
|
||||
/* Define task prototypes. */
|
||||
|
||||
static void thread_0_entry(ULONG task_input);
|
||||
|
||||
|
||||
/* Prototype for test control return. */
|
||||
|
||||
void test_control_return(UINT status);
|
||||
|
||||
|
||||
/* Define what the initial system looks like. */
|
||||
|
||||
#ifdef CTEST
|
||||
void test_application_define(void *first_unused_memory)
|
||||
#else
|
||||
void threadx_thread_stack_fill_value_application_define(void *first_unused_memory)
|
||||
#endif
|
||||
{
|
||||
|
||||
UINT status;
|
||||
CHAR *pointer;
|
||||
|
||||
pointer = (CHAR *) first_unused_memory;
|
||||
|
||||
/* Put system definition stuff in here, e.g. thread creates and other assorted
|
||||
create information. */
|
||||
|
||||
status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
|
||||
pointer, TEST_STACK_SIZE_PRINTF,
|
||||
16, 16, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Check for status. */
|
||||
if (status != TX_SUCCESS)
|
||||
{
|
||||
|
||||
printf("Running Thread Stack Fill Value Test................................ ERROR #1\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Define the test threads. */
|
||||
|
||||
static void thread_0_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
UINT i;
|
||||
ULONG stack_pattern;
|
||||
UINT non_zero_seen = TX_FALSE;
|
||||
|
||||
|
||||
/* Increment thread 0 counter. */
|
||||
thread_0_counter++;
|
||||
|
||||
/* Inform user of success getting to this test. */
|
||||
printf("Running Thread Stack Fill Value Test................................ ");
|
||||
|
||||
for (i = 0; i < TEST_PROBE_THREADS; i++)
|
||||
{
|
||||
|
||||
/* Create a thread that is never started, so that its stack still holds nothing but
|
||||
the fill pattern and the initial stack frame built at the top of the stack. */
|
||||
status = tx_thread_create(&probe_thread, "probe thread", thread_0_entry, 0,
|
||||
probe_stack, sizeof(probe_stack),
|
||||
17, 17, TX_NO_TIME_SLICE, TX_DONT_START);
|
||||
|
||||
/* Check for status. */
|
||||
if (status != TX_SUCCESS)
|
||||
{
|
||||
|
||||
printf("ERROR #2\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
/* Pick up the pattern the create service wrote into the unused part of the stack. */
|
||||
stack_pattern = *(((ULONG *) probe_thread.tx_thread_stack_start) + 4);
|
||||
|
||||
#ifndef TX_DISABLE_STACK_FILLING
|
||||
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
|
||||
|
||||
/* The control block must hold the value that was written into the stack. */
|
||||
if (probe_thread.tx_thread_stack_fill_value != stack_pattern)
|
||||
{
|
||||
|
||||
printf("ERROR #3\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
/* The random value is duplicated into all four bytes of the fill value. */
|
||||
if ((stack_pattern & 0xFFUL) !=
|
||||
((stack_pattern >> 24) & 0xFFUL))
|
||||
{
|
||||
|
||||
printf("ERROR #4\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
if (stack_pattern != ((ULONG) 0))
|
||||
{
|
||||
|
||||
non_zero_seen = TX_TRUE;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Without random filling, the pattern is the fixed one. */
|
||||
if (stack_pattern != ((ULONG) 0xEFEFEFEFUL))
|
||||
{
|
||||
|
||||
printf("ERROR #5\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
non_zero_seen = TX_TRUE;
|
||||
#endif
|
||||
#else
|
||||
|
||||
/* Stack filling is disabled, so there is nothing to compare. */
|
||||
non_zero_seen = TX_TRUE;
|
||||
#endif
|
||||
|
||||
/* Terminate and delete the probe thread so that the next pass starts from a clean
|
||||
slate. A thread created with TX_DONT_START is suspended rather than completed,
|
||||
so it must be terminated before it can be deleted. */
|
||||
status = tx_thread_terminate(&probe_thread);
|
||||
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
status = tx_thread_delete(&probe_thread);
|
||||
}
|
||||
|
||||
/* Check for status. */
|
||||
if (status != TX_SUCCESS)
|
||||
{
|
||||
|
||||
printf("ERROR #6\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* A run in which every fill value came out as zero would prove nothing. */
|
||||
if (non_zero_seen != TX_TRUE)
|
||||
{
|
||||
|
||||
printf("ERROR #7\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
/* Success! */
|
||||
printf("SUCCESS!\n");
|
||||
test_control_return(0);
|
||||
}
|
||||
@@ -97,6 +97,7 @@ set(regression_test_cases
|
||||
${SOURCE_DIR}/threadx_thread_sleep_for_100ticks_test.c
|
||||
${SOURCE_DIR}/threadx_thread_sleep_terminate_test.c
|
||||
${SOURCE_DIR}/threadx_thread_stack_checking_test.c
|
||||
${SOURCE_DIR}/threadx_thread_stack_fill_value_test.c
|
||||
${SOURCE_DIR}/threadx_thread_terminate_delete_test.c
|
||||
${SOURCE_DIR}/threadx_thread_exit_callback_transition_test.c
|
||||
${SOURCE_DIR}/threadx_thread_time_slice_change_test.c
|
||||
|
||||
@@ -232,6 +232,7 @@ void threadx_thread_create_preemption_threshold_application_define(void *);
|
||||
void threadx_thread_information_application_define(void *);
|
||||
void threadx_thread_reset_application_define(void *);
|
||||
void threadx_thread_stack_checking_application_define(void *);
|
||||
void threadx_thread_stack_fill_value_application_define(void *);
|
||||
|
||||
void threadx_time_get_set_application_define(void *);
|
||||
|
||||
@@ -352,6 +353,7 @@ TEST_ENTRY test_control_tests[] =
|
||||
threadx_thread_information_application_define,
|
||||
threadx_thread_reset_application_define,
|
||||
threadx_thread_stack_checking_application_define,
|
||||
threadx_thread_stack_fill_value_application_define,
|
||||
|
||||
threadx_time_get_set_application_define,
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/***************************************************************************/
|
||||
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||
/* */
|
||||
/* This program and the accompanying materials are made available under */
|
||||
/* the terms of the MIT License which is available at */
|
||||
/* https://opensource.org/licenses/MIT. */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/***************************************************************************/
|
||||
|
||||
// Some portions generated by Copilot (Opus 5).
|
||||
|
||||
/* This test checks that the stack fill value recorded in a thread control block is the
|
||||
value that was actually written into that thread's stack. The two used to disagree
|
||||
when TX_ENABLE_RANDOM_NUMBER_STACK_FILLING was enabled, because the control block was
|
||||
cleared after the random value had been chosen and the stack had been filled with it,
|
||||
which left the stack checking and stack analyze routines looking for a pattern that is
|
||||
not the one present in the stack. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "tx_api.h"
|
||||
|
||||
|
||||
/* Number of probe threads created. A random fill value can legitimately come out as zero,
|
||||
which hides the defect for that one thread, so several threads are created and at least
|
||||
one of them is required to have produced a non-zero pattern. */
|
||||
|
||||
#define TEST_PROBE_THREADS 16
|
||||
|
||||
|
||||
static unsigned long thread_0_counter = 0;
|
||||
static TX_THREAD thread_0;
|
||||
|
||||
static TX_THREAD probe_thread;
|
||||
static ULONG probe_stack[TX_MINIMUM_STACK / sizeof(ULONG)];
|
||||
|
||||
|
||||
/* Define task prototypes. */
|
||||
|
||||
static void thread_0_entry(ULONG task_input);
|
||||
|
||||
|
||||
/* Prototype for test control return. */
|
||||
|
||||
void test_control_return(UINT status);
|
||||
|
||||
|
||||
/* Define what the initial system looks like. */
|
||||
|
||||
#ifdef CTEST
|
||||
void test_application_define(void *first_unused_memory)
|
||||
#else
|
||||
void threadx_thread_stack_fill_value_application_define(void *first_unused_memory)
|
||||
#endif
|
||||
{
|
||||
|
||||
UINT status;
|
||||
CHAR *pointer;
|
||||
|
||||
pointer = (CHAR *) first_unused_memory;
|
||||
|
||||
/* Put system definition stuff in here, e.g. thread creates and other assorted
|
||||
create information. */
|
||||
|
||||
status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
|
||||
pointer, TEST_STACK_SIZE_PRINTF,
|
||||
16, 16, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Check for status. */
|
||||
if (status != TX_SUCCESS)
|
||||
{
|
||||
|
||||
printf("Running Thread Stack Fill Value Test................................ ERROR #1\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Define the test threads. */
|
||||
|
||||
static void thread_0_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
UINT i;
|
||||
ULONG stack_pattern;
|
||||
UINT non_zero_seen = TX_FALSE;
|
||||
|
||||
|
||||
/* Increment thread 0 counter. */
|
||||
thread_0_counter++;
|
||||
|
||||
/* Inform user of success getting to this test. */
|
||||
printf("Running Thread Stack Fill Value Test................................ ");
|
||||
|
||||
for (i = 0; i < TEST_PROBE_THREADS; i++)
|
||||
{
|
||||
|
||||
/* Create a thread that is never started, so that its stack still holds nothing but
|
||||
the fill pattern and the initial stack frame built at the top of the stack. */
|
||||
status = tx_thread_create(&probe_thread, "probe thread", thread_0_entry, 0,
|
||||
probe_stack, sizeof(probe_stack),
|
||||
17, 17, TX_NO_TIME_SLICE, TX_DONT_START);
|
||||
|
||||
/* Check for status. */
|
||||
if (status != TX_SUCCESS)
|
||||
{
|
||||
|
||||
printf("ERROR #2\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
/* Pick up the pattern the create service wrote into the unused part of the stack. */
|
||||
stack_pattern = *(((ULONG *) probe_thread.tx_thread_stack_start) + 4);
|
||||
|
||||
#ifndef TX_DISABLE_STACK_FILLING
|
||||
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
|
||||
|
||||
/* The control block must hold the value that was written into the stack. */
|
||||
if (probe_thread.tx_thread_stack_fill_value != stack_pattern)
|
||||
{
|
||||
|
||||
printf("ERROR #3\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
/* The random value is duplicated into all four bytes of the fill value. */
|
||||
if ((stack_pattern & 0xFFUL) !=
|
||||
((stack_pattern >> 24) & 0xFFUL))
|
||||
{
|
||||
|
||||
printf("ERROR #4\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
if (stack_pattern != ((ULONG) 0))
|
||||
{
|
||||
|
||||
non_zero_seen = TX_TRUE;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Without random filling, the pattern is the fixed one. */
|
||||
if (stack_pattern != ((ULONG) 0xEFEFEFEFUL))
|
||||
{
|
||||
|
||||
printf("ERROR #5\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
non_zero_seen = TX_TRUE;
|
||||
#endif
|
||||
#else
|
||||
|
||||
/* Stack filling is disabled, so there is nothing to compare. */
|
||||
non_zero_seen = TX_TRUE;
|
||||
#endif
|
||||
|
||||
/* Terminate and delete the probe thread so that the next pass starts from a clean
|
||||
slate. A thread created with TX_DONT_START is suspended rather than completed,
|
||||
so it must be terminated before it can be deleted. */
|
||||
status = tx_thread_terminate(&probe_thread);
|
||||
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
status = tx_thread_delete(&probe_thread);
|
||||
}
|
||||
|
||||
/* Check for status. */
|
||||
if (status != TX_SUCCESS)
|
||||
{
|
||||
|
||||
printf("ERROR #6\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* A run in which every fill value came out as zero would prove nothing. */
|
||||
if (non_zero_seen != TX_TRUE)
|
||||
{
|
||||
|
||||
printf("ERROR #7\n");
|
||||
test_control_return(1);
|
||||
}
|
||||
|
||||
/* Success! */
|
||||
printf("SUCCESS!\n");
|
||||
test_control_return(0);
|
||||
}
|
||||
Reference in New Issue
Block a user