/*************************************************************************** * 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. * * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5). * The AI-generated portions may be considered public domain (CC0-1.0) * and not subject to the project's licence. The human contributor has * reviewed and verified that the code is correct. * * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ /* This test creates a thread whose stack does not begin on a ULONG boundary. It is the SMP counterpart of the ThreadX suite's test of the same name. tx_thread_create rounds the starting address up to the next ULONG and then takes a ULONG off the size, so that the rounding cannot push the end of the stack past the memory the caller supplied: if (new_stack_start != updated_stack_start) { stack_size = stack_size - (sizeof(ULONG)); } Every other test in the suite hands tx_thread_create an aligned stack, so that subtraction was never executed -- the only uncovered line in tx_thread_create.c across all five build configurations. A misaligned stack is legitimate: the API takes a VOID * and the alignment fix-up exists precisely to accept one. The line is compiled only under TX_ENABLE_STACK_CHECKING, so it is absent from three of the five configurations' reports rather than uncovered in them. The thread is then run to completion rather than merely created, because the point of the adjustment is that the resulting stack is still usable and still inside the caller's buffer. */ #include #include "tx_api.h" void test_control_return(UINT status); static TX_THREAD thread_0; static TX_THREAD thread_1; /* Thread 1's stack is carved out of this by hand so that its start can be put deliberately off a ULONG boundary. The extra ULONG is what the misaligned start is offset into, so that the stack still ends inside the array after tx_thread_create has rounded the start up. */ static UCHAR misaligned_area[TEST_STACK_SIZE_PRINTF + sizeof(ULONG)]; static ULONG thread_1_counter = 0; static void thread_0_entry(ULONG thread_input); static void thread_1_entry(ULONG thread_input); /* Define what the initial system looks like. */ #ifdef CTEST void test_application_define(void *first_unused_memory) #else void threadx_thread_misaligned_stack_application_define(void *first_unused_memory) #endif { UINT status; CHAR *pointer; CHAR *misaligned_stack; /* Setup a pointer. */ pointer = (CHAR *) first_unused_memory; 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); pointer = pointer + TEST_STACK_SIZE_PRINTF; if (status != TX_SUCCESS) { printf("Running Thread Misaligned Stack Test................................ ERROR #1\n"); test_control_return(1); } /* Push the start one byte past a ULONG boundary. The array itself is aligned, so adding one is enough to guarantee the fix-up runs whatever the alignment of the array turned out to be. */ misaligned_stack = ((CHAR *) misaligned_area) + 1; status = tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, misaligned_stack, TEST_STACK_SIZE_PRINTF, 15, 15, TX_NO_TIME_SLICE, TX_AUTO_START); if (status != TX_SUCCESS) { printf("Running Thread Misaligned Stack Test................................ ERROR #2\n"); test_control_return(1); } } static void thread_0_entry(ULONG thread_input) { /* On this port the two threads start on separate cores, so this one does not have to wait for a relinquish to run. It sleeps well past the single tick thread 1 sleeps for, so the checks below are made against a thread that has actually finished either way. */ tx_thread_sleep(5); /* Both increments must have happened: one before thread 1 slept and one after it woke, which is the half that needed the stack to survive a context switch. */ if (thread_1_counter != ((ULONG) 2)) { printf("Running Thread Misaligned Stack Test................................ ERROR #3\n"); test_control_return(1); } /* The thread that ran on the misaligned stack must have run to completion, which is what says the adjusted stack was usable. */ if (thread_1.tx_thread_state != TX_COMPLETED) { printf("Running Thread Misaligned Stack Test................................ ERROR #4\n"); test_control_return(1); } printf("Running Thread Misaligned Stack Test................................ SUCCESS!\n"); test_control_return(0); } static void thread_1_entry(ULONG thread_input) { /* Use the stack either side of a context switch rather than returning straight away. */ thread_1_counter++; tx_thread_sleep(1); thread_1_counter++; }