

Polymorphic types aren't trivially relocatable – Arthur O'Dwyer – Stuff mostly a...
source link: https://quuxplusone.github.io/blog/2023/06/24/polymorphic-types-arent-trivially-relocatable/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Polymorphic types aren’t trivially relocatable
One of the (minor, non-key) differences between P1144 trivial relocatability and P2786R1 trivial relocatability (§11.3, page 19) is that P2786R1 accidentally considers polymorphic types to be trivially relocatable by default. I say “accidentally” because of course this cannot really be permitted. Godbolt:
struct B {
virtual int getter() const { return 1; }
virtual ~B() = default;
};
struct D : B {
int d = 2;
int getter() const override { return d; }
};
alignas(D) char dbuf[sizeof(D)];
alignas(B) char bbuf[sizeof(B)];
B *d = ::new (dbuf) D();
B *b = (B*)bbuf;
// RELOCATE
printf("Expect 1: %d\n", b->getter());
b->~B();
The “RELOCATE
” comment should be replaced with the code to relocate a B
object from *d
into *b
.
In P1144, the spelling is simply
std::relocate_at(d, b);
and the library decides whether to use trivial relocation behind the scenes. In P2786R1, the spelling is
static_assert(std::is_trivially_relocatable_v<B>);
std::trivially_relocate(d, d+1, b);
In P1144, B
is not considered trivially relocatable, and the code above Just Works.
Why is
B
not trivially relocatable? P1144 offers two answers: One, at the compiler level,B
doesn’t meet [basic.types.general]’s criterion that a trivially relocatable type mustn’t have virtual member functions. Two, at the human level, we can see thatB
fails to model [concept.relocatable]’s semantic requirements.
In P2786R1, B
is (“accidentally”) considered trivially relocatable, and the code above has undefined behavior
at runtime.
*d
’s vptr is memmoved into*b
, and then the virtual callb->getter()
invokesD::getter
through that (now-erroneous) vptr, which tries to access the data memberd
of aD
object that doesn’t actually exist.
The Godbolt above uses my own Clang/libc++ implementation of P1144R8, and Corentin Jabot’s Clang implementation of P2786R0 (with none of the library components). I’ve told Corentin he should feel free to adopt any pieces of my libc++ implementation that would help get the P2786 demonstration into a working state. Of course, the authors of P2786 could also help by refactoring P2786’s library clauses to match P1144’s. :) As you can see, the P1144 library facilities tend to be more usable than P2786’s.
This might be a good time to remind folks that my Clang/libc++ implementation also provides
a [[clang::maybe_trivially_relocatable]]
attribute implementing P2786’s
“dull knife” semantics (but without P2786R1’s
sharp-when-you-didn’t-want-it parts, like its treatment of polymorphic types). So you can experiment
with a full libc++ implementation of dull-knife semantics simply by passing
-D_LIBCPP_TRIVIALLY_RELOCATABLE_IF(x)=[[clang::maybe_trivially_relocatable(x)]]
.
(Godbolt.)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK