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

            Bug ID: 109732
           Summary: [14 regression] gcc miscompiles iterator comparison on
                    nlohmann_json
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: slyfox at gcc dot gnu.org
  Target Milestone: ---

Initially I observed the failure as a test failure on nlohmann_json-3.11.2
against gcc-14 master (r14-395-g1adb1a653d6739):

  33 - test-items_cpp11 (Failed)
  34 - test-items_cpp17 (Failed)

I extracted smaller but not yet self-contained example that seems to illustrate
the problem:

// $ cat unit-t.cpp
#include <cstdio>
#include <nlohmann/json.hpp>

namespace {

int seen_failures = 0;

__attribute__((noinline))
static void sne(nlohmann::json::const_reverse_iterator lhs,
                nlohmann::json::const_reverse_iterator rhs) {
    bool res = !(lhs == rhs);
    if (!res) seen_failures++;
}

struct TestCase
{
    void (*m_test)();
    TestCase(void (*test)()) {
        // not used anywhere, but triggers the failure
        m_test = test;
    }
};


static void _DOCTEST_ANON_FUNC_8()
{
    const nlohmann::json js = "hello world";
    const nlohmann::json js_const(js);

    nlohmann::json::const_reverse_iterator sit = js_const.crbegin();

    sne(sit, js_const.crend());
}

}

int main() {
    // below 3 lines look like a no-op, but afects the result:
    TestCase ltc(&_DOCTEST_ANON_FUNC_8);
    std::vector<const TestCase*> testArray;
    testArray.push_back(&ltc);

    _DOCTEST_ANON_FUNC_8();

    puts((seen_failures > 0) ? "FAILURE!" : "SUCCESS!");

    return EXIT_SUCCESS;
}

To trigger it we will need json headers-only library:

    $ git clone --depth 1 https://github.com/nlohmann/json.git
    # commit 6af826d0bdb55e4b69e3ad817576745335f243ca

    $ g++-14 unit-t.cpp -O2 -Ijson/include -o a && ./a
    FAILURE!

For comparison unoptimized and older gcc does work as expcted:

    $ g++-14 unit-t.cpp -O0 -Ijson/include -o a && ./a
    SUCCESS!
    $ g++ unit-t.cpp -O2 -Ijson/include -o a && ./a
    SUCCESS!

I'm not sure if `nlohmann::json::const_reverse_iterator` is implemented
correctly according to c++ requirements. The inheritance looks fishy. At least
I would expect consistent behaviour for -O0/O2.

-fsanitize={address,undefined} does not uncover anything obvious. Can you help
me understand if it's a gcc or json deficiency?

Thank you!

Reply via email to