Skip to content

Commit e8f7308

Browse files
authored
Clarify how to derive a -1 data member pointer
See the discussion here: #162
1 parent d9dc0c0 commit e8f7308

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

abi.html

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -709,13 +709,6 @@ <h4><a href="#data-member-pointers"> 2.3.1 Data Member Pointers </a></h4>
709709

710710
<p>
711711
A null data member pointer is represented as an offset of <code>-1</code>.
712-
Unfortunately, it is possible to generate a data member pointer with an
713-
offset of <code>-1</code> using explicit derived-to-base conversions.
714-
If this is done, implementations following this ABI may misbehave.
715-
<span class="future-abi">Recommendation for new platforms: consider using
716-
a different representation for data member pointers, such as left-shifting
717-
the offset by one and using a non-zero low bit to indicate a non-null
718-
value.</span>
719712

720713
<p>
721714
Note that by <code>[dcl.init]</code>, "zero initialization" of a data
@@ -732,6 +725,45 @@ <h4><a href="#data-member-pointers"> 2.3.1 Data Member Pointers </a></h4>
732725
to cross a <code>virtual</code> base relationship, and so a static offset
733726
is always known.
734727

728+
<p>
729+
Data member pointers that identify members of their class will always
730+
store non-negative offsets. Unfortunately, it is possible to apply
731+
conversions to a non-null data member pointer that will cause it to
732+
hold a negative offset. If this value is <code>-1</code>, the member
733+
pointer will subsequently be treated as a null pointer. This is
734+
considered an irreparable defect in this ABI.
735+
<span class="future-abi">Recommendation for new platforms: consider using
736+
a different representation for data member pointers, such as left-shifting
737+
the offset by one and using a non-zero low bit to indicate a non-null
738+
value.</span>
739+
740+
<p>
741+
It is relatively difficult to demonstrate this defect in well-defined
742+
code. It is possible to convert a member pointer to a member pointer in
743+
a derived class and then cast it back it to a different base class; if the
744+
second base class is stored after the first, the resulting offset will be
745+
negative. However, this cast has undefined behavior because the member is
746+
no longer a member of a base or derived class of the member pointer's
747+
class. To demonstrate the defect, either an empty base class or an empty
748+
data member must be involved. For example:
749+
750+
<pre>
751+
struct alignas(2) B1 {};
752+
753+
struct B2 : B1 {};
754+
struct B3 : B1 {};
755+
756+
struct D : B2, B3 {
757+
char a, b;
758+
};
759+
760+
// The offset in D of the B3 base subobject is 2, but the
761+
// offset of the data member b is 1.
762+
auto mptr = static_cast<char B3::*>(&D::b);
763+
764+
char B::*mptr = static_cast<char B::*>(static_cast<char C::*>(&A::a));
765+
</pre>
766+
735767
<a name="member-function-pointers"></a>
736768
<h4><a href="#member-function-pointers"> 2.3.2 Member Function Pointers </a></h4>
737769

0 commit comments

Comments
 (0)