-
Notifications
You must be signed in to change notification settings - Fork 517
Description
Just wanted to say that using
using namespace magic_enum::bitwise_operators;in a global namespace is extremely evil and dangerous and I didn't know about this behaviour at all.
Background
I am building a c++ application that ships protobuf and is cross-compatible with most of the major platforms. Recently after rebuilding my application on macOS, my program was crashing in a way i've honestly didn't experience in a long while of writing C++. It crashed during initialization of some static descriptor pool which was part of the protobuf code.
This has never happened to me and I had no idea what was causing it. It happened at initialization time, i.e. before main is called so it was even harder to debug.
More strangly, it only happened after me compiling the binary with *specific parts of code*, which I was completely confused about.
Turns out it was this single line of code in my precompiled header file before including the protobuf headers:
using namespace magic_enum::bitwise_operators;Proposed solution
What I wanted to point out is that after looking into the implementation, it was obvious that this may break things, but I would never expect that it would break them in such way that took me 2 days to debug.
What I suggest is to at least warn the user of this library that this code may be dangerous and may be used only with caution or in a limited namespace.
EDIT: Added section below
Reproducible example
I've made a reproducible example here: https://github.com/oxiKKK/protobuf-magic_enum-repro
The output from the following program after running it:
#include <iostream>
#include <magic_enum/magic_enum.hpp>
// >>>> THIS CAUSES CRASH <<<<
using namespace magic_enum::bitwise_operators;
// >>> NOW INCLUDE PROTOBUF <<<
#include "example.pb.h"
#include <google/protobuf/message.h>
int main() {
std::cout << "Creating protobuf message..." << std::endl;
example::Person person;
person.set_name("John Doe");
person.set_id(123);
person.set_email("john.doe@example.com");
std::cout << "Person created successfully!" << std::endl;
std::cout << "Name: " << person.name() << std::endl;
std::cout << "ID: " << person.id() << std::endl;
std::cout << "Email: " << person.email() << std::endl;
// Create an AddressBook with the person
example::AddressBook address_book;
auto *new_person = address_book.add_people();
*new_person = person;
std::cout << "AddressBook created with " << address_book.people_size()
<< " person(s)" << std::endl;
return 0;
}Output:
> protobuf-magic_enum-repro % lldb ./build/magic_enum_protobuf_repro
(lldb) target create "./build/magic_enum_protobuf_repro"
Current executable set to '/Users/XX/dev/protobuf-magic_enum-repro/build/magic_enum_protobuf_repro' (arm64).
(lldb) r
Process 57912 launched: '/Users/XX/dev/protobuf-magic_enum-repro/build/magic_enum_protobuf_repro' (arm64)
Process 57912 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x53707937)
frame #0: 0x0000000100002b44 magic_enum_protobuf_repro`std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::__is_long[abi:ne190102](this="") const at string:1881:29
1878 if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) {
1879 return __r_.first().__l.__is_long_;
1880 }
-> 1881 return __r_.first().__s.__is_long_;
1882 }
1883
1884 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __begin_lifetime(pointer __begin, size_type __n) {
Target 0: (magic_enum_protobuf_repro) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x53707937)
* frame #0: 0x0000000100002b44 magic_enum_protobuf_repro`std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::__is_long[abi:ne190102](this="") const at string:1881:29
frame #1: 0x0000000100002e80 magic_enum_protobuf_repro`std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::__get_pointer[abi:ne190102](this="") const at string:2009:12
frame #2: 0x0000000100002574 magic_enum_protobuf_repro`std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::data[abi:ne190102](this="") const at string:1705:30
frame #3: 0x00000001000063fc magic_enum_protobuf_repro`absl::lts_20250127::string_view::string_view<std::__1::allocator<char>>(this=0x000000016fdf8f78, str="") at string_view.h:193:25
frame #4: 0x0000000100243e28 magic_enum_protobuf_repro`google::protobuf::internal::TcParser::FastSS1(google::protobuf::MessageLite*, char const*, google::protobuf::internal::ParseContext*, google::protobuf::internal::TcFieldData, google::protobuf::internal::TcParseTableBase const*, unsigned long long)
... More in the repository's README
(lldb)