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(