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