From 5b35c1a74e64f1b33cc18db43b1a7bbf842a619a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 19 Dec 2019 22:02:17 +0900 Subject: [PATCH 1/7] fix: prohibit modification on inline table According to toml-lang/toml:36d3091b3 "Clarify that inline tables are immutable", check if it adds key-value pair to an inline table. This is one of the unreleased (after-0.5.0) toml feature. But this is marked as "Clarify", so TOML-lang intended that inline tables are immutable in all version. --- toml/parser.hpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 9e511ad..1ea650f 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -1331,7 +1331,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, tab->insert(std::make_pair(k, v)); return ok(true); } - else + else // k is not the last one, we should insert recursively { // if there is no corresponding value, insert it first. // related: you don't need to write @@ -1347,6 +1347,27 @@ insert_nested_key(typename Value::table_type& root, const Value& v, // type checking... if(tab->at(k).is_table()) { + // According to toml-lang/toml:36d3091b3 "Clarify that inline + // tables are immutable", check if it adds key-value pair to an + // inline table. + // This is one of the unreleased (after-0.5.0) toml feature. + // But this is marked as "Clarify", so TOML-lang intended that + // inline tables are immutable in all version. + { + // here, if the value is a (multi-line) table, the region + // should be something like `[table-name]`. + if(get_region(tab->at(k)).str().front() == '{') + { + throw syntax_error(format_underline(concat_to_string( + "toml::insert_value: inserting to an inline table (", + format_dotted_keys(first, std::next(iter)), + ") but inline tables are immutable"), { + {std::addressof(get_region(tab->at(k))), + "inline tables are immutable"}, + {std::addressof(get_region(v)), "inserting this"} + }), v.location()); + } + } tab = std::addressof((*tab)[k].as_table()); } else if(tab->at(k).is_array()) // inserting to array-of-tables? From c199bd8b49c078b1f5f21c2216ecb619b413a7b7 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 19 Dec 2019 22:07:50 +0900 Subject: [PATCH 2/7] feat: enable to access the 1st char of region --- toml/region.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toml/region.hpp b/toml/region.hpp index 973bf48..bf9ba12 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -41,6 +41,7 @@ struct region_base region_base& operator=(region_base&& ) = default; virtual bool is_ok() const noexcept {return false;} + virtual char front() const noexcept {return '\0';} virtual std::string str() const {return std::string("unknown region");} virtual std::string name() const {return std::string("unknown file");} @@ -89,6 +90,7 @@ struct location final : public region_base ~location() = default; bool is_ok() const noexcept override {return static_cast(source_);} + char front() const noexcept override {return *iter_;} // this const prohibits codes like `++(loc.iter())`. const const_iterator iter() const noexcept {return iter_;} @@ -240,6 +242,7 @@ struct region final : public region_base } bool is_ok() const noexcept override {return static_cast(source_);} + char front() const noexcept override {return *first_;} std::string str() const override {return make_string(first_, last_);} std::string line() const override From 18f84088b4703f7042cd9f17e53e56300075b054 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 19 Dec 2019 22:13:47 +0900 Subject: [PATCH 3/7] perf: avoid tmp str construction while checking --- toml/parser.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 1ea650f..7cf644a 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -1356,7 +1356,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, { // here, if the value is a (multi-line) table, the region // should be something like `[table-name]`. - if(get_region(tab->at(k)).str().front() == '{') + if(get_region(tab->at(k)).front() == '{') { throw syntax_error(format_underline(concat_to_string( "toml::insert_value: inserting to an inline table (", From b1827e6fca5e0f26cc486390fc3672717c4d52a7 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 20 Dec 2019 19:34:02 +0900 Subject: [PATCH 4/7] test: check immutability of inline tables --- tests/test_parse_inline_table.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_parse_inline_table.cpp b/tests/test_parse_inline_table.cpp index e1934a5..5fa99c1 100644 --- a/tests/test_parse_inline_table.cpp +++ b/tests/test_parse_inline_table.cpp @@ -46,3 +46,19 @@ BOOST_AUTO_TEST_CASE(test_inline_table_value) TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "{type.name = \"pug\"}", value(t)); } } + +BOOST_AUTO_TEST_CASE(test_inline_table_immutability) +{ + { + std::istringstream stream(std::string( + "a = {b = 1}\n" + "a.c = 2\n")); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); + } + { + std::istringstream stream(std::string( + "a = {b = {c = 1}}\n" + "a.b.d = 2\n")); + BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error); + } +} From a0c5192b7441156b2a983540b1ab590e7cc3776b Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 8 Jan 2020 23:07:05 +0900 Subject: [PATCH 5/7] chore: add option to use sanitizers --- CMakeLists.txt | 2 ++ tests/CMakeLists.txt | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0315eb..f75ffcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ set(toml11_VERSION ) option(toml11_BUILD_TEST "Build toml tests" ON) +option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF) +option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF) include(CheckCXXCompilerFlag) if("${CMAKE_VERSION}" VERSION_GREATER 3.1) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e527e04..8570aeb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -104,6 +104,19 @@ foreach(TEST_NAME ${TEST_NAMES}) add_executable(${TEST_NAME} ${TEST_NAME}.cpp) target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11) target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS}) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if(toml11_TEST_WITH_ASAN) + set_target_properties(${TEST_NAME} PROPERTIES + COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer" + LINK_FLAGS "-fsanitize=address -fno-omit-frame-pointer") + elseif(toml11_TEST_WITH_UBSAN) + set_target_properties(${TEST_NAME} PROPERTIES + COMPILE_FLAGS "-fsanitize=undefined" + LINK_FLAGS "-fsanitize=undefined") + endif() + endif() + add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) # Set the PATH to be able to find Boost DLL From 1f90af8e67b7d6de340a1e0d57fa07098f186124 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 8 Jan 2020 23:17:38 +0900 Subject: [PATCH 6/7] ci: refactor list of env vars --- .travis.yml | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3542fc3..4350eab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: - os: linux language: cpp compiler: gcc - env: COMPILER="g++-5" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="g++-5" CXX_STANDARD=11 addons: apt: sources: @@ -17,7 +17,7 @@ matrix: - os: linux language: cpp compiler: gcc - env: COMPILER="g++-6" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="g++-6" CXX_STANDARD=11 addons: apt: sources: @@ -29,7 +29,7 @@ matrix: - os: linux language: cpp compiler: gcc - env: COMPILER="g++-7" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="g++-7" CXX_STANDARD=11 addons: apt: sources: @@ -41,7 +41,7 @@ matrix: - os: linux language: cpp compiler: gcc - env: COMPILER="g++-8" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="g++-8" CXX_STANDARD=11 addons: apt: sources: @@ -65,7 +65,7 @@ matrix: - os: linux language: cpp compiler: gcc - env: COMPILER="g++-8" CXX_STANDARD=17 TOML_HEAD=OFF + env: COMPILER="g++-8" CXX_STANDARD=17 addons: apt: sources: @@ -89,7 +89,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="clang++-3.9" CXX_STANDARD=11 addons: apt: sources: @@ -103,7 +103,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-4.0" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="clang++-4.0" CXX_STANDARD=11 addons: apt: sources: @@ -117,7 +117,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-5.0" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="clang++-5.0" CXX_STANDARD=11 addons: apt: sources: @@ -131,7 +131,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-6.0" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="clang++-6.0" CXX_STANDARD=11 addons: apt: sources: @@ -145,7 +145,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-7" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="clang++-7" CXX_STANDARD=11 addons: apt: sources: @@ -159,7 +159,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=OFF + env: COMPILER="clang++-8" CXX_STANDARD=11 addons: apt: sources: @@ -187,7 +187,7 @@ matrix: - os: linux language: cpp compiler: clang - env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=OFF + env: COMPILER="clang++-8" CXX_STANDARD=17 addons: apt: sources: @@ -234,6 +234,11 @@ script: tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1 export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH} fi +- | + if [[ "${TOML_HEAD}" != "ON" ]]; then + export TOML_HEAD="OFF" + fi +- echo "TOML_HEAD = ${TOML_HEAD}" - cmake --version - mkdir build - cd build From c153c0e8c3ff17ac71fa429531a2f0f7272a10b6 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 8 Jan 2020 23:28:17 +0900 Subject: [PATCH 7/7] ci: test with sanitizers --- .travis.yml | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4350eab..5ff0c21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -212,6 +212,34 @@ matrix: - clang-8 - g++-8 - boost1.70 + - os: linux + language: cpp + compiler: clang + env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_ASAN=ON + addons: + apt: + sources: + - sourceline: 'ppa:ubuntu-toolchain-r/test' + - sourceline: 'ppa:mhier/libboost-latest' + - llvm-toolchain-trusty-8 + packages: + - clang-8 + - g++-8 + - boost1.70 + - os: linux + language: cpp + compiler: clang + env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_UBSAN=ON + addons: + apt: + sources: + - sourceline: 'ppa:ubuntu-toolchain-r/test' + - sourceline: 'ppa:mhier/libboost-latest' + - llvm-toolchain-trusty-8 + packages: + - clang-8 + - g++-8 + - boost1.70 - os: osx language: cpp compiler: clang @@ -239,11 +267,21 @@ script: export TOML_HEAD="OFF" fi - echo "TOML_HEAD = ${TOML_HEAD}" +- | + if [[ "${WITH_ASAN}" != "ON" ]]; then + export WITH_ASAN="OFF" + fi +- echo "WITH_ASAN = ${WITH_ASAN}" +- | + if [[ "${WITH_UBSAN}" != "ON" ]]; then + export WITH_UBSAN="OFF" + fi +- echo "WITH_UBSAN = ${WITH_UBSAN}" - cmake --version - mkdir build - cd build - git clone https://github.com/toml-lang/toml.git -- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} .. +- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} -Dtoml11_TEST_WITH_ASAN=${WITH_ASAN} -Dtoml11_TEST_WITH_UBSAN=${WITH_UBSAN} .. - make - ctest --output-on-failure