Make QuicFrame a standard-layout struct.

C++ provides certain guarantees about the way union fields interact, which are only valid for standard-layout types.  Standard-layout types are not allowed to have data members in both base and derived types; this fixes that by moving QuicInlinedFrame::type into individual frames.

Also, before C++17, using offsetof() on non-standard-layout types is undefined behavor.

Thanks to Stephan Hartmann <stha09@googlemail.com> for pointing this problem out in <https://quiche-review.googlesource.com/c/quiche/+/10600>.

PiperOrigin-RevId: 320195673
Change-Id: I179634af3e3a199b7b7320a031b42898a5644824
diff --git a/quic/core/frames/quic_frame.h b/quic/core/frames/quic_frame.h
index a8aabfc..b5785b8 100644
--- a/quic/core/frames/quic_frame.h
+++ b/quic/core/frames/quic_frame.h
@@ -6,6 +6,7 @@
 #define QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_
 
 #include <ostream>
+#include <type_traits>
 #include <vector>
 
 #include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h"
@@ -111,6 +112,8 @@
   };
 };
 
+static_assert(std::is_standard_layout<QuicFrame>::value,
+              "QuicFrame must have a standard layout");
 static_assert(sizeof(QuicFrame) <= 24,
               "Frames larger than 24 bytes should be referenced by pointer.");
 static_assert(offsetof(QuicStreamFrame, type) == offsetof(QuicFrame, type),
diff --git a/quic/core/frames/quic_handshake_done_frame.h b/quic/core/frames/quic_handshake_done_frame.h
index c16c169..1dd3fa0 100644
--- a/quic/core/frames/quic_handshake_done_frame.h
+++ b/quic/core/frames/quic_handshake_done_frame.h
@@ -23,6 +23,8 @@
       std::ostream& os,
       const QuicHandshakeDoneFrame& handshake_done_frame);
 
+  QuicFrameType type;
+
   // A unique identifier of this control frame. 0 when this frame is received,
   // and non-zero when sent.
   QuicControlFrameId control_frame_id = kInvalidControlFrameId;
diff --git a/quic/core/frames/quic_inlined_frame.h b/quic/core/frames/quic_inlined_frame.h
index 08c4869..cfa32dc 100644
--- a/quic/core/frames/quic_inlined_frame.h
+++ b/quic/core/frames/quic_inlined_frame.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_
 #define QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_
 
+#include <type_traits>
+
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 
@@ -16,13 +18,15 @@
 // inline and out-of-line frame types.
 template <typename DerivedT>
 struct QUIC_EXPORT_PRIVATE QuicInlinedFrame {
-  QuicInlinedFrame(QuicFrameType type) : type(type) {
+  QuicInlinedFrame(QuicFrameType type) {
+    static_cast<DerivedT*>(this)->type = type;
+    static_assert(std::is_standard_layout<DerivedT>::value,
+                  "Inlined frame must have a standard layout");
     static_assert(offsetof(DerivedT, type) == 0,
                   "type must be the first field.");
     static_assert(sizeof(DerivedT) <= 24,
                   "Frames larger than 24 bytes should not be inlined.");
   }
-  QuicFrameType type;
 };
 
 }  // namespace quic
diff --git a/quic/core/frames/quic_max_streams_frame.h b/quic/core/frames/quic_max_streams_frame.h
index e1595c0..902dbc2 100644
--- a/quic/core/frames/quic_max_streams_frame.h
+++ b/quic/core/frames/quic_max_streams_frame.h
@@ -28,6 +28,8 @@
       std::ostream& os,
       const QuicMaxStreamsFrame& frame);
 
+  QuicFrameType type;
+
   // A unique identifier of this control frame. 0 when this frame is received,
   // and non-zero when sent.
   QuicControlFrameId control_frame_id = kInvalidControlFrameId;
diff --git a/quic/core/frames/quic_mtu_discovery_frame.h b/quic/core/frames/quic_mtu_discovery_frame.h
index 330df21..52e980d 100644
--- a/quic/core/frames/quic_mtu_discovery_frame.h
+++ b/quic/core/frames/quic_mtu_discovery_frame.h
@@ -16,6 +16,8 @@
 struct QUIC_EXPORT_PRIVATE QuicMtuDiscoveryFrame
     : public QuicInlinedFrame<QuicMtuDiscoveryFrame> {
   QuicMtuDiscoveryFrame() : QuicInlinedFrame(MTU_DISCOVERY_FRAME) {}
+
+  QuicFrameType type;
 };
 
 }  // namespace quic
diff --git a/quic/core/frames/quic_padding_frame.h b/quic/core/frames/quic_padding_frame.h
index 0918f0f..09ddb89 100644
--- a/quic/core/frames/quic_padding_frame.h
+++ b/quic/core/frames/quic_padding_frame.h
@@ -25,6 +25,8 @@
       std::ostream& os,
       const QuicPaddingFrame& padding_frame);
 
+  QuicFrameType type;
+
   // -1: full padding to the end of a max-sized packet
   // otherwise: only pad up to num_padding_bytes bytes
   int num_padding_bytes = -1;
diff --git a/quic/core/frames/quic_ping_frame.h b/quic/core/frames/quic_ping_frame.h
index 5cefdf9..04f5afb 100644
--- a/quic/core/frames/quic_ping_frame.h
+++ b/quic/core/frames/quic_ping_frame.h
@@ -23,6 +23,8 @@
       std::ostream& os,
       const QuicPingFrame& ping_frame);
 
+  QuicFrameType type;
+
   // A unique identifier of this control frame. 0 when this frame is received,
   // and non-zero when sent.
   QuicControlFrameId control_frame_id = kInvalidControlFrameId;
diff --git a/quic/core/frames/quic_stop_waiting_frame.h b/quic/core/frames/quic_stop_waiting_frame.h
index 84bfc2a..b05d2e1 100644
--- a/quic/core/frames/quic_stop_waiting_frame.h
+++ b/quic/core/frames/quic_stop_waiting_frame.h
@@ -21,6 +21,8 @@
       std::ostream& os,
       const QuicStopWaitingFrame& s);
 
+  QuicFrameType type;
+
   // The lowest packet we've sent which is unacked, and we expect an ack for.
   QuicPacketNumber least_unacked;
 };
diff --git a/quic/core/frames/quic_stream_frame.h b/quic/core/frames/quic_stream_frame.h
index f807ee1..10ad7db 100644
--- a/quic/core/frames/quic_stream_frame.h
+++ b/quic/core/frames/quic_stream_frame.h
@@ -35,6 +35,7 @@
 
   bool operator!=(const QuicStreamFrame& rhs) const;
 
+  QuicFrameType type;
   bool fin = false;
   QuicPacketLength data_length = 0;
   // TODO(wub): Change to a QuicUtils::GetInvalidStreamId when it is not version
diff --git a/quic/core/frames/quic_streams_blocked_frame.h b/quic/core/frames/quic_streams_blocked_frame.h
index 91c7ac9..2df9636 100644
--- a/quic/core/frames/quic_streams_blocked_frame.h
+++ b/quic/core/frames/quic_streams_blocked_frame.h
@@ -28,6 +28,8 @@
       std::ostream& os,
       const QuicStreamsBlockedFrame& frame);
 
+  QuicFrameType type;
+
   // A unique identifier of this control frame. 0 when this frame is received,
   // and non-zero when sent.
   QuicControlFrameId control_frame_id = kInvalidControlFrameId;