https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120915

            Bug ID: 120915
           Summary: Possible -fsanitize=pointer-subtract false positive
           Product: gcc
           Version: 15.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: christian.morales.vega at gmail dot com
  Target Milestone: ---

Using Boost 1.88, using this simple code

```
#include <boost/json/src.hpp>

int main() {
  const auto payload = boost::json::serialize(boost::json::object{{"field",
"value"}});
}
```

built with

`g++ -g -o test test.cpp -I boost_1_88_0 -fsanitize=address
-fsanitize=pointer-subtract`

and run as

`ASAN_OPTIONS="detect_invalid_pointer_pairs=1" ./test`

you get

```
$ ASAN_OPTIONS="detect_invalid_pointer_pairs=1" ./test 
=================================================================
==20812==ERROR: AddressSanitizer: invalid-pointer-pair: 0x7998dc601040
0x7998dc600042
    #0 0x000000435ac5 in boost::json::detail::stream::remain() const
boost_1_88_0/boost/json/detail/stream.hpp:265
    #1 0x000000449789 in bool
boost::json::detail::do_write_string<true>(boost::json::detail::writer&,
boost::json::detail::stream&) boost_1_88_0/boost/json/impl/serializer.ipp:228
    #2 0x000000414960 in
boost::json::detail::write_string(boost::json::detail::writer&,
boost::json::detail::stream&) boost_1_88_0/boost/json/impl/serializer.ipp:348
    #3 0x00000044c86c in bool
boost::json::detail::write_impl<boost::json::object,
true>(boost::json::detail::map_like_conversion_tag,
boost::json::detail::writer&, boost::json::detail::stream&)
boost_1_88_0/boost/json/impl/serializer.hpp:336
    #4 0x00000044c86c in bool
boost::json::detail::write_object<true>(boost::json::detail::writer&,
boost::json::detail::stream&) boost_1_88_0/boost/json/impl/serializer.ipp:380
    #5 0x000000415678 in boost::json::serializer::read(char*, unsigned long)
boost_1_88_0/boost/json/impl/serializer.ipp:548
    #6 0x000000447e03 in boost::core::basic_string_view<char>
boost::json::serializer::read<4096ul>(char (&) [4096ul])
boost_1_88_0/boost/json/serializer.hpp:292
    #7 0x000000412b67 in
boost::json::detail::serialize_impl(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, boost::json::serializer&)
boost_1_88_0/boost/json/impl/serialize.ipp:64
    #8 0x000000413417 in boost::json::serialize[abi:cxx11](boost::json::object
const&, boost::json::serialize_options const&)
boost_1_88_0/boost/json/impl/serialize.ipp:147
    #9 0x0000004272be in main /test/test.cpp:5
    #10 0x7d98de2ae5f4 in __libc_start_call_main (/lib64/libc.so.6+0x35f4)
(BuildId: 7504db94dbf054e06eaac49950f57161c601f5c6)
    #11 0x7d98de2ae6a7 in __libc_start_main@@GLIBC_2.34
(/lib64/libc.so.6+0x36a7) (BuildId: 7504db94dbf054e06eaac49950f57161c601f5c6)
    #12 0x0000004009b4 in _start (/test/test+0x4009b4) (BuildId:
c19e3884d2a136258e826e7c13e90e801896f155)

Address 0x7998dc601040 is located in stack of thread T0 at offset 4160 in frame
    #0 0x000000412a22 in
boost::json::detail::serialize_impl(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, boost::json::serializer&)
boost_1_88_0/boost/json/impl/serialize.ipp:59

  This frame has 2 object(s):
    [32, 48) 'sv' (line 63)
    [64, 4160) 'buf' (line 62) <== Memory access at offset 4160 overflows this
variable
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Address 0x7998dc600042 is located in stack of thread T0 at offset 66 in frame
    #0 0x000000412a22 in
boost::json::detail::serialize_impl(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, boost::json::serializer&)
boost_1_88_0/boost/json/impl/serialize.ipp:59

  This frame has 2 object(s):
    [32, 48) 'sv' (line 63)
    [64, 4160) 'buf' (line 62) <== Memory access at offset 66 is inside this
variable
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: invalid-pointer-pair
boost_1_88_0/boost/json/detail/stream.hpp:265 in
boost::json::detail::stream::remain() const
==20812==ABORTING
```

When using clang++ you get a similar
```
bash-5.2# ASAN_OPTIONS="detect_invalid_pointer_pairs=1" ./test
=================================================================
==16667==ERROR: AddressSanitizer: invalid-pointer-pair: 0x7a4a68801020
0x7a4a68800022
    #0 0x000000535cca in boost::json::detail::stream::remain() const
/test/boost_1_88_0/boost/json/detail/stream.hpp:265:21
    #1 0x000000523083 in bool
boost::json::detail::do_write_string<true>(boost::json::detail::writer&,
boost::json::detail::stream&)
/test/boost_1_88_0/boost/json/impl/serializer.ipp:228:19
    #2 0x0000005036ec in
boost::json::detail::write_string(boost::json::detail::writer&,
boost::json::detail::stream&)
/test/boost_1_88_0/boost/json/impl/serializer.ipp:348:12
    #3 0x0000005263cb in bool
boost::json::detail::write_impl<boost::json::object,
true>(boost::json::detail::map_like_conversion_tag,
boost::json::detail::writer&, boost::json::detail::stream&)
/test/boost_1_88_0/boost/json/impl/serializer.hpp:336:16
    #4 0x0000005263cb in bool
boost::json::detail::write_object<true>(boost::json::detail::writer&,
boost::json::detail::stream&)
/test/boost_1_88_0/boost/json/impl/serializer.ipp:380:12
    #5 0x00000050048c in boost::json::serializer::read(char*, unsigned long)
/test/boost_1_88_0/boost/json/impl/serializer.ipp:548:9
    #6 0x000000520cd1 in boost::core::basic_string_view<char>
boost::json::serializer::read<4096ul>(char (&) [4096ul])
/test/boost_1_88_0/boost/json/serializer.hpp:292:16
    #7 0x0000004ffff7 in
boost::json::detail::serialize_impl(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char>>&, boost::json::serializer&)
/test/boost_1_88_0/boost/json/impl/serialize.ipp:64:13
    #8 0x000000501208 in boost::json::serialize[abi:cxx11](boost::json::object
const&, boost::json::serialize_options const&)
/test/boost_1_88_0/boost/json/impl/serialize.ipp:147:5
    #9 0x0000005160c4 in main /test/test.cpp:5:7
    #10 0x7e4a6a1d75f4 in __libc_start_call_main (/lib64/libc.so.6+0x35f4)
(BuildId: 7504db94dbf054e06eaac49950f57161c601f5c6)
    #11 0x7e4a6a1d76a7 in __libc_start_main@GLIBC_2.2.5
(/lib64/libc.so.6+0x36a7) (BuildId: 7504db94dbf054e06eaac49950f57161c601f5c6)
    #12 0x000000400b84 in _start (/test/test+0x400b84) (BuildId:
28faa094e25175e27e52d2c74ae0f585a02ece4d)

Address 0x7a4a68801020 is located in stack of thread T0 at offset 4128 in frame
    #0 0x0000004ffebf in
boost::json::detail::serialize_impl(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char>>&, boost::json::serializer&)
/test/boost_1_88_0/boost/json/impl/serialize.ipp:59

  This frame has 2 object(s):
    [32, 4128) 'buf' (line 62) <== Memory access at offset 4128 overflows this
variable
    [4256, 4272) 'sv' (line 63)
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Address 0x7a4a68800022 is located in stack of thread T0 at offset 34 in frame
    #0 0x0000004ffebf in
boost::json::detail::serialize_impl(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char>>&, boost::json::serializer&)
/test/boost_1_88_0/boost/json/impl/serialize.ipp:59

  This frame has 2 object(s):
    [32, 4128) 'buf' (line 62) <== Memory access at offset 34 is inside this
variable
    [4256, 4272) 'sv' (line 63)
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: invalid-pointer-pair
/test/boost_1_88_0/boost/json/detail/stream.hpp:265:21 in
boost::json::detail::stream::remain() const
==16667==ABORTING
```

(I'm reporting it here because of
https://github.com/google/sanitizers/issues/1860#issuecomment-2999555091)

The Boost.JSON author thinks this is actually a bug in the sanitizer:
https://github.com/boostorg/json/issues/1090#issuecomment-3022073666


The issue the sanitizer complains about seems to be just a simple function in a
string_view like class. In
https://github.com/boostorg/json/blob/boost-1.88.0/include/boost/json/detail/stream.hpp#L265,
it's using "one after the buffer". With "end" having been initialized to data +
size in
https://github.com/boostorg/json/blob/boost-1.88.0/include/boost/json/detail/stream.hpp#L251.

The object was created in
https://github.com/boostorg/json/blob/boost-1.88.0/include/boost/json/impl/serializer.ipp#L546
, via
https://github.com/boostorg/json/blob/boost-1.88.0/include/boost/json/serializer.hpp#L290
, from this array:
https://github.com/boostorg/json/blob/boost-1.88.0/include/boost/json/impl/serialize.ipp#L62.
So nothing special here.

The array would have been 4096 bytes long:
https://github.com/boostorg/json/blob/boost-1.88.0/include/boost/json/detail/config.hpp#L141
  • [Bug analyzer/120915]... christian.morales.vega at gmail dot com via Gcc-bugs

Reply via email to