C++ Logo

std-proposals

Advanced search

Re: Allowing access to object representations

From: Brian Bi <bbi5291_at_[hidden]>
Date: Mon, 19 Aug 2019 17:23:04 -0500
On Mon, Aug 19, 2019 at 5:11 PM language.lawyer--- via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On 20/08/2019 00:37, Brian Bi wrote:
> > On Mon, Aug 19, 2019 at 4:20 PM language.lawyer--- via Std-Proposals <
> > std-proposals_at_[hidden]> wrote:
> >
> >>>> The creation of an object of type T would end the lifetime of the
> array
> >>>> elements, so accessing them would be UB.
> >>>>
> >>>
> >>> An array of unsigned char or std::byte can have an object of some other
> >>> type nested within it, so the array's lifetime is not ended.
> >>
> >> Right, but I wrote that the lifetimes of the array *elements* would end.
> >> There is no "nested within" relation between the elements and an object
> >> which is placed over them.
> >>
> >
> > [intro.object]/3
> > If a complete object is created ([expr.new]
> > <http://eel.is/c++draft/expr.new>) in storage associated with another
> > object e of type “array of N unsigned char” or of type “array of N
> std::byte”
> > ([cstddef.syn] <http://eel.is/c++draft/cstddef.syn>), that array
> *provides
> > storage* <http://eel.is/c++draft/basic.memobj#def:provides_storage> for
> the
> > created object if: ...
> >
> > [intro.object]/4
> > An object a is *nested within*
> > <http://eel.is/c++draft/basic.memobj#def:nested_within> another object
> b if:
> > *...* or b provides storage for a, or ...
> >
> >
> > [basic.life]/1
> > The lifetime of an object o of type T ends when: ... the storage which
> the
> > object occupies is released, or is reused by an object that is not nested
> > within o ([intro.object] <
> http://eel.is/c++draft/basic.memobj#intro.object>)
> > . <http://eel.is/c++draft/basic.memobj#basic.life-1.sentence-4>
>
> Again: the lifetime of the array won't end, but the lifetime of its
> *elements*, covered by a newly created object, will.
> If, say, an `int` object `i` is created at the beginning of an `unsigned
> char` array `a`, which one nested within the other: `i` or `a[0]`?
> Neither is.
>

Sorry, my fault for not understanding what you wrote previously. But are
you sure this interpretation is sensible? I think it's impossible to say
that the lifetime of an array does not end while the lifetimes of its
elements end. Anyway, you might be right (at least, your interpretation
does line up with what the text says). So, that would mean two std::bless
calls would be needed. Lovely!


>
> >>>> This just shows that the access to object representations do not fit
> >> well
> >>>> into the current model of the C++ abstract machine.
> >>>>
> >>>
> >>> Indeed. On one hand, one could conclude that people who want to access
> >>> object representations should just suck it up. On the other hand, one
> >> could
> >>> observe that the current C++ memory and object model results in a lot
> of
> >>> pre-C++17 code being broken, and conclude that it should be revised.
> >>>
> >>> Besides, even if you think that no one should ever try to access object
> >>> representations of anything much more complicated than a struct with a
> >>> bunch of ints in it, do you think it is reasonable to limit typical
> usage
> >>> of offsetof to such types as well? If I have a pointer to a member of
> >> some
> >>> class that is standard-layout but not implicit-lifetime, should there
> not
> >>> be a way for me to get a pointer to the enclosing class using pointer
> >>> arithmetic? Are you comfortable with letting all the existing code of
> >> this
> >>> form, written before C++17, continue to be broken? What did we gain
> from
> >>> the C++17 changes that was so beneficial that it justified *silently
> >>> breaking* said code? What about the fact that the migration effort for
> >> such
> >>> code can be significant (given, as I've pointed out, the inadequacies
> of
> >>> the proposed std::bless solution)?
> >>
> >> Isn't offsetof usually used in some low-level code which typically also
> >> breaks the strict aliasing rule?
> >> There are compiler flags making the later behavior defined.
> >> It is not forbidden for implementations to define behavior which the
> >> standard does not define.
> >>
> >
> > I don't see why that is necessarily the case. It could, for example, be
> > used to allow a user to remove an object from a node-based container
> given
> > a pointer to the object. There's no reason why such code should have to
> > depend on special flags to make strict aliasing violations well-defined.
> > Oh, sure, you can rewrite the container so that its API is based on
> > iterators instead, to avoid this problem---and, of course, you'll also
> have
> > to rewrite ALL the code that uses it. As I said, the migration effort is
> > "significant".
>
> I do not think that a lot of developers started to rewrite their code
> because its behavior became undefined in C++17.
>

Exactly - that means it's still undefined. As I said in one of my earlier
messages, it is undesirable to change the standard in a way that breaks
lots of code which people will then not rewrite, as this erodes the
legitimacy of the standard (and leaves users uncertain about what might get
trampled by their compiler optimizers the next time they update.) Yet
that's exactly what happened in C++17, and we should fix that.


> (I'd say it always was undefined)
>

CWG thought it was well-defined in 2011. Now, you can say that even then
the wording made it undefined, but if the wording contradicted all of (a)
the committee's intent, (b) the common understanding of C++ programmers,
and (c) the rules of C++ that compiler authors implicitly targeted... then
that just means the wording was defective at that point (the point of view
that I advocate).


>
> >>>>>> I do not think that this is a good way.
> >>>>>>
> >>>>>
> >>>>> What problem did this cause when it was effectively the status quo in
> >>>>> C++14, that is so serious that we should not attempt to codify it in
> >>>> C++23
> >>>>> or some future version of the standard?
> >>>>
> >>>> I do not think calling bytes of memory "objects" is a good status quo.
> >>>>
> >>>
> >>> Is that really your only objection? Presumably, it would be possible to
> >>> word the changes to the standard in a way that would avoid this. The
> >> point
> >>> is that existing code relies on being able to do pointer arithmetic on
> >>> memory that various types of objects occupy *as though* an array of
> >> unsigned
> >>> char objects existed there. We don't have to say that there are actual
> >>> objects. Given the way pointers work in C++17, I think this would
> >> require a
> >>> lot of wording, but I think I've already stated enough times how the
> >>> alternative of doing nothing leaves a lot of code broken.
> >>
> >> I don't know the solution for this problem :/
> >>
> >
> > I don't know the solution either, but I felt it was important to point
> out
> > how "just use std::bless" is not a solution.
> > It's good that we're at least talking about the OP's proposal (although I
> > can't access it right now... what happened to the github link?)
>
> The current version is
> https://github.com/18/accessing-object-representations/blob/master/P1839R1.md,
> the original paper was renamed to ...R0.md
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>


-- 
*Brian Bi*

Received on 2019-08-19 17:25:20