Skip to content

Commit b6db963

Browse files
Eugene Ostroukhovofrobots
Eugene Ostroukhov
authored andcommitted
inspector: simplify buffer management
This change simplifies buffer management to address a number of issues that original implementation had. Original implementation was trying to reduce the number of allocations by providing regions of the internal buffer to libuv IO code. This introduced some potential use after free issues if the buffer grows (or shrinks) while there's a pending read. It also had some confusing math that resulted in issues on Windows version of the libuv. PR-URL: #8257 Fixes: #8155 Reviewed-By: bnoordhuis - Ben Noordhuis <[email protected]>
1 parent b1bbc68 commit b6db963

File tree

4 files changed

+62
-68
lines changed

4 files changed

+62
-68
lines changed

src/inspector_agent.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ void InterruptCallback(v8::Isolate*, void* agent) {
241241
}
242242

243243
void DataCallback(uv_stream_t* stream, ssize_t read, const uv_buf_t* buf) {
244-
inspector_socket_t* socket = static_cast<inspector_socket_t*>(stream->data);
244+
inspector_socket_t* socket = inspector_from_stream(stream);
245245
static_cast<AgentImpl*>(socket->data)->OnRemoteDataIO(socket, read, buf);
246246
}
247247

src/inspector_socket.cc

+41-58
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,17 @@ static void dump_hex(const char* buf, size_t len) {
4848
}
4949
#endif
5050

51+
static void remove_from_beginning(std::vector<char>* buffer, size_t count) {
52+
buffer->erase(buffer->begin(), buffer->begin() + count);
53+
}
54+
5155
static void dispose_inspector(uv_handle_t* handle) {
52-
inspector_socket_t* inspector =
53-
reinterpret_cast<inspector_socket_t*>(handle->data);
56+
inspector_socket_t* inspector = inspector_from_stream(handle);
5457
inspector_cb close =
5558
inspector->ws_mode ? inspector->ws_state->close_cb : nullptr;
5659
inspector->buffer.clear();
5760
delete inspector->ws_state;
5861
inspector->ws_state = nullptr;
59-
inspector->data_len = 0;
60-
inspector->last_read_end = 0;
6162
if (close) {
6263
close(inspector, 0);
6364
}
@@ -159,21 +160,19 @@ static std::vector<char> encode_frame_hybi17(const char* message,
159160
return frame;
160161
}
161162

162-
static ws_decode_result decode_frame_hybi17(const char* buffer_begin,
163-
size_t data_length,
163+
static ws_decode_result decode_frame_hybi17(const std::vector<char>& buffer,
164164
bool client_frame,
165165
int* bytes_consumed,
166166
std::vector<char>* output,
167167
bool* compressed) {
168168
*bytes_consumed = 0;
169-
if (data_length < 2)
169+
if (buffer.size() < 2)
170170
return FRAME_INCOMPLETE;
171171

172-
const char* p = buffer_begin;
173-
const char* buffer_end = p + data_length;
172+
auto it = buffer.begin();
174173

175-
unsigned char first_byte = *p++;
176-
unsigned char second_byte = *p++;
174+
unsigned char first_byte = *it++;
175+
unsigned char second_byte = *it++;
177176

178177
bool final = (first_byte & kFinalBit) != 0;
179178
bool reserved1 = (first_byte & kReserved1Bit) != 0;
@@ -215,12 +214,12 @@ static ws_decode_result decode_frame_hybi17(const char* buffer_begin,
215214
} else {
216215
return FRAME_ERROR;
217216
}
218-
if (buffer_end - p < extended_payload_length_size)
217+
if ((buffer.end() - it) < extended_payload_length_size)
219218
return FRAME_INCOMPLETE;
220219
payload_length64 = 0;
221220
for (int i = 0; i < extended_payload_length_size; ++i) {
222221
payload_length64 <<= 8;
223-
payload_length64 |= static_cast<unsigned char>(*p++);
222+
payload_length64 |= static_cast<unsigned char>(*it++);
224223
}
225224
}
226225

@@ -233,16 +232,16 @@ static ws_decode_result decode_frame_hybi17(const char* buffer_begin,
233232
}
234233
size_t payload_length = static_cast<size_t>(payload_length64);
235234

236-
if (data_length - kMaskingKeyWidthInBytes < payload_length)
235+
if (buffer.size() - kMaskingKeyWidthInBytes < payload_length)
237236
return FRAME_INCOMPLETE;
238237

239-
const char* masking_key = p;
240-
const char* payload = p + kMaskingKeyWidthInBytes;
238+
std::vector<char>::const_iterator masking_key = it;
239+
std::vector<char>::const_iterator payload = it + kMaskingKeyWidthInBytes;
241240
for (size_t i = 0; i < payload_length; ++i) // Unmask the payload.
242241
output->insert(output->end(),
243242
payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes]);
244243

245-
size_t pos = p + kMaskingKeyWidthInBytes + payload_length - buffer_begin;
244+
size_t pos = it + kMaskingKeyWidthInBytes + payload_length - buffer.begin();
246245
*bytes_consumed = pos;
247246
return closed ? FRAME_CLOSE : FRAME_OK;
248247
}
@@ -280,13 +279,13 @@ static void close_frame_received(inspector_socket_t* inspector) {
280279
}
281280
}
282281

283-
static int parse_ws_frames(inspector_socket_t* inspector, size_t len) {
282+
static int parse_ws_frames(inspector_socket_t* inspector) {
284283
int bytes_consumed = 0;
285284
std::vector<char> output;
286285
bool compressed = false;
287286

288-
ws_decode_result r = decode_frame_hybi17(&inspector->buffer[0],
289-
len, true /* client_frame */,
287+
ws_decode_result r = decode_frame_hybi17(inspector->buffer,
288+
true /* client_frame */,
290289
&bytes_consumed, &output,
291290
&compressed);
292291
// Compressed frame means client is ignoring the headers and misbehaves
@@ -312,24 +311,22 @@ static int parse_ws_frames(inspector_socket_t* inspector, size_t len) {
312311
}
313312

314313
static void prepare_buffer(uv_handle_t* stream, size_t len, uv_buf_t* buf) {
315-
inspector_socket_t* inspector =
316-
reinterpret_cast<inspector_socket_t*>(stream->data);
314+
*buf = uv_buf_init(new char[len], len);
315+
}
317316

318-
if (len > (inspector->buffer.size() - inspector->data_len)) {
319-
int new_size = (inspector->data_len + len + BUFFER_GROWTH_CHUNK_SIZE - 1) /
320-
BUFFER_GROWTH_CHUNK_SIZE *
321-
BUFFER_GROWTH_CHUNK_SIZE;
322-
inspector->buffer.resize(new_size);
317+
static void reclaim_uv_buf(inspector_socket_t* inspector, const uv_buf_t* buf,
318+
ssize_t read) {
319+
if (read > 0) {
320+
std::vector<char>& buffer = inspector->buffer;
321+
buffer.insert(buffer.end(), buf->base, buf->base + read);
323322
}
324-
buf->base = &inspector->buffer[inspector->data_len];
325-
buf->len = len;
326-
inspector->data_len += len;
323+
delete[] buf->base;
327324
}
328325

329326
static void websockets_data_cb(uv_stream_t* stream, ssize_t nread,
330327
const uv_buf_t* buf) {
331-
inspector_socket_t* inspector =
332-
reinterpret_cast<inspector_socket_t*>(stream->data);
328+
inspector_socket_t* inspector = inspector_from_stream(stream);
329+
reclaim_uv_buf(inspector, buf, nread);
333330
if (nread < 0 || nread == UV_EOF) {
334331
inspector->connection_eof = true;
335332
if (!inspector->shutting_down && inspector->ws_state->read_cb) {
@@ -339,29 +336,19 @@ static void websockets_data_cb(uv_stream_t* stream, ssize_t nread,
339336
#if DUMP_READS
340337
printf("%s read %ld bytes\n", __FUNCTION__, nread);
341338
if (nread > 0) {
342-
dump_hex(buf->base, nread);
339+
dump_hex(inspector->buffer.data() + inspector->buffer.size() - nread,
340+
nread);
343341
}
344342
#endif
345-
// 1. Move read bytes to continue the buffer
346-
// Should be same as this is supposedly last buffer
347-
ASSERT_EQ(buf->base + buf->len, &inspector->buffer[inspector->data_len]);
348-
349-
// Should be noop...
350-
memmove(&inspector->buffer[inspector->last_read_end], buf->base, nread);
351-
inspector->last_read_end += nread;
352-
353343
// 2. Parse.
354344
int processed = 0;
355345
do {
356-
processed = parse_ws_frames(inspector, inspector->last_read_end);
346+
processed = parse_ws_frames(inspector);
357347
// 3. Fix the buffer size & length
358348
if (processed > 0) {
359-
memmove(&inspector->buffer[0], &inspector->buffer[processed],
360-
inspector->last_read_end - processed);
361-
inspector->last_read_end -= processed;
362-
inspector->data_len = inspector->last_read_end;
349+
remove_from_beginning(&inspector->buffer, processed);
363350
}
364-
} while (processed > 0 && inspector->data_len > 0);
351+
} while (processed > 0 && !inspector->buffer.empty());
365352
}
366353
}
367354

@@ -435,7 +422,6 @@ static void handshake_complete(inspector_socket_t* inspector) {
435422
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->client));
436423
handshake_cb callback = inspector->http_parsing_state->callback;
437424
inspector->ws_state = new ws_state_s();
438-
inspector->last_read_end = 0;
439425
inspector->ws_mode = true;
440426
callback(inspector, kInspectorHandshakeUpgraded,
441427
inspector->http_parsing_state->path);
@@ -448,8 +434,7 @@ static void cleanup_http_parsing_state(inspector_socket_t* inspector) {
448434

449435
static void report_handshake_failure_cb(uv_handle_t* handle) {
450436
dispose_inspector(handle);
451-
inspector_socket_t* inspector =
452-
static_cast<inspector_socket_t*>(handle->data);
437+
inspector_socket_t* inspector = inspector_from_stream(handle);
453438
handshake_cb cb = inspector->http_parsing_state->callback;
454439
cleanup_http_parsing_state(inspector);
455440
cb(inspector, kInspectorHandshakeFailed, std::string());
@@ -481,8 +466,7 @@ static void init_handshake(inspector_socket_t* inspector);
481466
static int message_complete_cb(http_parser* parser) {
482467
inspector_socket_t* inspector =
483468
reinterpret_cast<inspector_socket_t*>(parser->data);
484-
struct http_parsing_state_s* state =
485-
(struct http_parsing_state_s*) inspector->http_parsing_state;
469+
struct http_parsing_state_s* state = inspector->http_parsing_state;
486470
if (parser->method != HTTP_GET) {
487471
handshake_failed(inspector);
488472
} else if (!parser->upgrade) {
@@ -527,22 +511,22 @@ static void data_received_cb(uv_stream_s* client, ssize_t nread,
527511
printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, uv_err_name(nread));
528512
}
529513
#endif
530-
inspector_socket_t* inspector =
531-
reinterpret_cast<inspector_socket_t*>((client->data));
514+
inspector_socket_t* inspector = inspector_from_stream(client);
515+
reclaim_uv_buf(inspector, buf, nread);
532516
if (nread < 0 || nread == UV_EOF) {
533517
close_and_report_handshake_failure(inspector);
534518
} else {
535519
http_parsing_state_s* state = inspector->http_parsing_state;
536520
http_parser* parser = &state->parser;
537-
http_parser_execute(parser, &state->parser_settings, &inspector->buffer[0],
538-
nread);
521+
http_parser_execute(parser, &state->parser_settings,
522+
inspector->buffer.data(), nread);
523+
remove_from_beginning(&inspector->buffer, nread);
539524
if (parser->http_errno != HPE_OK) {
540525
handshake_failed(inspector);
541526
}
542527
if (inspector->http_parsing_state->done) {
543528
cleanup_http_parsing_state(inspector);
544529
}
545-
inspector->data_len = 0;
546530
}
547531
}
548532

@@ -576,7 +560,6 @@ int inspector_accept(uv_stream_t* server, inspector_socket_t* inspector,
576560
err = uv_accept(server, client);
577561
}
578562
if (err == 0) {
579-
client->data = inspector;
580563
init_handshake(inspector);
581564
inspector->http_parsing_state->callback = callback;
582565
err = uv_read_start(client, prepare_buffer,

src/inspector_socket.h

+16-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define SRC_INSPECTOR_SOCKET_H_
33

44
#include "http_parser.h"
5+
#include "util.h"
6+
#include "util-inl.h"
57
#include "uv.h"
68

79
#include <string>
@@ -48,8 +50,6 @@ struct inspector_socket_s {
4850
struct http_parsing_state_s* http_parsing_state;
4951
struct ws_state_s* ws_state;
5052
std::vector<char> buffer;
51-
size_t data_len;
52-
size_t last_read_end;
5353
uv_tcp_t client;
5454
bool ws_mode;
5555
bool shutting_down;
@@ -64,12 +64,25 @@ int inspector_accept(uv_stream_t* server, struct inspector_socket_s* inspector,
6464
void inspector_close(struct inspector_socket_s* inspector,
6565
inspector_cb callback);
6666

67-
// Callbacks will receive handles that has inspector in data field...
67+
// Callbacks will receive stream handles. Use inspector_from_stream to get
68+
// inspector_socket_t* from the stream handle.
6869
int inspector_read_start(struct inspector_socket_s* inspector, uv_alloc_cb,
6970
uv_read_cb);
7071
void inspector_read_stop(struct inspector_socket_s* inspector);
7172
void inspector_write(struct inspector_socket_s* inspector,
7273
const char* data, size_t len);
7374
bool inspector_is_active(const struct inspector_socket_s* inspector);
7475

76+
inline inspector_socket_t* inspector_from_stream(uv_tcp_t* stream) {
77+
return node::ContainerOf(&inspector_socket_t::client, stream);
78+
}
79+
80+
inline inspector_socket_t* inspector_from_stream(uv_stream_t* stream) {
81+
return inspector_from_stream(reinterpret_cast<uv_tcp_t*>(stream));
82+
}
83+
84+
inline inspector_socket_t* inspector_from_stream(uv_handle_t* stream) {
85+
return inspector_from_stream(reinterpret_cast<uv_tcp_t*>(stream));
86+
}
87+
7588
#endif // SRC_INSPECTOR_SOCKET_H_

test/cctest/test_inspector_socket.cc

+4-6
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ struct expectations {
178178

179179
static void grow_expects_buffer(uv_handle_t* stream, size_t size, uv_buf_t* b) {
180180
expectations* expects = static_cast<expectations*>(
181-
(static_cast<inspector_socket_t*>(stream->data))->data);
181+
inspector_from_stream(stream)->data);
182182
size_t end = expects->actual_end;
183183
// Grow the buffer in chunks of 64k.
184184
size_t new_length = (end + size + 65535) & ~((size_t) 0xFFFF);
@@ -213,7 +213,7 @@ static void grow_expects_buffer(uv_handle_t* stream, size_t size, uv_buf_t* b) {
213213
static void save_read_data(uv_stream_t* stream, ssize_t nread,
214214
const uv_buf_t* buf) {
215215
expectations* expects =static_cast<expectations*>(
216-
(static_cast<inspector_socket_t*>(stream->data))->data);
216+
inspector_from_stream(stream)->data);
217217
expects->err_code = nread < 0 ? nread : 0;
218218
if (nread > 0) {
219219
expects->actual_end += nread;
@@ -254,8 +254,7 @@ static void expect_on_server(const char* data, size_t len) {
254254

255255
static void inspector_record_error_code(uv_stream_t* stream, ssize_t nread,
256256
const uv_buf_t* buf) {
257-
inspector_socket_t *inspector =
258-
reinterpret_cast<inspector_socket_t*>(stream->data);
257+
inspector_socket_t *inspector = inspector_from_stream(stream);
259258
// Increment instead of assign is to ensure the function is only called once
260259
*(static_cast<int *>(inspector->data)) += nread;
261260
}
@@ -760,8 +759,7 @@ static void CleanupSocketAfterEOF_close_cb(inspector_socket_t* inspector,
760759
static void CleanupSocketAfterEOF_read_cb(uv_stream_t* stream, ssize_t nread,
761760
const uv_buf_t* buf) {
762761
EXPECT_EQ(UV_EOF, nread);
763-
inspector_socket_t* insp =
764-
reinterpret_cast<inspector_socket_t*>(stream->data);
762+
inspector_socket_t* insp = inspector_from_stream(stream);
765763
inspector_close(insp, CleanupSocketAfterEOF_close_cb);
766764
}
767765

0 commit comments

Comments
 (0)