Skip to content

Fix buffer size calculation and memory alignment in evolver_ndf15 | Avoid buffer overflow from input#652

Open
kabeleh wants to merge 3 commits intolesgourg:masterfrom
kabeleh:master
Open

Fix buffer size calculation and memory alignment in evolver_ndf15 | Avoid buffer overflow from input#652
kabeleh wants to merge 3 commits intolesgourg:masterfrom
kabeleh:master

Conversation

@kabeleh
Copy link

@kabeleh kabeleh commented Feb 9, 2026

I was investigating a performance and stability issue in my own CLASS fork (kabeleh/iDM), for which I compiled CLASS with the flags

CCFLAG += -fsanitize=undefined 
LDFLAG += -fsanitize=undefined

This reported a memory misalignment issue in evolver_ndf15. There is a (4 bit) int array that is in between doubles (8 bit), which causes a misalignment at the boundary. The fix is relatively simple: move the int array to the end.

This was the TL;DR. In more prose:
The ndf15 evolver allocates a single contiguous buffer and carves it into sub-arrays for doubles, an int array (interpidx), a double-pointer array (dif), and a second double region for backward differences.

The original layout placed the int array (neqp × sizeof(int)) between the double arrays and the double-pointer array:

[15×neqp doubles] [neqp ints] [neqp double*] [(7×neq+1) doubles]

When neqp is odd, neqp × 4 bytes leaves the subsequent double* and double regions at a 4-byte boundary, rather than the 8-byte alignment required for these types. This constitutes undefined behaviour in C11 and is flagged at runtime by the -fsanitize=undefined CCFLAG / LDFLAG as misaligned load/store errors during thermodynamics integration.

The solution is to move the int array to the end of the buffer, after all double and double* regions:

[15×neqp doubles] [neqp double*] [(7×neq+1) doubles] [neqp ints]

Since malloc returns memory aligned to at least 8 bytes, and all regions before the int array are multiples of 8 bytes in size, every double and double* access is now aligned. The int array at the tail has no alignment requirement beyond 4 bytes, so placing it last is safe.

The total buffer size is unchanged.
Verified clean under
-fsanitize=undefined,
-fsanitize=address, and
-fsanitize=thread.

Fix misaligned memory access in evolver_ndf15 buffer layout:
The ndf15 evolver allocates a single contiguous buffer and carves it into sub-arrays for doubles, an int array (interpidx), a double-pointer array (dif), and a second double region for backward differences.

The original layout placed the int array (neqp × sizeof(int)) between the double arrays and the double-pointer array:

[15×neqp doubles] [neqp ints] [neqp double*] [(7×neq+1) doubles]

When neqp is odd, neqp × 4 bytes leaves the subsequent double* and double regions at a 4-byte boundary, rather than the 8-byte alignment required for these types. This constitutes undefined behaviour in C11 and is flagged at runtime by the -fsanitize=undefined CCFLAG / LDFLAG as misaligned load/store errors during thermodynamics integration.

The solution is to move the int array to the end of the buffer, after all double and double* regions:

[15×neqp doubles] [neqp double*] [(7×neq+1) doubles] [neqp ints]

Since malloc returns memory aligned to at least 8 bytes, and all regions before the int array are multiples of 8 bytes in size, every double and double* access is now aligned. The int array at the tail has no alignment requirement beyond 4 bytes, so placing it last is safe.

The total buffer size is unchanged.
Verified clean under
-fsanitize=undefined,
-fsanitize=address, and
-fsanitize=thread.
There was a tiny chance that line 50 in input.h
    if (flag_temp == _TRUE_)                                                    \
49
    {                                                                           \
50
      strcpy(destination, string_temp);                                         \
51
    }

might cause a bufferoverflow. It's very unlikely to encounter this, but no downside in preventing it.
@kabeleh kabeleh changed the title Fix buffer size calculation and memory alignment in evolver_ndf15 Fix buffer size calculation and memory alignment in evolver_ndf15 | Avoid buffer overflow from input Feb 18, 2026
@kabeleh
Copy link
Author

kabeleh commented Feb 18, 2026

The second commit comes at no cost, yet prevents the (unlikely) possibility that line 50 in input.h

    if (flag_temp == _TRUE_)                                                    \
49
    {                                                                           \
50
      strcpy(destination, string_temp);                                         \
51
    }

might cause a buffer overflow. It's very unlikely to encounter this, but no downside in preventing it by increasing the _BASEPATHSIZE_ from 1000 to 1024 in common.h.

Variable length arrays are actually not supported. It's not an issue, just a compiler warning. Though, the fix is simply to define REFINE as a const int instead of just an int. Compiler is happy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant