Skip to content

fix: improve Windows host build and strengthen heap/package tests - #60

Merged
srpatcha merged 2 commits into
embeddedos-org:masterfrom
Rani2909:fix/windows-host-tests
Aug 29, 2026
Merged

srpatcha merged 2 commits into
embeddedos-org:masterfrom
Rani2909:fix/windows-host-tests

Conversation

@Rani2909

Copy link
Copy Markdown
Contributor

Summary

This PR improves Windows host/simulation compatibility and strengthens the heap and package test coverage.

Changes

  • Removed the x64 hlt instruction from the host/simulation idle-task path in kernel/src/task.c to avoid executing a privileged CPU instruction during host-based testing.

  • Expanded tests/test_heap.c to validate:

    • Basic allocation
    • 8-byte alignment
    • Memory read/write
    • Multiple allocations
    • Free and re-allocation
    • calloc zero-initialization
    • realloc data preservation
    • Heap statistics
    • Double-free protection
  • Updated tests/test_package.c to use static EosPackageSet instances, preventing stack-related issues in the Windows test environment.

Validation

  • Windows/MSVC Debug build completed successfully.
  • All 21 CTest tests passed.
  • Test result: 21/21 passed (100%)
  • git diff --check completed with no errors.

Test Command

ctest --test-dir build_sim_windows -C Debug --output-on-failure

Result

100% tests passed out of 21

@srpatcha

Copy link
Copy Markdown
Member

Review — three separate changes; two are fine, one needs a decision

Built merged onto current master: 24/24 ctest pass.

1. test_package.c static sets — correct, and byte-identical to #52 and to the same hunk in #48 (compared blob hashes). #48 carries the explanatory comment, so that is probably the one to land; this hunk then rebases to nothing. No action needed from you.

2. test_heap.c expansion — mostly a clear improvement: alignment, write/read-back, calloc zeroing, realloc preserving data, and a stats check. One part I'd ask you to reconsider:

/* 11. Double-free should not corrupt allocator */
eos_free(a);          /* a was already freed in step 9 */

This pins double-free tolerance as a contract. If the allocator is ever changed to detect double-free and trap — which is a defensible hardening choice — this test starts failing and someone will "fix" it by weakening the allocator. If the intent is "we currently survive this", a comment saying so keeps the option open. If the intent is "we guarantee this", it should be stated in the heap's documentation, because it constrains future work.

3. Removing the x86_64 hlt from idle_task_func — this is the one that needs a decision, and it is not really a test change:

-#elif defined(__x86_64__) || defined(_M_X64)
-    __asm volatile ("hlt");

You are right that hlt is privileged and faults in a user-space host build. But this also removes it for a genuine bare-metal x86_64 target, where it is the correct instruction and the power saving is the point. Gate it rather than delete it — on EOS_PLATFORM, on a hosted/freestanding check, or on __STDC_HOSTED__ — so the host build stops faulting without silently making bare-metal x86 spin at 100%.

Splitting 3 into its own PR would let 1 and 2 land quickly.

@Rani2909

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I’ve addressed the requested changes:

  • Removed the double-free tolerance test from test_heap.c so the test does not establish a future allocator contract.
  • Kept the test_package.c static EosPackageSet changes as requested.
  • Split the x86_64 hlt change into separate PR fix: gate x86 idle hlt for hosted builds #76 so the hosted-build fix can be reviewed independently.

PR #60 now contains only the heap and package test improvements. The working tree is clean and the branch is pushed to my fork.

srpatcha pushed a commit that referenced this pull request Aug 28, 2026
…ree() (#77)

The kernel allocator has a validation boundary in one of its two pointer-taking
entry points. eos_free() range-checks its argument against the heap;
eos_realloc() takes the same kind of pointer, derives a header from it, and
trusts whatever it finds:

    block_header_t *block = (block_header_t *)((uint8_t *)ptr - HEADER_SIZE);
    size_t current_usable = block->size - HEADER_SIZE;
    if (new_size <= current_usable) return ptr;

Two consequences, both reproduced against the unmodified allocator:

1. A pointer that never came from this heap is read out of bounds for its
   "header" and then handed straight back, as if it had been resized. eos_free()
   rejects exactly that pointer.

2. `block->size - HEADER_SIZE` is unsigned. A header whose size field is below
   HEADER_SIZE underflows current_usable to nearly SIZE_MAX, so every growth
   request looks already satisfied and realloc returns the original short
   buffer. The caller then writes new_size bytes into it. That turns a single
   corrupted header byte -- the thing a prior small overflow leaves behind --
   into an unbounded overflow, which is the opposite of what an allocator's
   metadata checks are for.

Both paths now go through one block_from_ptr() helper: the pointer must lie
inside the heap, its header must be 8-byte aligned relative to the heap base,
and the size field must be at least MIN_BLOCK_SIZE and not claim to extend past
the end of the heap. eos_free() uses it too and gains the size checks it did
not have. An unrecognised pointer makes realloc return NULL and free a no-op,
which is what each already did for the cases it did check.

Verified: ctest 24/24, pytest 10 passed. tests/test_heap.c gains coverage for
both paths plus a grow-and-preserve case; against the unmodified heap.c it
fails on "realloc of a non-heap pointer must be rejected".

Note for review: PR #60 also touches tests/test_heap.c (it does not touch
kernel/src/mem/heap.c). If that lands first this needs a trivial rebase in the
test file.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@srpatcha

Copy link
Copy Markdown
Member

Needs a rebase — #77 landed in the same file

Only tests/test_heap.c conflicts. #77 merged a heap-header validation change that added realloc coverage to the same file, so the two sets of additions collide textually.

Worth reading #77 before you resolve, because it overlaps this PR's subject rather than just its line numbers. It added:

  • block_from_ptr(), which range-checks and sanity-checks a header, now used by both eos_free and eos_realloc — previously only eos_free validated, so eos_realloc trusted whatever it was handed.
  • A rejection for headers claiming a size below HEADER_SIZE, because block->size - HEADER_SIZE is unsigned and underflowed to near SIZE_MAX, making every growth request look already satisfied.
  • Tests for a foreign pointer, an undersized header, and payload preservation across a growing realloc.

So some of what this PR strengthens in test_heap.c may now be covered. Keep whatever is genuinely additional and drop the rest — the Windows host-build half of this PR is untouched by #77 and is the part I am most interested in, since none of it can be exercised on this machine.

On that: I cannot verify the Windows changes here at all. Linux is the only host available to me, so for that half I am relying on your testing rather than mine, and I would rather say so than imply I checked it. If CI covers the Windows build after the rebase, that is the evidence I would go on.

tests/test_package.c also changed under you via #48 (all EosPackageSet locals became static, with a comment explaining the ~3.8 MB against a 1 MB Windows stack) — that one auto-merges, but it is adjacent to what you are doing and may already solve part of it.

@Rani2909
Rani2909 force-pushed the fix/windows-host-tests branch from a06bf7c to 2a7a452 Compare August 28, 2026 23:49
@Rani2909

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I’ve completed the requested rebase and cleanup.

The branch is clean and pushed to my fork. I’ve also verified that the current PR diff contains only tests/test_heap.c.

Please take another look when convenient.

@srpatcha
srpatcha merged commit 647e0df into embeddedos-org:master Aug 29, 2026
5 of 22 checks passed
Kartikey1306 added a commit to Kartikey1306/eos that referenced this pull request Sep 14, 2026
…ree()

The kernel allocator has a validation boundary in one of its two pointer-taking
entry points. eos_free() range-checks its argument against the heap;
eos_realloc() takes the same kind of pointer, derives a header from it, and
trusts whatever it finds:

    block_header_t *block = (block_header_t *)((uint8_t *)ptr - HEADER_SIZE);
    size_t current_usable = block->size - HEADER_SIZE;
    if (new_size <= current_usable) return ptr;

Two consequences, both reproduced against the unmodified allocator:

1. A pointer that never came from this heap is read out of bounds for its
   "header" and then handed straight back, as if it had been resized. eos_free()
   rejects exactly that pointer.

2. `block->size - HEADER_SIZE` is unsigned. A header whose size field is below
   HEADER_SIZE underflows current_usable to nearly SIZE_MAX, so every growth
   request looks already satisfied and realloc returns the original short
   buffer. The caller then writes new_size bytes into it. That turns a single
   corrupted header byte -- the thing a prior small overflow leaves behind --
   into an unbounded overflow, which is the opposite of what an allocator's
   metadata checks are for.

Both paths now go through one block_from_ptr() helper: the pointer must lie
inside the heap, its header must be 8-byte aligned relative to the heap base,
and the size field must be at least MIN_BLOCK_SIZE and not claim to extend past
the end of the heap. eos_free() uses it too and gains the size checks it did
not have. An unrecognised pointer makes realloc return NULL and free a no-op,
which is what each already did for the cases it did check.

Verified: ctest 24/24, pytest 10 passed. tests/test_heap.c gains coverage for
both paths plus a grow-and-preserve case; against the unmodified heap.c it
fails on "realloc of a non-heap pointer must be rejected".

Note for review: PR embeddedos-org#60 also touches tests/test_heap.c (it does not touch
kernel/src/mem/heap.c). If that lands first this needs a trivial rebase in the
test file.
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.

2 participants