Add memory safety guard for QuicFrame
The current memory model for QuicFrame is error-prone in that the owner of an array of QuicFrames is responsible for deleting non-inlined frames. This CL adds a check in debug and asan builds that will ensure that we crash if we accidentally attempt to delete an ACK frame that is owned by the QuicReceivedPacketManager.
Debug-only change
PiperOrigin-RevId: 328649792
Change-Id: I419cec433393d9f978dffc7f4f54e60c5293fc05
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc
index 99b0963..7fe322d 100644
--- a/quic/core/frames/quic_frame.cc
+++ b/quic/core/frames/quic_frame.cc
@@ -87,6 +87,16 @@
}
void DeleteFrame(QuicFrame* frame) {
+#if QUIC_FRAME_DEBUG
+ // If the frame is not inlined, check that it can be safely deleted.
+ if (frame->type != PADDING_FRAME && frame->type != MTU_DISCOVERY_FRAME &&
+ frame->type != PING_FRAME && frame->type != MAX_STREAMS_FRAME &&
+ frame->type != STOP_WAITING_FRAME &&
+ frame->type != STREAMS_BLOCKED_FRAME && frame->type != STREAM_FRAME &&
+ frame->type != HANDSHAKE_DONE_FRAME) {
+ CHECK(!frame->delete_forbidden) << *frame;
+ }
+#endif // QUIC_FRAME_DEBUG
switch (frame->type) {
// Frames smaller than a pointer are inlined, so don't need to be deleted.
case PADDING_FRAME:
diff --git a/quic/core/frames/quic_frame.h b/quic/core/frames/quic_frame.h
index b5785b8..6e096e3 100644
--- a/quic/core/frames/quic_frame.h
+++ b/quic/core/frames/quic_frame.h
@@ -36,6 +36,14 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#ifndef QUIC_FRAME_DEBUG
+#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
+#define QUIC_FRAME_DEBUG 1
+#else // !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
+#define QUIC_FRAME_DEBUG 0
+#endif // !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
+#endif // QUIC_FRAME_DEBUG
+
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicFrame {
@@ -87,6 +95,10 @@
struct {
QuicFrameType type;
+#if QUIC_FRAME_DEBUG
+ bool delete_forbidden = false;
+#endif // QUIC_FRAME_DEBUG
+
// TODO(wub): These frames can also be inlined without increasing the size
// of QuicFrame: QuicRstStreamFrame, QuicWindowUpdateFrame,
// QuicBlockedFrame, QuicPathResponseFrame, QuicPathChallengeFrame and
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index 9cc6c29..539cdce 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -189,7 +189,13 @@
}
}
+#if QUIC_FRAME_DEBUG
+ QuicFrame frame = QuicFrame(&ack_frame_);
+ frame.delete_forbidden = true;
+ return frame;
+#else // QUIC_FRAME_DEBUG
return QuicFrame(&ack_frame_);
+#endif // QUIC_FRAME_DEBUG
}
void QuicReceivedPacketManager::DontWaitForPacketsBefore(