diff --git a/.travis.yml b/.travis.yml index 006647edf..6bf2297e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,14 +42,20 @@ matrix: - make check TEST_PREFIX="valgrind --error-exitcode=1 --leak-check=full " TEST_PATTERN="" # cLang sanitizer - - #- os: linux - # env: - # - LLVM_VERSION=3.8.1 - # - SPECIAL=sanitizer - # compiler: clang - # before_script: - # - make clang_sanitize + # note: sadly clang's libc++ has errors when running with sanitize, + # so we use clang with gcc's libstdc++ which doesn't give those error. + # that's why we need to install g++-6 to get the lastest version + - os: linux + env: + - LLVM_VERSION=3.8.1 + - SPECIAL=sanitizer + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: g++-6 + compiler: clang + before_script: + - make clang_sanitize # cppcheck diff --git a/Makefile b/Makefile index e2c120dbd..c16d9d9b1 100644 --- a/Makefile +++ b/Makefile @@ -92,8 +92,9 @@ fuzzing-stop: cppcheck: cppcheck --enable=warning --inconclusive --force --std=c++11 src/json.hpp --error-exitcode=1 +# run clang sanitize (we are overrding the CXXFLAGS provided by travis in order to use gcc's libstdc++) clang_sanitize: clean - CXX=clang++ CXXFLAGS="-g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer" $(MAKE) + CXX=clang++ CXXFLAGS="-g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer" $(MAKE) check -C test ########################################################################## diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 25fd33497..c439c1c3e 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -111,6 +111,16 @@ struct my_allocator : std::allocator } }; +// allows deletion of raw pointer, usually hold by json_value +template +void my_allocator_clean_up(T* p) +{ + assert(p != nullptr); + my_allocator alloc; + alloc.destroy(p); + alloc.deallocate(p, 1); +} + TEST_CASE("controlled bad_alloc") { // create JSON type using the throwing allocator @@ -131,7 +141,8 @@ TEST_CASE("controlled bad_alloc") { next_construct_fails = false; auto t = my_json::value_t::object; - CHECK_NOTHROW(my_json::json_value j(t)); + auto clean_up = [](my_json::json_value& j){ my_allocator_clean_up(j.object); }; + CHECK_NOTHROW(my_json::json_value j(t); clean_up(j)); next_construct_fails = true; CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc); next_construct_fails = false; @@ -140,7 +151,8 @@ TEST_CASE("controlled bad_alloc") { next_construct_fails = false; auto t = my_json::value_t::array; - CHECK_NOTHROW(my_json::json_value j(t)); + auto clean_up = [](my_json::json_value& j){ my_allocator_clean_up(j.array); }; + CHECK_NOTHROW(my_json::json_value j(t); clean_up(j)); next_construct_fails = true; CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc); next_construct_fails = false; @@ -149,7 +161,8 @@ TEST_CASE("controlled bad_alloc") { next_construct_fails = false; auto t = my_json::value_t::string; - CHECK_NOTHROW(my_json::json_value j(t)); + auto clean_up = [](my_json::json_value& j){ my_allocator_clean_up(j.string); }; + CHECK_NOTHROW(my_json::json_value j(t); clean_up(j)); next_construct_fails = true; CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc); next_construct_fails = false; @@ -160,7 +173,8 @@ TEST_CASE("controlled bad_alloc") { next_construct_fails = false; my_json::string_t v("foo"); - CHECK_NOTHROW(my_json::json_value j(v)); + auto clean_up = [](my_json::json_value& j){ my_allocator_clean_up(j.string); }; + CHECK_NOTHROW(my_json::json_value j(v); clean_up(j)); next_construct_fails = true; CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); next_construct_fails = false;