Skip to content

_tx_thread_create truncates the stack start pointer under TX_MISRA_ENABLE on ports where ALIGN_TYPE is wider than ULONG #744

Description

@fdesbiens

_tx_thread_create() truncates the thread's stack start pointer to 32 bits when
TX_MISRA_ENABLE and TX_ENABLE_STACK_CHECKING are both defined, on any port whose
ALIGN_TYPE is wider than its ULONG. It compiles cleanly and fails silently.

Where

common/src/tx_thread_create.c, inside #ifdef TX_ENABLE_STACK_CHECKING:

#ifdef TX_MISRA_ENABLE
    new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start);
#else
    new_stack_start =  TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
#endif
    ...
#ifdef TX_MISRA_ENABLE
    stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start);
#else
    stack_start =  TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
#endif

new_stack_start and updated_stack_start are declared ALIGN_TYPE at lines 95-96.
Under MISRA the pointer goes through _tx_misra_pointer_to_ulong_convert(), which
returns ULONG, and comes back through _tx_misra_ulong_to_pointer_convert(),
which takes ULONG. Where ULONG is narrower than the pointer, both directions lose
the top bits.

Which ports are affected

Every port that widens ALIGN_TYPE past ULONG. That is not a corner: the AArch64
Cortex-A family (a34, a35, a53, a55, a57, a65, a65ae, a72, a73, a75, a76, a76ae, a77,
a78, a5x), RISC-V 64, win64 and the Linux simulator on __x86_64__ all declare

typedef unsigned int                            ULONG;      /* 32-bit */
typedef unsigned long long                      ALIGN_TYPE; /* 64-bit */

Demonstration

Compiled against ports/linux/gnu, 64-bit, which has exactly those widths:

sizeof(ULONG)=4 sizeof(ALIGN_TYPE)=8 sizeof(void*)=8
original=0x7f1234567890  after ULONG round trip=0x34567890  TRUNCATED

And the file itself compiles without a diagnostic in that combination:

gcc -c -DTX_MISRA_ENABLE -DTX_ENABLE_STACK_CHECKING \
    -I common/inc -I ports/linux/gnu/inc common/src/tx_thread_create.c -o /dev/null

exits 0. The thread is then created with a stack_start that does not point at its
stack.

Suggested fix

Drop the #ifdef and write the conversion inline, as #742 does for the simulator
ports' _tx_thread_stack_build():

    new_stack_start =  (ALIGN_TYPE) ((VOID *) stack_start);
    ...
    stack_start =  (VOID *) ((ALIGN_TYPE) updated_stack_start);

One form, correct in both modes and at both widths. Adding ALIGN_TYPE conversion
helpers to the MISRA branch of tx_api.h would work equally well and would also serve
the sibling report below.

Related, and not the same defect

common_smp/src/tx_thread_create.c (lines 135, 147) and
common_modules/module_manager/src/txm_module_manager_thread_create.c (lines 297, 309)
call TX_POINTER_TO_ALIGN_TYPE_CONVERT and TX_ALIGN_TYPE_TO_POINTER_CONVERT with no
#ifdef at all. Those macros exist only in the non-MISRA branch, so with
TX_MISRA_ENABLE and TX_ENABLE_STACK_CHECKING both defined, neither file compiles:

common_smp/src/tx_thread_create.c:135:24: error: implicit declaration of function
  'TX_POINTER_TO_ALIGN_TYPE_CONVERT'

That is the same defect #741 reports for the simulator ports, in two more files. #742
fixes the ports only and should be extended to cover these two.

Neither file truncates, because neither compiles.

Why none of this shows up in CI

No build configuration under test/tx/cmake or test/smp/cmake defines
TX_MISRA_ENABLE, so nothing is ever compiled in that mode.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions