1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
/***************************************************************************
* 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.
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 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 <stdio.h>
#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)
{
/* Thread 1 is the higher priority of the two, so this thread first gets the
processor while thread 1 is sleeping. Sleep past that, so the check below
is made against a thread that has actually finished. */
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++;
}
|