Date: Mon, 31 Jul 2023 16:58:33 -0700
On Monday, 31 July 2023 16:33:42 PDT Thiago Macieira via Std-Discussion wrote:
> 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().
And see my other reply: how do you prove that the read() → memcpy() didn't
create an object of type
union U
{
char storage[std::max(sizeof(Foo), sizeof(Bar))];
Foo foo;
Bar bar;
};
That means reinterpret_cast is allowed here without UB.
The prototypical use of this is struct sockaddr, like in my own code at
https://github.com/qt/qtbase/blob/c6fce818db7e56f659ea88784d2f9278f9ce1436/
src/network/socket/qnativesocketengine_p.h#L77
inline QT_SOCKLEN_T setSockaddr(sockaddr *sa, const QHostAddress &addr,
quint16 port = 0)
{
switch (addr.protocol()) {
case QHostAddress::IPv4Protocol:
return setSockaddr(reinterpret_cast<sockaddr_in *>(sa), addr, port);
case QHostAddress::IPv6Protocol:
case QHostAddress::AnyIPProtocol:
return setSockaddr(reinterpret_cast<sockaddr_in6 *>(sa), addr, port);
This is allowed because those three types are members of
union qt_sockaddr {
sockaddr a;
sockaddr_in a4;
sockaddr_in6 a6;
};
https://github.com/qt/qtbase/blob/c6fce818db7e56f659ea88784d2f9278f9ce1436/
src/network/socket/qnativesocketengine_p_p.h#L63-L67
> 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().
And see my other reply: how do you prove that the read() → memcpy() didn't
create an object of type
union U
{
char storage[std::max(sizeof(Foo), sizeof(Bar))];
Foo foo;
Bar bar;
};
That means reinterpret_cast is allowed here without UB.
The prototypical use of this is struct sockaddr, like in my own code at
https://github.com/qt/qtbase/blob/c6fce818db7e56f659ea88784d2f9278f9ce1436/
src/network/socket/qnativesocketengine_p.h#L77
inline QT_SOCKLEN_T setSockaddr(sockaddr *sa, const QHostAddress &addr,
quint16 port = 0)
{
switch (addr.protocol()) {
case QHostAddress::IPv4Protocol:
return setSockaddr(reinterpret_cast<sockaddr_in *>(sa), addr, port);
case QHostAddress::IPv6Protocol:
case QHostAddress::AnyIPProtocol:
return setSockaddr(reinterpret_cast<sockaddr_in6 *>(sa), addr, port);
This is allowed because those three types are members of
union qt_sockaddr {
sockaddr a;
sockaddr_in a4;
sockaddr_in6 a6;
};
https://github.com/qt/qtbase/blob/c6fce818db7e56f659ea88784d2f9278f9ce1436/
src/network/socket/qnativesocketengine_p_p.h#L63-L67
-- Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org Software Architect - Intel DCAI Cloud Engineering
Received on 2023-07-31 23:58:35