Skip to content

using namespace magic_enum::bitwise_operators; is very evil #434

@oxiKKK

Description

@oxiKKK

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) 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions