Skip to content

drive: static_assert that struct Log stays all-float#460

Closed
eugenevinitsky wants to merge 1 commit into
emerge/temp_trainingfrom
ev/log-struct-static-assert
Closed

drive: static_assert that struct Log stays all-float#460
eugenevinitsky wants to merge 1 commit into
emerge/temp_trainingfrom
ev/log-struct-static-assert

Conversation

@eugenevinitsky
Copy link
Copy Markdown

Summary

`env_binding.h`'s `vec_log` iterates `struct Log` as a raw `float[]` via `sizeof(Log)/sizeof(float)`. The existing comment "Will break horribly if Log has non-float data" warns about it, but nothing enforces the invariant. Adding a `double` / pointer field or even an unintended `int` could silently type-pun across the aggregation path.

This PR ties a `LOG_NUM_FLOAT_FIELDS` macro to the field count and `_Static_assert`s at the struct boundary that `sizeof(struct Log) == LOG_NUM_FLOAT_FIELDS * sizeof(float)`. Adding a field requires bumping the count; forgetting to bump it, or sneaking in a wider-than-float field, becomes a compile error.

```c
#define LOG_NUM_FLOAT_FIELDS 54

struct Log {
float n;
...
float reward_ade;
};
_Static_assert(
sizeof(struct Log) == LOG_NUM_FLOAT_FIELDS * sizeof(float),
"struct Log size mismatch: a field was added without bumping "
"LOG_NUM_FLOAT_FIELDS, or a non-float field slipped in (would corrupt "
"vec_log's raw-float iteration).");
```

Gap

A same-sized non-float field (e.g. `int`) with the count bumped would still match `sizeof(Log) == N * sizeof(float)` and slip past the assert — the raw-float iteration would then type-pun the int bytes through `float`-typed reads. The comment at the top of the struct calls this out so a contributor is at least warned. A fully type-safe fix would need an X-macro field-registry refactor, which is much more invasive; this PR aims for the cheap, high-coverage defense.

Test plan

  • `python setup.py build_ext --inplace --force` clean (only the pre-existing `maps_checked` warning).
  • Verified that the assertion is meaningful: bumping the count to 55 in a sandbox triggered the expected compile-time error.

🤖 Generated with Claude Code

env_binding.h's vec_log iterates Log as a raw float[] via
sizeof(Log)/sizeof(float). A field of a different size (double, pointer) or
a forgotten count bump after adding a field would silently misbehave. Wire
LOG_NUM_FLOAT_FIELDS to the field count and _Static_assert at the struct
boundary that sizeof(struct Log) matches LOG_NUM_FLOAT_FIELDS * sizeof(float).

Catches forgotten count updates and wider-than-float field additions at
compile time. Doesn't catch a same-sized non-float (e.g. int) if the count
is also bumped; the warning comment on the struct flags that footgun for
contributors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 30, 2026 19:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a compile-time guard to keep struct Log compatible with env_binding.h’s raw-float aggregation path.

Changes:

  • Defines LOG_NUM_FLOAT_FIELDS next to struct Log.
  • Adds documentation that every Log field must remain a float.
  • Adds a _Static_assert ensuring sizeof(struct Log) matches the expected float field count.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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