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

Side by Side Diff: base/json/json_parser_unittest.cc

Issue 2859513002: Fix potential buffer over-read errors for un-terminated JSON strings and comments. (Closed)
Patch Set: Address comments Created 3 years, 7 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/json/json_parser.h" 5 #include "base/json/json_parser.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
(...skipping 10 matching lines...) Expand all
21 public: 21 public:
22 JSONParser* NewTestParser(const std::string& input, 22 JSONParser* NewTestParser(const std::string& input,
23 int options = JSON_PARSE_RFC) { 23 int options = JSON_PARSE_RFC) {
24 JSONParser* parser = new JSONParser(options); 24 JSONParser* parser = new JSONParser(options);
25 parser->start_pos_ = input.data(); 25 parser->start_pos_ = input.data();
26 parser->pos_ = parser->start_pos_; 26 parser->pos_ = parser->start_pos_;
27 parser->end_pos_ = parser->start_pos_ + input.length(); 27 parser->end_pos_ = parser->start_pos_ + input.length();
28 return parser; 28 return parser;
29 } 29 }
30 30
31 // MSan will do a better job detecting over-read errors if the input is
32 // not nul-terminated on the heap. This will copy |input| to a new buffer
33 // owned by |owner|, returning a StringPiece to |owner|.
34 StringPiece MakeNotNullTerminatedInput(const char* input,
35 std::unique_ptr<char[]>* owner) {
36 size_t str_len = strlen(input);
37 owner->reset(new char[str_len]);
38 memcpy(owner->get(), input, str_len);
39 return StringPiece(owner->get(), str_len);
40 }
41
31 void TestLastThree(JSONParser* parser) { 42 void TestLastThree(JSONParser* parser) {
32 EXPECT_EQ(',', *parser->NextChar()); 43 EXPECT_EQ(',', *parser->NextChar());
33 EXPECT_EQ('|', *parser->NextChar()); 44 EXPECT_EQ('|', *parser->NextChar());
34 EXPECT_EQ('\0', *parser->NextChar()); 45 EXPECT_EQ('\0', *parser->NextChar());
35 EXPECT_EQ(parser->end_pos_, parser->pos_); 46 EXPECT_EQ(parser->end_pos_, parser->pos_);
36 } 47 }
37 }; 48 };
38 49
39 TEST_F(JSONParserTest, NextChar) { 50 TEST_F(JSONParserTest, NextChar) {
40 std::string input("Hello world"); 51 std::string input("Hello world");
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 {"9e-3", true, 0.009}, 371 {"9e-3", true, 0.009},
361 {"2e+", false, 0}, 372 {"2e+", false, 0},
362 {"2e+2", true, 200}, 373 {"2e+2", true, 200},
363 // clang-format on 374 // clang-format on
364 }; 375 };
365 376
366 for (unsigned int i = 0; i < arraysize(kCases); ++i) { 377 for (unsigned int i = 0; i < arraysize(kCases); ++i) {
367 auto test_case = kCases[i]; 378 auto test_case = kCases[i];
368 SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case.input)); 379 SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case.input));
369 380
370 // MSan will do a better job detecting over-read errors if the input is 381 std::unique_ptr<char[]> input_owner;
371 // not nul-terminated on the heap. 382 StringPiece input =
372 size_t str_len = strlen(test_case.input); 383 MakeNotNullTerminatedInput(test_case.input, &input_owner);
373 auto non_nul_termianted = MakeUnique<char[]>(str_len);
374 memcpy(non_nul_termianted.get(), test_case.input, str_len);
375 384
376 StringPiece string_piece(non_nul_termianted.get(), str_len); 385 std::unique_ptr<Value> result = JSONReader::Read(input);
377 std::unique_ptr<Value> result = JSONReader::Read(string_piece);
378 if (test_case.parse_success) { 386 if (test_case.parse_success) {
379 EXPECT_TRUE(result); 387 EXPECT_TRUE(result);
380 } else { 388 } else {
381 EXPECT_FALSE(result); 389 EXPECT_FALSE(result);
382 } 390 }
383 391
384 if (!result) 392 if (!result)
385 continue; 393 continue;
386 394
387 double double_value = 0; 395 double double_value = 0;
388 EXPECT_TRUE(result->GetAsDouble(&double_value)); 396 EXPECT_TRUE(result->GetAsDouble(&double_value));
389 EXPECT_EQ(test_case.value, double_value); 397 EXPECT_EQ(test_case.value, double_value);
390 } 398 }
391 } 399 }
392 400
401 TEST_F(JSONParserTest, UnterminatedInputs) {
402 const char* kCases[] = {
403 // clang-format off
404 "/",
405 "//",
406 "/*",
407 "\"xxxxxx",
408 "\"",
409 "{ ",
410 "[\t",
411 "tru",
412 "fals",
413 "nul",
414 "\"\\x2",
415 "\"\\u123",
416 // clang-format on
417 };
418
419 for (unsigned int i = 0; i < arraysize(kCases); ++i) {
brettw 2017/05/09 19:53:14 Random optional thought: Does C++11 let you do:
Robert Sesek 2017/05/09 21:27:36 The |for (:)| construct does work, but I use |i| i
420 auto* test_case = kCases[i];
421 SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case));
422
423 std::unique_ptr<char[]> input_owner;
424 StringPiece input = MakeNotNullTerminatedInput(test_case, &input_owner);
425
426 EXPECT_FALSE(JSONReader::Read(input));
427 }
428 }
429
393 } // namespace internal 430 } // namespace internal
394 } // namespace base 431 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698