-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
[PoC] Segmentation fault (possibly due to ODR violation) when mixing format.h with and without ostream.h in different cpp files #2357
Comments
(The following analysis only work for current trunk (427b534). I did not look into the older versions.) You should always include If you don't, it will never generate the code calling In your case, fmt::format("test {}", Foo{}); In In case you are curious about what causes segfault, just like I am, I have spent several hours digging into it. The two generated The If you use both, the linker will throw away one If you only use one, you should pray the linker for not throwing away the correct |
@sunmy2019 What I'm saying is this is a HUGE pitfall that should be addressed. Anyone unsuspecting can step into it. Library should be implemented in a way that avoids this and not crash your program depending on what you include or not. But i think, it's already obvious and hope you're already planning how to fix this. |
This HUGE pitfall should only happen if one If you mark the conversion operator I don't know how to fix. I am not in charge here. Maybe include the For internals: The conversion to default formattable type is controlled by Lines 1213 to 1352 in 427b534
Here we use function overload to decide what to convert. If the conversion operator is marked |
You can clearly see this from my PoC. Yes, it is my case.
You can see from the PoC that it is
Okay then. Then I'm more confused than before. Why do you so confidently suggest what I should do and what is/is-not a HUGE pitfall, if you're not the maintainer of this library? Isn't it up to them to counter my argument?
Again, as you can see from PoC, it is explicit. FYI |
Sorry, but I couldn't stop myself from writing this. Imagine a hypothetical scenario. You bought a new coffee machine. It's super convenient, the coffee is perfect, but then there's one thing that bothers you. Among the myriad of buttons there's one special. A really small one, located somewhere on a side. When you press it (hopefully by a accident) the coffee machine spays a hot steam in your face. You quickly open a manual, read through it and yeah, found a small script at a bottom of one of the pages: Maybe you should avoid pressing this button by default? 😄 Your words sound to me exactly like this hypothetical scenario. |
Thanks for reporting. This is indeed problematic behavior and we should fix or at least diagnose it. |
Any hope for a progress on this in the upcoming releases? |
I plan to look into this issue but don't have any specific timeline yet. |
Fixed in f055ebb. Including template <> struct fmt::formatter<Foo> : ostream_formatter {}; |
I won't speculate, it's just a hypothesis that this is an ODR violation. Maybe it's something else. Maybe library makes a static check and interprets the packaged argument one way or another, depending on static conditions, that can result in two different outcomes: depending on whether
fmt/ostream.h
is included.I haven't dug too deep into the library. I've just stoppen on a PoC to reproduce the issue. The issue stems from a fact that some class
Foo
has both: (1) conversion tostd::string_view
and (2)operator << (std::ostream&)
.The PoC
foo.hpp
test.cpp
main.cpp
Compile and run
Note: The order of cpp files is important here. We want to instantiate test.cpp first and then setfault in main.cpp. Though it will work both ways, granted that both usages are invoked (uncomment call to
test();
in main.cpp), one of the will always fail.FreeBSD
clang --std=c++17 main.cpp test.cpp -I /usr/local/include -L /usr/local/lib -stdlib=libc++ -lc++ -lm -lfmt -o poc && ./poc
Linux
clang --std=c++17 test.cpp main.cpp -I /usr/local/include -L /usr/local/lib -lstdc++ -lm -lfmt -o poc && ./poc
The issue is pretty critical, given how hard it is to track all of the possible places where
format()
can accept argument by conversion tostd::string_view
, without a prior include of<fmt/ostream.h>
.Update:
Forgot to add that this issue only exists in
v7.*
. We were successfully usingv6.*
without any issues at all. Only noticed it after the upgrade.The text was updated successfully, but these errors were encountered: