• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "build/build_config.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <limits>
11 #include <memory>
12 #include <set>
13 
14 #include "base/run_loop.h"
15 #include "ipc/ipc_channel_reader.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace IPC {
19 namespace internal {
20 
21 namespace {
22 
23 class MockChannelReader : public ChannelReader {
24  public:
MockChannelReader()25   MockChannelReader()
26       : ChannelReader(nullptr), last_dispatched_message_(nullptr) {}
27 
ReadData(char * buffer,int buffer_len,int * bytes_read)28   ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) override {
29     if (data_.empty())
30       return READ_PENDING;
31 
32     size_t read_len = std::min(static_cast<size_t>(buffer_len), data_.size());
33     memcpy(buffer, data_.data(), read_len);
34     *bytes_read = static_cast<int>(read_len);
35     data_.erase(0, read_len);
36     return READ_SUCCEEDED;
37   }
38 
ShouldDispatchInputMessage(Message * msg)39   bool ShouldDispatchInputMessage(Message* msg) override { return true; }
40 
GetAttachments(Message * msg)41   bool GetAttachments(Message* msg) override { return true; }
42 
DidEmptyInputBuffers()43   bool DidEmptyInputBuffers() override { return true; }
44 
HandleInternalMessage(const Message & msg)45   void HandleInternalMessage(const Message& msg) override {}
46 
DispatchMessage(Message * m)47   void DispatchMessage(Message* m) override { last_dispatched_message_ = m; }
48 
get_last_dispatched_message()49   Message* get_last_dispatched_message() { return last_dispatched_message_; }
50 
AppendData(const void * data,size_t size)51   void AppendData(const void* data, size_t size) {
52     data_.append(static_cast<const char*>(data), size);
53   }
54 
AppendMessageData(const Message & message)55   void AppendMessageData(const Message& message) {
56     AppendData(message.data(), message.size());
57   }
58 
59  private:
60   Message* last_dispatched_message_;
61   std::string data_;
62 };
63 
64 class ExposedMessage: public Message {
65  public:
66   using Message::Header;
67   using Message::header;
68 };
69 
70 // Payload that makes messages large
71 const size_t LargePayloadSize = Channel::kMaximumReadBufferSize * 3 / 2;
72 
73 }  // namespace
74 
75 // We can determine message size from its header (and hence resize the buffer)
76 // only when attachment broker is not used, see IPC::Message::FindNext().
77 
TEST(ChannelReaderTest,ResizeOverflowBuffer)78 TEST(ChannelReaderTest, ResizeOverflowBuffer) {
79   MockChannelReader reader;
80 
81   ExposedMessage::Header header = {};
82 
83   header.payload_size = 128 * 1024;
84   EXPECT_LT(reader.input_overflow_buf_.capacity(), header.payload_size);
85   EXPECT_TRUE(reader.TranslateInputData(
86       reinterpret_cast<const char*>(&header), sizeof(header)));
87 
88   // Once message header is available we resize overflow buffer to
89   // fit the entire message.
90   EXPECT_GE(reader.input_overflow_buf_.capacity(), header.payload_size);
91 }
92 
TEST(ChannelReaderTest,InvalidMessageSize)93 TEST(ChannelReaderTest, InvalidMessageSize) {
94   MockChannelReader reader;
95 
96   ExposedMessage::Header header = {};
97 
98   size_t capacity_before = reader.input_overflow_buf_.capacity();
99 
100   // Message is slightly larger than maximum allowed size
101   header.payload_size = Channel::kMaximumMessageSize + 1;
102   EXPECT_FALSE(reader.TranslateInputData(
103       reinterpret_cast<const char*>(&header), sizeof(header)));
104   EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
105 
106   // Payload size is negative, overflow is detected by Pickle::PeekNext()
107   header.payload_size = static_cast<uint32_t>(-1);
108   EXPECT_FALSE(reader.TranslateInputData(
109       reinterpret_cast<const char*>(&header), sizeof(header)));
110   EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
111 
112   // Payload size is maximum int32_t value
113   header.payload_size = std::numeric_limits<int32_t>::max();
114   EXPECT_FALSE(reader.TranslateInputData(
115       reinterpret_cast<const char*>(&header), sizeof(header)));
116   EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
117 }
118 
TEST(ChannelReaderTest,TrimBuffer)119 TEST(ChannelReaderTest, TrimBuffer) {
120   // ChannelReader uses std::string as a buffer, and calls reserve()
121   // to trim it to kMaximumReadBufferSize. However, an implementation
122   // is free to actually reserve a larger amount.
123   size_t trimmed_buffer_size;
124   {
125     std::string buf;
126     buf.reserve(Channel::kMaximumReadBufferSize);
127     trimmed_buffer_size = buf.capacity();
128   }
129 
130   // Buffer is trimmed after message is processed.
131   {
132     MockChannelReader reader;
133 
134     Message message;
135     message.WriteString(std::string(LargePayloadSize, 'X'));
136 
137     // Sanity check
138     EXPECT_TRUE(message.size() > trimmed_buffer_size);
139 
140     // Initially buffer is small
141     EXPECT_LE(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
142 
143     // Write and process large message
144     reader.AppendMessageData(message);
145     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
146               reader.ProcessIncomingMessages());
147 
148     // After processing large message buffer is trimmed
149     EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
150   }
151 
152   // Buffer is trimmed only after entire message is processed.
153   {
154     MockChannelReader reader;
155 
156     ExposedMessage message;
157     message.WriteString(std::string(LargePayloadSize, 'X'));
158 
159     // Write and process message header
160     reader.AppendData(message.header(), sizeof(ExposedMessage::Header));
161     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
162               reader.ProcessIncomingMessages());
163 
164     // We determined message size for the message from its header, so
165     // we resized the buffer to fit.
166     EXPECT_GE(reader.input_overflow_buf_.capacity(), message.size());
167 
168     // Write and process payload
169     reader.AppendData(message.payload(), message.payload_size());
170     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
171               reader.ProcessIncomingMessages());
172 
173     // But once we process the message, we trim the buffer
174     EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
175   }
176 
177   // Buffer is not trimmed if the next message is also large.
178   {
179     MockChannelReader reader;
180 
181     // Write large message
182     Message message1;
183     message1.WriteString(std::string(LargePayloadSize * 2, 'X'));
184     reader.AppendMessageData(message1);
185 
186     // Write header for the next large message
187     ExposedMessage message2;
188     message2.WriteString(std::string(LargePayloadSize, 'Y'));
189     reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
190 
191     // Process messages
192     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
193               reader.ProcessIncomingMessages());
194 
195     // We determined message size for the second (partial) message, so
196     // we resized the buffer to fit.
197     EXPECT_GE(reader.input_overflow_buf_.capacity(), message1.size());
198   }
199 
200   // Buffer resized appropriately if next message is larger than the first.
201   // (Similar to the test above except for the order of messages.)
202   {
203     MockChannelReader reader;
204 
205     // Write large message
206     Message message1;
207     message1.WriteString(std::string(LargePayloadSize, 'Y'));
208     reader.AppendMessageData(message1);
209 
210     // Write header for the next even larger message
211     ExposedMessage message2;
212     message2.WriteString(std::string(LargePayloadSize * 2, 'X'));
213     reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
214 
215     // Process messages
216     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
217               reader.ProcessIncomingMessages());
218 
219     // We determined message size for the second (partial) message, and
220     // resized the buffer to fit it.
221     EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
222   }
223 
224   // Buffer is not trimmed if we've just resized it to accommodate large
225   // incoming message.
226   {
227     MockChannelReader reader;
228 
229     // Write small message
230     Message message1;
231     message1.WriteString(std::string(11, 'X'));
232     reader.AppendMessageData(message1);
233 
234     // Write header for the next large message
235     ExposedMessage message2;
236     message2.WriteString(std::string(LargePayloadSize, 'Y'));
237     reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
238 
239     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
240               reader.ProcessIncomingMessages());
241 
242     // We determined message size for the second (partial) message, so
243     // we resized the buffer to fit.
244     EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
245   }
246 }
247 
248 }  // namespace internal
249 }  // namespace IPC
250