/*************************************************************************** * 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 Codex (gpt-6.1-sol). * 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 **************************************************************************/ /* Execute the real create service and MISRA shim with Linux port types. Only interrupt, stack-builder and scheduler boundaries are recorders. */ #define TX_SOURCE_CODE #include "tx_api.h" #include "tx_thread.h" #include #define STACK_BYTES 8192U #define PADDING_BYTES 32U #define SENTINEL 0xA5U #define CASE_COUNT (sizeof(ULONG) * sizeof(ULONG)) /* Kernel state owned by this harness; the real shim declares it extern. */ TX_THREAD *_tx_thread_created_ptr; TX_THREAD *_tx_thread_execute_ptr; ULONG _tx_thread_created_count; volatile ULONG _tx_thread_system_state; volatile UINT _tx_thread_preempt_disable; static TX_THREAD threads[CASE_COUNT]; static ALIGN_TYPE storage[(STACK_BYTES + 2U * PADDING_BYTES + 16U) / sizeof(ALIGN_TYPE)]; static VOID *recorded_start; static VOID *recorded_end; static ULONG recorded_size; static VOID *safe_stack_ptr; static UINT interrupt_depth; static UINT interrupt_errors; static UINT build_calls; static UINT preempt_calls; static UINT unexpected_calls; static UINT failures; /* Report all cases, including on the old tree, without using corrupt metadata as an address to read or write. */ static VOID check(UINT condition, const CHAR *message) { if (condition == 0U) { printf("FAIL: %s\n", message); failures++; } } /* Record the stack handed to the port. The supplied pointer belongs to the original allocation even when the create service truncates its metadata. */ VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*entry)(VOID)) { recorded_start = thread_ptr -> tx_thread_stack_start; recorded_end = thread_ptr -> tx_thread_stack_end; recorded_size = thread_ptr -> tx_thread_stack_size; thread_ptr -> tx_thread_stack_ptr = safe_stack_ptr; build_calls++; check(entry == _tx_thread_shell_entry, "stack builder shell entry"); } /* Preserve and restore the port's interrupt posture contract. */ UINT _tx_thread_interrupt_disable(VOID) { UINT previous = interrupt_depth; interrupt_depth++; return(previous); } VOID _tx_thread_interrupt_restore(UINT previous) { if ((interrupt_depth == 0U) || (previous + 1U != interrupt_depth)) { interrupt_errors++; } interrupt_depth = previous; } /* DONT_START reaches preemption checking, but must never resume or execute. */ VOID _tx_thread_system_preempt_check(VOID) { preempt_calls++; check(_tx_thread_preempt_disable == 0U, "balanced preemption posture"); } VOID _tx_thread_system_resume(TX_THREAD *thread_ptr) { (void) thread_ptr; unexpected_calls++; } VOID _tx_thread_shell_entry(VOID) { unexpected_calls++; } VOID _tx_thread_timeout(ULONG input) { (void) input; unexpected_calls++; } static VOID thread_entry(ULONG input) { (void) input; unexpected_calls++; } /* Check the complete fill region, caller padding and both reserved stack boundaries. Expectations use remainder arithmetic, independently of the create service's alignment mask. */ static VOID run_case(UINT offset, ULONG size, UINT index) { TX_THREAD *thread_ptr = &threads[index]; UCHAR *bytes = (UCHAR *) storage; UCHAR *input = bytes + PADDING_BYTES + offset; ULONG remainder = (ULONG) ((ALIGN_TYPE) input % sizeof(ULONG)); ULONG adjustment = (remainder == 0U) ? 0U : (ULONG) sizeof(ULONG) - remainder; UCHAR *expected_start = input + adjustment; ULONG expected_size = size - size % (ULONG) sizeof(ULONG) - (ULONG) sizeof(ULONG); UCHAR *expected_end; UINT status; UINT i; UINT calls_before = build_calls; TX_THREAD *next; TX_THREAD *previous; if (adjustment != 0U) { expected_size -= (ULONG) sizeof(ULONG); } expected_end = expected_start + expected_size - 1U; safe_stack_ptr = expected_start + expected_size - 2U * sizeof(ULONG); memset(storage, SENTINEL, sizeof(storage)); status = _tx_thread_create(thread_ptr, "alignment", thread_entry, 17U, input, size, 15U, 15U, TX_NO_TIME_SLICE, TX_DONT_START); printf("offset=%u size=%u input=%p start=%p end=%p usable=%u\n", offset, (UINT) size, (VOID *) input, recorded_start, recorded_end, (UINT) recorded_size); check(status == TX_SUCCESS, "create status"); check(build_calls == calls_before + 1U, "one stack build per create"); check(recorded_start == expected_start, "port start retains high bits and alignment"); check(thread_ptr -> tx_thread_stack_start == expected_start, "stored stack start"); check(recorded_size == expected_size, "port stack size and guards"); check(thread_ptr -> tx_thread_stack_size == expected_size, "stored stack size"); check(recorded_end == expected_end, "port stack end within caller storage"); check(thread_ptr -> tx_thread_stack_end == expected_end, "stored stack end"); check(thread_ptr -> tx_thread_stack_highest_ptr == safe_stack_ptr, "highest stack pointer"); check(thread_ptr -> tx_thread_stack_ptr == safe_stack_ptr, "initial stack pointer"); check(thread_ptr -> tx_thread_state == TX_SUSPENDED, "DONT_START suspended state"); check(thread_ptr -> tx_thread_id == TX_THREAD_ID, "created thread ID"); check(thread_ptr -> tx_thread_entry == thread_entry, "entry function"); check(thread_ptr -> tx_thread_entry_parameter == 17U, "scalar entry parameter"); check(thread_ptr -> tx_thread_priority == 15U, "priority"); check(thread_ptr -> tx_thread_preempt_threshold == 15U, "preemption threshold"); check(thread_ptr -> tx_thread_time_slice == TX_NO_TIME_SLICE, "time slice"); check(thread_ptr -> tx_thread_timer.tx_timer_internal_timeout_function == _tx_thread_timeout, "timeout callback"); check(thread_ptr -> tx_thread_timer.tx_timer_internal_extension_ptr == thread_ptr, "timeout thread pointer retains high bits"); for (i = 0U; i < sizeof(storage); i++) { UCHAR expected = ((i >= PADDING_BYTES + offset) && (i < PADDING_BYTES + offset + size)) ? (UCHAR) TX_STACK_FILL : SENTINEL; if (bytes[i] != expected) { check(0U, "fill region or caller sentinel corrupted"); break; } } for (i = 0U; i < sizeof(ULONG); i++) { check(expected_start[i] == (UCHAR) TX_STACK_FILL, "bottom stack guard fill"); check(expected_end[1U + i] == (UCHAR) TX_STACK_FILL, "top reserved guard fill"); } check(_tx_thread_created_count == index + 1U, "created list count"); check(_tx_thread_created_ptr == &threads[0], "created list head"); next = _tx_thread_created_ptr; previous = thread_ptr; for (i = 0U; i <= index; i++) { check(next == &threads[i], "created list order"); check(next -> tx_thread_created_previous == previous, "created list back link"); previous = next; next = next -> tx_thread_created_next; } check(next == _tx_thread_created_ptr, "created list closes"); check((interrupt_depth == 0U) && (interrupt_errors == 0U), "balanced interrupt posture"); check(preempt_calls == index + 1U, "preemption check count"); check(unexpected_calls == 0U, "no scheduling at recorder boundary"); } /* Native64 is a required precondition, never a successful no-op test. */ INT main(VOID) { UINT offset; UINT tail; UINT index = 0U; printf("sizeof(ULONG)=%zu sizeof(ALIGN_TYPE)=%zu sizeof(void*)=%zu\n", sizeof(ULONG), sizeof(ALIGN_TYPE), sizeof(VOID *)); if ((sizeof(ULONG) != 4U) || (sizeof(ALIGN_TYPE) != 8U) || (sizeof(VOID *) != 8U) || ((ALIGN_TYPE) storage <= (ALIGN_TYPE) ((ULONG) ~0U))) { puts("FAIL: native64 high-address preconditions absent"); return(1); } for (offset = 0U; offset < sizeof(ULONG); offset++) { for (tail = 0U; tail < sizeof(ULONG); tail++) { run_case(offset, STACK_BYTES + tail, index++); } } printf("%s: %u alignment/size cases, %u failures\n", (failures == 0U) ? "PASS" : "FAIL", index, failures); return((failures == 0U) ? 0 : 1); }