Skip to content

-Wmismatched-new-delete error in dir_itr_imp::operator delete with GCC at -O1 (GCC PR 103993) #356

Closed

Description

@baumgold

src/directory.cpp fails to compile with GCC at -O1 when warnings are errors:

src/directory.cpp:238:14: error: 'void free(void*)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
src/directory.cpp:486:92: note: returned from 'static void* boost::filesystem::detail::dir_itr_imp::operator new(std::size_t, std::size_t)'

Environment

  • Boost: 1.90.0 (the develop branch has the same code)
  • Compiler: GCC 15.2.0
  • Platform: Linux, AlmaLinux 9, x86-64
  • Flags: -std=c++26 -O1 -Wall -Werror -fsanitize=thread (-march=x86-64 -mtune=generic -pthread)

dir_itr_imp::operator new allocates with std::malloc, so std::free in operator delete is the correct deallocation function. When intrusive_ptr<dir_itr_imp>::~intrusive_ptr is inlined into dir_itr_create, GCC pairs the new expression with the free call and warns. The pair itself is consistent, so the warning is spurious here; it appears when GCC inlines only one half of the pair.

It is not specific to TSan. This standalone reproduction mirrors the class-specific operator new/operator delete pair:

#include <cstdlib>
#include <cstring>
#include <cstddef>

struct imp
{
    int refs = 1;
    static void* operator new(std::size_t class_size, std::size_t extra_size) noexcept;
    static void operator delete(void* p, std::size_t) noexcept;
    static void operator delete(void* p) noexcept;
};

void* imp::operator new(std::size_t class_size, std::size_t extra_size) noexcept
{
    void* p = std::malloc(class_size + extra_size);
    if (p) std::memset(p, 0, class_size + extra_size);
    return p;
}
void imp::operator delete(void* p, std::size_t) noexcept { std::free(p); }
void imp::operator delete(void* p) noexcept { std::free(p); }

int f(std::size_t n, bool fail)
{
    imp* p = new (n) imp();
    if (!p) return 1;
    if (fail) { delete p; return 2; }
    delete p;
    return 0;
}
int main(int argc, char**) { return f(64, argc > 1); }

g++ -std=c++26 -O1 -Wall -Werror -c repro.cpp reports the error with GCC 15.2.0. It does not fire at -O0, -O2 or -O3 with this example.

I also ran this reproduction on Compiler Explorer with -std=c++20 -Wall on x86-64 GCC 12.2, 13.1, 13.2, 14.2, 15.1, 15.2 and trunk (17.0.0 20261020). All of them warn at -O1 and -Os and not at -O0, -O2 or -O3, so this is not a recent regression.

This is already reported to GCC as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103993 (open since 2022). The GCC maintainers' position there is that the warning is computed on the optimized code and fires when only one of operator new / operator delete is inlined; the suggested workaround is to keep both inlined or both out of line. #357 keeps the pair out of line.

Activity

  1. added a commit that references this issue on Oct 20, 2026
    c6f3fd7
  2. Lastique commented on Oct 20, 2026

    @Lastique
    Member

    Since this is a false positive, please report this to gcc. I can silence the warning, but the bug needs to be fixed in the compiler.

  3. added a commit that references this issue on Oct 20, 2026
    9e3e5cc
  4. changed the title [-]-Wmismatched-new-delete error in dir_itr_imp::operator delete with GCC 15 at -O1[/-] [+]-Wmismatched-new-delete error in dir_itr_imp::operator delete with GCC at -O1 (GCC PR 103993)[/+] on Oct 20, 2026
  5. baumgold commented on Oct 20, 2026

    @baumgold
    Author

    Thanks. This is already reported to GCC as PR 103993, open since 2022, so I haven't filed a duplicate. There are matching reports in that thread from other projects, including one from the libstdc++ testsuite. The GCC maintainer's reply there (comment 2) is that the warning is computed on the optimized code, so it fires when GCC inlines only one of a class's operator new / operator delete, and that the intended workaround is to keep both inlined or both out of line. I checked with Compiler Explorer that the reproduction in the description still warns on GCC trunk (17.0.0 20261020), and on every release back to 12.2, so I don't expect a compiler fix soon.

    Because of that, I've replaced the diagnostic pragma in #357 with marking operator new and both operator delete overloads BOOST_NOINLINE. That follows the workaround from the GCC thread, doesn't suppress the diagnostic, and doesn't change how memory is allocated. I rebuilt and ran the filesystem tests with GCC 15 (details in the PR description).

    If you would still rather suppress the warning with a pragma than keep these out of line, I can switch back.

  6. Lastique commented on Oct 20, 2026

    @Lastique
    Member

    Thanks, I've applied my version of the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions