From ef94f4ba3ca35d063807fff62a9766769d067202 Mon Sep 17 00:00:00 2001 From: Dmitry Bochkarev Date: Thu, 15 Dec 2016 18:09:10 +0500 Subject: [PATCH] Fix segmentations failure in error.c gumbo_caret_diagnostic_to_string Without this patch method find_last_newline returns value bigger than find_next_newline and in line `original_line.length = line_end - line_start;` overflow happens. Before changes newly added test failed with segmentation failure: ``` ./test-driver: line 107: 12171 Segmentation fault (core dumped) "$@" > $log_file 2>&1 ``` This slightly changed copy of code used in nokogumbo gem. [Link](https://github.com/rubys/nokogumbo/blob/8b4446847dea5c614759684ebcae4c580c47f4ad/ext/nokogumboc/nokogumbo.c#L230) --- Makefile.am | 3 ++- src/error.c | 2 +- tests/error.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 tests/error.cc diff --git a/Makefile.am b/Makefile.am index cb624591..b0cfc33c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,7 +93,8 @@ gumbo_test_SOURCES = \ tests/tokenizer.cc \ tests/test_utils.cc \ tests/utf8.cc \ - tests/vector.cc + tests/vector.cc \ + tests/error.cc gumbo_test_DEPENDENCIES = libgumbo.la gumbo_test_LDADD = libgumbo.la diff --git a/src/error.c b/src/error.c index 6b184ed4..3bf56aab 100644 --- a/src/error.c +++ b/src/error.c @@ -140,7 +140,7 @@ static const char* find_last_newline( // There may be an error at EOF, which would be a nul byte. assert(*c || c == error_location); } - return c == original_text ? c : c + 1; + return c == original_text || c == error_location ? c : c + 1; } // Finds the next newline in the original source buffer from a given byte diff --git a/tests/error.cc b/tests/error.cc new file mode 100644 index 00000000..879b26d3 --- /dev/null +++ b/tests/error.cc @@ -0,0 +1,41 @@ +#include "gumbo.h" +#include "parser.h" +#include "error.h" + +#include + +#include "gtest/gtest.h" +#include "test_utils.h" + +namespace { + +class GumboErrorTest : public ::testing::Test { + protected: + GumboErrorTest() {} + + virtual ~GumboErrorTest() { + + } +}; + +TEST_F(GumboErrorTest, NewlineAfterLessThanSymbol) { + const GumboOptions *options = &kGumboDefaultOptions; + const char *input = "<\n"; + size_t input_len = strlen(input); + GumboOutput *output = gumbo_parse_with_options(options, input, input_len); + GumboVector *errors = &output->errors; + GumboParser parser = { ._options = options }; + GumboStringBuffer msg; + + gumbo_string_buffer_init(&parser, &msg); + for (size_t i=0; i < errors->length; i++) { + GumboError *err = (GumboError *)errors->data[i]; + gumbo_string_buffer_clear(&parser, &msg); + gumbo_caret_diagnostic_to_string(&parser, err, input, &msg); + } + gumbo_string_buffer_destroy(&parser, &msg); + + gumbo_destroy_output(options, output); +} + +}