serdepp icon indicating copy to clipboard operation
serdepp copied to clipboard

Infinite recursion with operator<<

Open seingierf opened this issue 2 years ago • 3 comments

Hello!

I noticed a crash when printing to stdout just by including <serdepp/serde.hpp>:

#include <iostream>
#include <serdepp/serde.hpp>

int main(int argc, char* argv[]) {
    if (argc > 1) {
        std::cout << argv[1] << std::endl;
    }
    return 0;
}

gcc emits the following warning:

In file included from ../include/serdepp/serde.hpp:8,
                 from ../test.cc:2:
../include/serdepp/ostream.hpp: In function ‘std::basic_ostream<_CharT, _Traits>& serde::ostream::operator<<(std::basic_ostream<_CharT, _Traits>&, const T&) [with CharT = char; Traits = std::char_traits<char>; T
 = char*]’:
../include/serdepp/ostream.hpp:18:40: warning: infinite recursion detected [-Winfinite-recursion]
   18 |     std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT,Traits>& os, const T& x) {
      |                                        ^~~~~~~~
../include/serdepp/ostream.hpp:22:23: note: recursive call
   22 |             return os << x;
      |                    ~~~^~~~

which, by reading the code, is exactly what happens at runtime in my example, hence the crash.

seingierf avatar Dec 26 '23 21:12 seingierf

Could you provide additional information about the environment in which you built it?

injae avatar Dec 28 '23 05:12 injae

My source layout is the following:

.
├── include
│   ├── magic_enum.hpp
│   ├── magic_enum_all.hpp
│   ├── magic_enum_containers.hpp
│   ├── magic_enum_flags.hpp
│   ├── magic_enum_format.hpp
│   ├── magic_enum_fuse.hpp
│   ├── magic_enum_iostream.hpp
│   ├── magic_enum_switch.hpp
│   ├── magic_enum_utility.hpp
│   ├── nameof.hpp
│   └── serdepp
│       ├── adaptor
│       │   ├── fmt.hpp
│       │   ├── nlohmann_json.hpp
│       │   ├── rapidjson.hpp
│       │   ├── reflection.hpp
│       │   ├── sstream.hpp
│       │   ├── toml11.hpp
│       │   └── yaml-cpp.hpp
│       ├── attribute
│       │   ├── algorithm.hpp
│       │   ├── default.hpp
│       │   ├── flatten.hpp
│       │   ├── make_optional.hpp
│       │   ├── meta.hpp
│       │   ├── mutli_key.hpp
│       │   ├── skip.hpp
│       │   ├── string_convert.hpp
│       │   └── value_or_struct.hpp
│       ├── attributes.hpp
│       ├── exception.hpp
│       ├── meta.hpp
│       ├── ostream.hpp
│       ├── serde.hpp
│       ├── serializer.hpp
│       └── utility.hpp
├── meson.build
└── test.cc

I am using the main branch of serdepp (commit 2682b8d586a8c07a7826211ea66087ac841bbc12), magic_enum 0.9.5 and nameof 0.10.3.

g++ version:

g++ (Ubuntu 13.1.0-8ubuntu1~22.04) 13.1.0

g++ commands invoked by ninja:

c++ -ITest.p -I. -I.. -I../include -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++23 -O0 -g -MD -MQ Test.p/test.cc.o -MF Test.p/test.cc.o.d -o Test.p/test.cc.o -c ../test.cc
c++  -o Test Test.p/test.cc.o -Wl,--as-needed -Wl,--no-undefined

seingierf avatar Dec 28 '23 09:12 seingierf

It seems to be a bug in serdepp. It looks like we need to implement it in a different way than the current approach in ostream.hpp.

If you want to use it before I patch the bug, you can comment out the following section in the code:

https://github.com/injae/serdepp/blob/2682b8d586a8c07a7826211ea66087ac841bbc12/include/serdepp/serde.hpp#L8

After commenting out that part, you can use it like this:

std::cout << serialize<serde::serde_sstream>(x).str() << std::endl;

Thank you for reporting the bug. 👍

injae avatar Dec 28 '23 14:12 injae