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

Example fails with address sanitizer #111

Closed
Peanhua opened this issue Jan 15, 2023 · 3 comments
Closed

Example fails with address sanitizer #111

Peanhua opened this issue Jan 15, 2023 · 3 comments

Comments

@Peanhua
Copy link

Peanhua commented Jan 15, 2023

The example taken from the front page fails with address sanitizer enabled. Error occurs with both g++ and clang++.

$ cat example.cc 
#include <glaze/glaze.hpp>

struct my_struct
{
  int i = 287;
  double d = 3.14;
  std::string hello = "Hello World";
  std::array<uint64_t, 3> arr = { 1, 2, 3 };
};

template <>
struct glz::meta<my_struct> {
   using T = my_struct;
   static constexpr auto value = object(
      "i", &T::i,
      "d", &T::d,
      "hello", &T::hello,
      "arr", &T::arr
   );
};

int main()
{
  std::string buffer = R"({"i":287,"d":3.14,"hello":"Hello World","arr":[1,2,3]})";
  auto s = glz::read_json<my_struct>(buffer);
}
$ g++ --version
g++ (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4)
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ clang++ --version
clang version 14.0.5 (Fedora 14.0.5-2.fc36)
Target: x86_64-redhat-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ g++ -std=c++20 -I /usr/local/include/glaze -fsanitize=address example.cc && ./a.out 
=================================================================
==3878334==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00000042d040 at pc 0x00000040521a bp 0x7ffcd7ec8540 sp 0x7ffcd7ec8538
READ of size 8 at 0x00000042d040 thread T0
    #0 0x405219 in glz::to_uint64(char const*, unsigned long) (/tmp/a.out+0x405219)
    #1 0x411fba in bool glz::string_cmp<std::basic_string_view<char, std::char_traits<char> > const&, std::basic_string_view<char, std::char_traits<char> >&>(std::basic_string_view<char, std::char_traits<char> > const&, std::basic_string_view<char, std::char_traits<char> >&) (/tmp/a.out+0x411fba)
    #2 0x40eda6 in decltype(auto) glz::detail::single_char_map<std::variant<int my_struct::*, double my_struct::*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > my_struct::*, std::array<unsigned long, 3ul> my_struct::*>, glz::detail::single_char_hash_desc{4ul, true, (unsigned char)1, (unsigned char)97, (unsigned char)105, true}>::at<std::basic_string_view<char, std::char_traits<char> >&>(std::basic_string_view<char, std::char_traits<char> >&) const (/tmp/a.out+0x40eda6)
    #3 0x40f5bd in void glz::detail::from_json<my_struct>::op<glz::opts{10u, false, true, true, false, false, false, (char)32, (unsigned char)3}, char*&, my_struct, glz::context&, char*&>(my_struct&, glz::context&, char*&, char*&) (/tmp/a.out+0x40f5bd)
    #4 0x40cdbc in void glz::detail::read<10u>::op<glz::opts{10u, false, true, true, false, false, false, (char)32, (unsigned char)3}, my_struct&, glz::context&, char*&, char*&>(my_struct&, glz::context&, char*&, char*&) (/tmp/a.out+0x40cdbc)
    #5 0x409d8b in void glz::read<glz::opts{10u, false, true, true, false, false, false, (char)32, (unsigned char)3}, my_struct, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, glz::context&>(my_struct&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, glz::context&) (/tmp/a.out+0x409d8b)
    #6 0x407586 in auto glz::read_json<my_struct, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (/tmp/a.out+0x407586)
    #7 0x404703 in main (/tmp/a.out+0x404703)
    #8 0x7f2fa982950f in __libc_start_call_main (/lib64/libc.so.6+0x2950f)
    #9 0x7f2fa98295c8 in __libc_start_main_impl (/lib64/libc.so.6+0x295c8)
    #10 0x4044b4 in _start (/tmp/a.out+0x4044b4)

0x00000042d042 is located 0 bytes to the right of global variable '*.LC55' defined in 'example.cc' (0x42d040) of size 2
  '*.LC55' is ascii string 'i'
SUMMARY: AddressSanitizer: global-buffer-overflow (/tmp/a.out+0x405219) in glz::to_uint64(char const*, unsigned long)
Shadow bytes around the buggy address:
  0x00008007d9b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00008007d9c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00008007d9d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00008007d9e0: 00 00 00 00 00 00 06 f9 f9 f9 f9 f9 00 00 00 00
  0x00008007d9f0: 00 00 00 00 00 00 00 00 00 00 01 f9 f9 f9 f9 f9
=>0x00008007da00: 00 00 f9 f9 f9 f9 f9 f9[02]f9 f9 f9 f9 f9 f9 f9
  0x00008007da10: 02 f9 f9 f9 f9 f9 f9 f9 06 f9 f9 f9 f9 f9 f9 f9
  0x00008007da20: 04 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
  0x00008007da30: 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9
  0x00008007da40: 00 04 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
  0x00008007da50: 00 00 00 00 00 03 f9 f9 f9 f9 f9 f9 00 00 00 00
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
==3878334==ABORTING
$ 

Version used:

$ git rev-parse HEAD
99ce9aa2649585541c499faff8b2b81b9599c227

Also the version number in CMakeLists.txt does not seem to be correct (0.2.4), both in main branch and the latest release, which is labeled 0.2.9.

@stephenberry
Copy link
Owner

Thanks, right now we're checking page boundaries and only reading and discarding, but it makes sense that the address sanitizer fails. But, this wouldn't work on all platforms and we really should ensure that address sanitizers don't error, so we'll be changing the codebase to fix this. The code currently is written as it is for performance reasons to operate on 64 bit chunks of data. But, since the object keys are known at compile time we should be able to get even better performance and not have address sanitizer or buffer read issues.

Thanks for pointing this out, and the version number discontinuity.

@stephenberry
Copy link
Owner

#112 addresses the string comparison and hashing use of undefined behavior. There is still undefined behavior that breaks the address sanitizer in the floating point number conversion, which has yet to be addressed.

@stephenberry
Copy link
Owner

#120 addresses the rest of the address sanitizer issues. So, the code now passes the address sanitizer checks. These changes also remove undefined behavior, using std::memcpy rather than reinterpret_cast.

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

No branches or pull requests

2 participants