Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Container Overflow (ASAN) when using operator >> on an ifs #1873

Closed
Milerius opened this issue Dec 17, 2019 · 5 comments
Closed

Container Overflow (ASAN) when using operator >> on an ifs #1873

Milerius opened this issue Dec 17, 2019 · 5 comments

Comments

@Milerius
Copy link

Milerius commented Dec 17, 2019

  • What is the issue you have?

I got a Container Overflow (ASAN) when using operator >> on an input file stream (std::ifstream)

  • Please describe the steps to reproduce the issue. Can you provide a small but working code example?

  • What is the expected behavior?

No Report from ASAN is expected.

  • And what is the actual behavior instead?

ASAN Is blaming lexer.hpp code

AppleClang 11 OSX.

  • Did you use a released version of the library or the version from the develop branch?

I use nlohmann::json through Vcpkg.

(V 3.7.3)

There is the code that I use for load my json:

#pragma once

//! C System Headers
#include <cassert> ///< assert

//! C++ System Headers
#include <filesystem> ///< fs::create_directories, fs::path, fs::exists
#include <fstream> ///< std::ifstream, std::ofstream
#include <string> ///< std::string
#include <system_error> ///< std::error_code

//! Dependencies Headers
#include <nlohmann/json.hpp> ///< nlohmann::json

namespace antara::gaming::config {
    namespace details {
        

        template<typename TConfig>
        TConfig load_config(const std::filesystem::path &full_path) noexcept {
            TConfig config_to_fill{};
            std::ifstream ifs(full_path);
            assert(ifs.is_open());
            nlohmann::json config_json_data;
            ifs >> config_json_data; //< ASAN Complaining here
            config_to_fill = config_json_data;
            return config_to_fill;
        }
    }
}

Asan full report:

==45010==ERROR: AddressSanitizer: container-overflow on address 0x602000000b10 at pc 0x000102347f1b bp 0x7ffeeda2ef30 sp 0x7ffeeda2ef28
WRITE of size 1 at 0x602000000b10 thread T0
    #0 0x102347f1a in void std::__1::allocator<char>::construct<char, char>(char*, char&&) memory:1825
    #1 0x102347e3f in void std::__1::allocator_traits<std::__1::allocator<char> >::__construct<char, char>(std::__1::integral_constant<bool, true>, std::__1::allocator<char>&, char*, char&&) memory:1717
    #2 0x1023478a7 in void std::__1::allocator_traits<std::__1::allocator<char> >::construct<char, char>(std::__1::allocator<char>&, char*, char&&) memory:1560
    #3 0x1023475bc in std::__1::vector<char, std::__1::allocator<char> >::push_back(char&&) vector:1656
    #4 0x102342087 in nlohmann::detail::lexer<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::get() lexer.hpp:1264
    #5 0x102341579 in nlohmann::detail::lexer<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::scan() lexer.hpp:1422
    #6 0x102340665 in nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::get_token() parser.hpp:455
    #7 0x10234058c in nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parser(std::__1::shared_ptr<nlohmann::detail::input_adapter_protocol>&&, std::__1::function<bool (int, nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parse_event_t, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer>&)>, bool) parser.hpp:69
    #8 0x10233b88a in nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parser(std::__1::shared_ptr<nlohmann::detail::input_adapter_protocol>&&, std::__1::function<bool (int, nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parse_event_t, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer>&)>, bool) parser.hpp:67
    #9 0x10233185b in nlohmann::operator>>(std::__1::basic_istream<char, std::__1::char_traits<char> >&, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer>&) json.hpp:6356
    #10 0x1028744e0 in antara::gaming::graphics::canvas_2d antara::gaming::config::details::load_config<antara::gaming::graphics::canvas_2d>(std::__1::__fs::filesystem::path const&) config.loading.hpp:56
    #11 0x10286c33f in antara::gaming::graphics::canvas_2d antara::gaming::config::load_configuration<antara::gaming::graphics::canvas_2d>(std::__1::__fs::filesystem::path&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) config.loading.hpp:85
    #12 0x10286b324 in antara::gaming::world::app::app(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) world.app.cpp:41
    #13 0x1021ece00 in atomic_dex::application::application() atomic.dex.app.cpp:31
    #14 0x1021ef364 in atomic_dex::application::application() atomic.dex.app.cpp:32
    #15 0x1021e1df3 in main atomic.dex.desktop.cpp:51
    #16 0x7fff6c2e52e4 in start (libdyld.dylib:x86_64+0x112e4)

0x602000000b10 is located 0 bytes inside of 1-byte region [0x602000000b10,0x602000000b11)
allocated by thread T0 here:
    #0 0x103f137cd in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x517cd)
    #1 0x1021f854c in std::__1::__libcpp_allocate(unsigned long, unsigned long) new:253
    #2 0x102272697 in std::__1::allocator<char>::allocate(unsigned long, void const*) memory:1813
    #3 0x102272350 in std::__1::allocator_traits<std::__1::allocator<char> >::allocate(std::__1::allocator<char>&, unsigned long) memory:1546
    #4 0x102348a0f in std::__1::__split_buffer<char, std::__1::allocator<char>&>::__split_buffer(unsigned long, unsigned long, std::__1::allocator<char>&) __split_buffer:311
    #5 0x10234837c in std::__1::__split_buffer<char, std::__1::allocator<char>&>::__split_buffer(unsigned long, unsigned long, std::__1::allocator<char>&) __split_buffer:310
    #6 0x102347b36 in void std::__1::vector<char, std::__1::allocator<char> >::__push_back_slow_path<char>(char&&) vector:1622
    #7 0x102347673 in std::__1::vector<char, std::__1::allocator<char> >::push_back(char&&) vector:1663
    #8 0x102342087 in nlohmann::detail::lexer<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::get() lexer.hpp:1264
    #9 0x102341b0b in nlohmann::detail::lexer<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::skip_bom() lexer.hpp:1398
    #10 0x102341513 in nlohmann::detail::lexer<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::scan() lexer.hpp:1413
    #11 0x102340665 in nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::get_token() parser.hpp:455
    #12 0x10234058c in nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parser(std::__1::shared_ptr<nlohmann::detail::input_adapter_protocol>&&, std::__1::function<bool (int, nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parse_event_t, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer>&)>, bool) parser.hpp:69
    #13 0x10233b88a in nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parser(std::__1::shared_ptr<nlohmann::detail::input_adapter_protocol>&&, std::__1::function<bool (int, nlohmann::detail::parser<nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer> >::parse_event_t, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer>&)>, bool) parser.hpp:67
    #14 0x10233185b in nlohmann::operator>>(std::__1::basic_istream<char, std::__1::char_traits<char> >&, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::adl_serializer>&) json.hpp:6356
    #15 0x1028744e0 in antara::gaming::graphics::canvas_2d antara::gaming::config::details::load_config<antara::gaming::graphics::canvas_2d>(std::__1::__fs::filesystem::path const&) config.loading.hpp:56
    #16 0x10286c33f in antara::gaming::graphics::canvas_2d antara::gaming::config::load_configuration<antara::gaming::graphics::canvas_2d>(std::__1::__fs::filesystem::path&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) config.loading.hpp:85
    #17 0x10286b324 in antara::gaming::world::app::app(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) world.app.cpp:41
    #18 0x1021ece00 in atomic_dex::application::application() atomic.dex.app.cpp:31
    #19 0x1021ef364 in atomic_dex::application::application() atomic.dex.app.cpp:32
    #20 0x1021e1df3 in main atomic.dex.desktop.cpp:51
    #21 0x7fff6c2e52e4 in start (libdyld.dylib:x86_64+0x112e4)

HINT: if you don't care about these errors you may set ASAN_OPTIONS=detect_container_overflow=0.
If you suspect a false positive see also: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow.
SUMMARY: AddressSanitizer: container-overflow memory:1825 in void std::__1::allocator<char>::construct<char, char>(char*, char&&)
Shadow bytes around the buggy address:
  0x1c0400000110: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x1c0400000120: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x1c0400000130: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x1c0400000140: fa fa 00 00 fa fa 00 00 fa fa fd fa fa fa fd fd
  0x1c0400000150: fa fa 00 fa fa fa 04 fa fa fa 00 00 fa fa 00 00
=>0x1c0400000160: fa fa[fc]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0400000170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0400000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0400000190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c04000001a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c04000001b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==45010==ABORTING

There is the json config that I'm loading:

{
  "background_color": [
    0,
    0,
    0,
    255
  ],
  "canvas_height": 900.0,
  "canvas_width": 1280.0,
  "custom_canvas_height": true,
  "custom_canvas_width": true,
  "native_desktop_mode": false,
  "scale_mode": "fit",
  "window_height": 900.0,
  "window_title": "atomicDEX Desktop",
  "window_width": 1280.0,
  "no_style": false,
  "mouse_grabbed": false,
  "mouse_visible": true,
  "vsync": true
}

I want to clarify that I have unit tests that pass on this loading function, and no problem with asan.

https://github.com/KomodoPlatform/antara-gaming-sdk/blob/master/modules/config/antara/gaming/config/antara.config.loading.tests.cpp

@nlohmann
Copy link
Owner

That is weird. If I understand the documentation correctly, it means that a container is accessed between size and capacity. In the stack trace, however, this seems to be triggered by std::vector::push_back which seems to make no sense...

@Milerius
Copy link
Author

@nlohmann May be it's a false positive ?

@Milerius
Copy link
Author

Milerius commented Dec 18, 2019

If a part of the application is built with asan and another part is not instrumented, and both parts use e.g. instrumented std::vector, asan may report non-existent container overflow. This happens because instrumented and non-instrumented bits of std::vector, inlined and not, are mixed during linking, so you end up with incompletely instrumented std::vector.

@nlohmann
Copy link
Owner

Could you try compiling the whole app with ASAN?

@Milerius
Copy link
Author

Yeah it's working now @nlohmann

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants