Fuite de mémoire pendant unordered_map :: insert exception KeyEqual avec GCC - rompre la garantie de sécurité d'exception forte?

10

J'utilise GCC 7.3.1, mais aussi testé sur coliru, qui je crois est la version 9.2.0. Construisez avec les éléments suivants:

g++ -fsanitize=address -fno-omit-frame-pointer rai.cpp

Voici rai.cpp:

#include <iostream>
#include <unordered_map>

int main()
{
    try
    {
        struct MyComp {
            bool operator()(const std::string&, const std::string&) const {
                throw std::runtime_error("Nonono");
            }
        };

        std::unordered_map<std::string, std::string, std::hash<std::string>, MyComp> mymap;
        mymap.insert(std::make_pair("Hello", "There"));
        mymap.insert(std::make_pair("Hello", "There")); // Hash match forces compare
    } catch (const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << "\n";
    }
}

Son exécution entraîne:

> ./a.out
Caught exception: Nonono

=================================================================
==72432==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 32 byte(s) in 1 object(s) allocated from:
...

Direct leak of 4 byte(s) in 1 object(s) allocated from:
...

Indirect leak of 60 byte(s) in 2 object(s) allocated from:
...

SUMMARY: AddressSanitizer: 96 byte(s) leaked in 4 allocation(s).

Je ne vois aucune fuite de mémoire avec Visual C ++ (Microsoft (R) C/C++ Optimizing Compiler Version 19.24.28314 for x64 ).

Est-ce que cela brise la garantie de sécurité d'exception de unordered_map::insert( https://stackoverflow.com/a/11699271/1958315 )? Est-ce un bug dans la GCC STL?

Rai
la source
La STL n'attrapera que les exceptions qu'elle génère (si elle le peut). Cela ne vous empêchera pas de briser, c'est invariant. Bon CPPCON en parler: youtube.com/…
NathanOliver
1
@ NathanOliver-ReinstateMonica doit probablement mettre à jour la documentation, comme std::unordered_map::insertle dit clairement "1-4) Si une exception est levée par une opération , l'insertion n'a aucun effet." (c'est moi qui souligne) à partir d'ici en.cppreference.com/w/cpp/container/unordered_map/insert
Slava
libc ++ ne perd aucune mémoire lors de l'exécution de ce programme.
Marshall Clow
@ NathanOliver-ReinstateMonica c'est un non-sens. La bibliothèque standard doit gérer les exceptions des types définis par l'utilisateur. Il n'y a pas d'invariant brisé ici.
Jonathan Wakely
@Rai c'est un bug, merci de le signaler gcc.gnu.org/bugs
Jonathan Wakely

Réponses:

2

La garantie imposée par la norme (devis du dernier projet):

[container.requirements.general]

Sauf indication contraire (voir [associative.reqmts.except], [unord.req.except], [deque.modifiers] et [vector.modifiers]), tous les types de conteneurs définis dans la présente clause satisfont aux exigences supplémentaires suivantes:

  • si une exception est levée par une fonction insert () ou emplace () lors de l'insertion d'un seul élément, cette fonction n'a aucun effet.

[associative.reqmts.except]

Pour les conteneurs associatifs, si une exception est levée par une opération à partir d'une fonction d'insertion ou de placement insérant un seul élément, l'insertion n'a aucun effet.

[unord.req.except]

Pour les conteneurs associatifs non ordonnés, si une exception est levée par une opération autre que la fonction de hachage du conteneur depuis une fonction insert ou emplace insérant un seul élément, l'insertion n'a aucun effet.

Pour autant que je comprends, "n'a aucun effet" implique "pas de fuite de mémoire". Selon une telle interprétation, je considérerais une fuite comme un bug.

eerorika
la source