C++ Logo

std-discussion

Advanced search

Re: Is it valid use reinterpret_cast to form pointer to object?

From: Thiago Macieira <thiago_at_[hidden]>
Date: Mon, 31 Jul 2023 16:33:42 -0700
On Monday, 31 July 2023 14:01:11 PDT Bjorn Reese via Std-Discussion wrote:
> > I can't figure out if the second application is valid in general, or is
> > it UB? It seems that the standard of the language through prescriptions
>
> Undefined behaviour. See https://wg21.link/p2590

I just want to point out that I disagree with the premises of the paper above.
I know this means I disagree with the current wording of the standard, as the
paper has been adopted for C++23, but I think that was a mistake.

The paper says these reinterpret_cast are UB:

void process(Stream* stream) {
  std::unique_ptr<char[]> buffer = stream->read();
  if (buffer[0] == FOO)
    processFoo(reinterpret_cast<Foo*>(buffer.get()));
  else
    processBar(reinterpret_cast<Bar*>(buffer.get()));
}

But the standard also says that memcpy() is allowed to implicitly create
objects, something this paper even reminds us of. Since any read() implies a
memcpy() from some other storage, I argue that the object's lifetime was
already started. This means the correct function here was std::launder().

If you don't believe me, see the kernel source code. For simplicity, I here
are the links for a pipe instead of network or disk I/O:
https://codebrowser.dev/linux/linux/fs/pipe.c.html#pipe_read calls
https://codebrowser.dev/linux/linux/lib/iov_iter.c.html#copy_page_to_iter then
https://codebrowser.dev/linux/linux/lib/iov_iter.c.html#_copy_to_iter, then
https://codebrowser.dev/linux/linux/lib/iov_iter.c.html#copyout, which finally
calls raw_copy_to_user()

That last function is a memcpy(). Of course, since this is a freestanding
implementation, the implementation of memcpy() comes with the source code, but
that does not negate the memcpy()'s attributes. The x86-64 port implements it
in an assembly block which does rep movsb, which is memcpy() in a two-byte
assembler instruction. https://codebrowser.dev/linux/linux/arch/x86/include/
asm/uaccess_64.h.html#copy_user_generic

The MIPS implementations is the same as memcpy:
https://github.com/torvalds/linux/blob/master/arch/mips/lib/memcpy.S#L660

The User Mode implementation actually calls memcpy:
https://codebrowser.dev/linux/linux/arch/um/kernel/skas/
uaccess.c.html#raw_copy_from_user


Ditto for FreeBSD, which is more direct
https://github.com/freebsd/freebsd-src/blob/main/sys/kern/sys_pipe.c#L713
https://github.com/freebsd/freebsd-src/blob/main/sys/kern/subr_uio.c#L195
https://github.com/freebsd/freebsd-src/blob/main/sys/kern/subr_uio.c#L209
https://github.com/freebsd/freebsd-src/blob/main/sys/amd64/amd64/
copyout.c#L186 →
https://github.com/freebsd/freebsd-src/blob/main/sys/amd64/amd64/
support.S#L847, which inlines memmove()

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel DCAI Cloud Engineering

Received on 2023-07-31 23:33:45