Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(951)

Unified Diff: net/spdy/spdy_session_spdy3_unittest.cc

Issue 12207122: SPDY - Added unit tests for use after free of SpdySession (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/spdy/spdy_session_spdy2_unittest.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_session_spdy3_unittest.cc
===================================================================
--- net/spdy/spdy_session_spdy3_unittest.cc (revision 181662)
+++ net/spdy/spdy_session_spdy3_unittest.cc (working copy)
@@ -1936,16 +1936,18 @@
EXPECT_TRUE(data.at_read_eof());
}
-// Test that SpdySession::DoRead yields while reading the data. This test makes
-// 4 reads of kMaxReadBytes / 4 (-spdy_data_frame_size), one read of
-// kMaxReadBytes (-spdy_data_frame_size), and some reads of kMaxReadBytes + 8k
-// (-spdy_data_frame_size), bytes of data available on the socket for reading.
-// It then verifies that DoRead has yielded even though there is data available
-// for it to read (i.e, socket()->Read didn't return ERR_IO_PENDING during
-// socket reads). Also verifies that SpdySession reads only
-// SpdySession::kReadBufferSize data from the underlying transport.
-// TODO(rtennti): Make this test work after fixes to DeterministicSocketData.
-TEST_F(SpdySessionSpdy3Test, DISABLED_TestYieldingDuringLargeReadData) {
+// Test that SpdySession::DoRead() tests interactions of yielding + async,
+// by doing the following MockReads.
+//
+// MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K
+// ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K.
+//
+// The above reads 26K synchronously. Since that is less that 32K, we will
+// attempt to read again. However, that DoRead() will return ERR_IO_PENDING
+// (because of async read), so DoRead() will yield. When we come back, DoRead()
+// will read the results from the async read, and rest of the data
+// synchronously.
+TEST_F(SpdySessionSpdy3Test, TestYieldingDuringAsyncReadData) {
MockConnect connect_data(SYNCHRONOUS, OK);
BufferedSpdyFramer framer(3, false);
@@ -1957,36 +1959,24 @@
// Build buffer of size kMaxReadBytes / 4 (-spdy_data_frame_size).
ASSERT_EQ(32 * 1024, kMaxReadBytes);
TestDataStream test_stream;
- const int kSmallPayloadSize = kMaxReadBytes / 4 - SpdyDataFrame::size();
- scoped_refptr<net::IOBuffer> small_payload(
- new net::IOBuffer(kSmallPayloadSize));
- char* small_payload_data = small_payload->data();
- test_stream.GetBytes(small_payload_data, kSmallPayloadSize);
+ const int kEightKPayloadSize = kMaxReadBytes / 4 - SpdyDataFrame::size();
+ scoped_refptr<net::IOBuffer> eightk_payload(
+ new net::IOBuffer(kEightKPayloadSize));
+ char* eightk_payload_data = eightk_payload->data();
+ test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize);
- // Build buffer of size kMaxReadBytes - (-spdy_data_frame_size).
- TestDataStream test_stream1;
- const int kMaxReadBytesPayloadSize = kMaxReadBytes - SpdyDataFrame::size();
- scoped_refptr<net::IOBuffer> max_bytes_payload(
- new net::IOBuffer(kMaxReadBytesPayloadSize));
- char* max_bytes_payload_data = max_bytes_payload->data();
- test_stream1.GetBytes(max_bytes_payload_data, kMaxReadBytesPayloadSize);
-
- // Build buffer of size kMaxReadBytes + kSmallPayloadSize
- // (-spdy_data_frame_size).
+ // Build buffer of 2k size.
TestDataStream test_stream2;
- const int kLargePayloadSize =
- kMaxReadBytes + kSmallPayloadSize - SpdyDataFrame::size();
- scoped_refptr<net::IOBuffer> large_payload(
- new net::IOBuffer(kLargePayloadSize));
- char* large_payload_data = large_payload->data();
- test_stream2.GetBytes(large_payload_data, kLargePayloadSize);
+ const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024;
+ scoped_refptr<net::IOBuffer> twok_payload(
+ new net::IOBuffer(kTwoKPayloadSize));
+ char* twok_payload_data = twok_payload->data();
+ test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize);
- scoped_ptr<SpdyFrame> small_data_frame(framer.CreateDataFrame(
- 1, small_payload_data, kSmallPayloadSize, DATA_FLAG_NONE));
- scoped_ptr<SpdyFrame> max_bytes_data_frame(framer.CreateDataFrame(
- 1, max_bytes_payload_data, kMaxReadBytesPayloadSize, DATA_FLAG_NONE));
- scoped_ptr<SpdyFrame> large_data_frame(framer.CreateDataFrame(
- 1, large_payload_data, kLargePayloadSize, DATA_FLAG_NONE));
+ scoped_ptr<SpdyFrame> eightk_data_frame(framer.CreateDataFrame(
+ 1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE));
+ scoped_ptr<SpdyFrame> twok_data_frame(framer.CreateDataFrame(
+ 1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE));
scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame(
1, "h", 1, DATA_FLAG_FIN));
@@ -1994,14 +1984,17 @@
MockRead reads[] = {
CreateMockRead(*resp1, 1),
- CreateMockRead(*small_data_frame, 2),
- CreateMockRead(*small_data_frame, 3, SYNCHRONOUS),
- CreateMockRead(*small_data_frame, 4, SYNCHRONOUS),
- CreateMockRead(*small_data_frame, 5, SYNCHRONOUS),
- CreateMockRead(*max_bytes_data_frame, 6),
- CreateMockRead(*large_data_frame, 7, SYNCHRONOUS),
- CreateMockRead(*finish_data_frame, 8, SYNCHRONOUS),
- MockRead(ASYNC, 0, 9) // EOF
+ CreateMockRead(*eightk_data_frame, 2),
+ CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS),
+ CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
+ CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS),
+ CreateMockRead(*eightk_data_frame, 6, ASYNC),
+ CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS),
+ CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
+ CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
+ CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS),
+ CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS),
+ MockRead(ASYNC, 0, 12) // EOF
};
// Create SpdySession and SpdyStream and send the request.
@@ -2036,7 +2029,7 @@
EXPECT_TRUE(spdy_stream1->HasUrl());
spdy_stream1->SendRequest(false);
- // Set up the TaskObserver to verify SpdySession::DoRead posts a task.
+ // Set up the TaskObserver to monitor SpdySession::DoRead posting of tasks.
SpdySessionTestTaskObserver observer("spdy_session.cc", "DoRead");
// Run until 1st read.
@@ -2046,7 +2039,7 @@
EXPECT_EQ(0u, observer.executed_count());
// Read all the data and verify SpdySession::DoRead has posted a task.
- data.RunFor(10);
+ data.RunFor(12);
// Verify task observer's executed_count is 1, which indicates DoRead has
// posted only one task and thus yielded though there is data available for
@@ -2056,4 +2049,82 @@
EXPECT_TRUE(data.at_read_eof());
}
+// Send a GoAway frame when SpdySession is in DoLoop. If scoped_refptr to
+// <SpdySession> is deleted from SpdySession::DoLoop(), we get a crash because
+// GoAway could delete the SpdySession from the SpdySessionPool and the last
+// reference to SpdySession.
+TEST_F(SpdySessionSpdy3Test, GoAwayWhileInDoLoop) {
+ MockConnect connect_data(SYNCHRONOUS, OK);
+ BufferedSpdyFramer framer(3, false);
+
+ scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, MEDIUM));
+ MockWrite writes[] = {
+ CreateMockWrite(*req1, 0),
+ };
+
+ scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<SpdyFrame> body1(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<SpdyFrame> goaway(ConstructSpdyGoAway());
+
+ MockRead reads[] = {
+ CreateMockRead(*resp1, 1),
+ CreateMockRead(*body1, 2),
+ CreateMockRead(*goaway, 3),
+ MockRead(ASYNC, 0, 4) // EOF
+ };
+
+ // Create SpdySession and SpdyStream and send the request.
+ DeterministicSocketData data(reads, arraysize(reads),
+ writes, arraysize(writes));
+ data.set_connect_data(connect_data);
+ session_deps_.host_resolver->set_synchronous_mode(true);
+ session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+
+ SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+ session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+
+ CreateDeterministicNetworkSession();
+
+ scoped_refptr<SpdySession> session = CreateInitializedSession();
+
+ scoped_refptr<SpdyStream> spdy_stream1;
+ TestCompletionCallback callback1;
+ GURL url1("http://www.google.com");
+ EXPECT_EQ(OK, session->CreateStream(url1, MEDIUM, &spdy_stream1,
+ BoundNetLog(), callback1.callback()));
+ EXPECT_EQ(0u, spdy_stream1->stream_id());
+
+ scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
+ (*headers)[":method"] = "GET";
+ (*headers)[":scheme"] = url1.scheme();
+ (*headers)[":host"] = url1.host();
+ (*headers)[":path"] = url1.path();
+ (*headers)[":version"] = "HTTP/1.1";
+
+ spdy_stream1->set_spdy_headers(headers.Pass());
+ EXPECT_TRUE(spdy_stream1->HasUrl());
+ spdy_stream1->SendRequest(false);
+
+ // Run until 1st read.
+ EXPECT_EQ(0u, spdy_stream1->stream_id());
+ data.RunFor(1);
+ EXPECT_EQ(1u, spdy_stream1->stream_id());
+
+ // Drop the reference to the session.
+ session = NULL;
+
+ // Run until GoAway.
+ data.RunFor(2);
+
+ // Drop the reference to the stream which deletes its reference to the
+ // SpdySession. Only references to SpdySession are held by DoLoop and
+ // SpdySessionPool. If DoLoop doesn't hold the reference, we get a crash if
+ // SpdySession is deleted from the SpdySessionPool.
+ spdy_stream1 = NULL;
+
+ data.RunFor(2);
+ EXPECT_TRUE(data.at_write_eof());
+ EXPECT_TRUE(data.at_read_eof());
+}
+
} // namespace net
« no previous file with comments | « net/spdy/spdy_session_spdy2_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698