Skip to content

Reflection relies on implementation-defined pointer-to-member layout #21

@jkalias

Description

@jkalias

Problem

The reflection core derives member offsets in two fragile ways:

  • OffsetFromStart (include/reflection.h:97) memcpys the raw bytes of a pointer-to-member and reinterprets the leading sizeof(size_t) bytes as a byte offset.
  • DEFINE_MEMBER (include/reflection.h) uses offsetof(struct REFLECTABLE, R), and members are accessed via reinterpret_cast at the computed offset (GetMemberAddress).

Impact

This works for simple standard-layout structs under the common Itanium / MSVC ABIs, but:

  • The byte representation of a pointer-to-member is implementation-defined; for multiple or virtual inheritance the leading-bytes-as-offset assumption is wrong.
  • offsetof on a non-standard-layout type is conditionally-supported / undefined.

So the whole introspection mechanism rests on assumptions the standard doesn't guarantee, and would break (silently, with wrong offsets) for records that aren't simple standard-layout aggregates.

Suggested direction

Document the constraint explicitly (reflectable records must be standard-layout, no inheritance) and enforce it at registration with static_assert(std::is_standard_layout_v<T>), so a violating type fails to compile instead of misbehaving at runtime.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions