简体   繁体   中英

Thrown exceptions being leaked in C++

I'm fooling around a bit with C++, and as part of that have a piece of "restartable" code. To wit:

class handler {
public:
    virtual ~handler() {}
    virtual response handle(request &req) = 0;
};

response dispatch(request &req, handler &hnd) {
    try {
        return(hnd.handle(req));
    } catch(handler &rep) {
        return(dispatch(req, rep));
    }
}

Then, in another part of the code:

static response serve(request &req) {
    throw(resp::message("Merdel", {"Test"}));
}

Where resp::message is a subclass of handler .

This appears to work fine, but when I run it an Valgrind, it tells me this leaks memory:

==2609== 352 bytes in 11 blocks are definitely lost in loss record 12 of 16
==2609==    at 0x4C270FE: memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2609==    by 0x4010BEF: tls_get_addr_tail (dl-tls.c:529)
==2609==    by 0x401110F: __tls_get_addr (dl-tls.c:767)
==2609==    by 0x668FC9B: __cxa_get_globals (eh_globals.cc:63)
==2609==    by 0x668F5EE: __cxa_allocate_exception (eh_alloc.cc:132)
==2609==    by 0x61DDA5E: serve(arw::request&) (arwtest.ashc:7)
==2609==    by 0x640E18B: arw::funhandler::handle(arw::request&) (arw.cpp:95)
==2609==    by 0x640E1C5: arw::dispatch(arw::request&, arw::handler&) (arw.cpp:100)
==2609==    by 0x640E487: arw::dispatch(ashd::request const&, arw::handler&) (arw.cpp:119)
==2609==    by 0x61DDBA7: _htstart (arwtest.ashc:11)
==2609==    by 0x403CCD: servehtstart (request.c:228)
==2609==    by 0x4040C5: servereq (request.c:303)

serve(arw::request&) (arwtest.ashc:7) is the serve function listed above.

Why does this leak memory? It is my understanding that the C++ runtime should free these exceptions for me automatically (and it's not like I have any ability to free them manually anyway, right?), so what could cause it not to?

I did find these two previous questions on a similar theme, but they don't seem to be applicable here as they only treat a single leaked exception under exceptional circumstances, while this code leaks an exception per request (do note that 11 individual blocks are leaked; this is because I ran this test function 11 times during this test).

EDIT : I don't know if it's relevant or not, but it may be worth noting that servehtstart and servereq in the backtrace are functions in a pure-C program. _htstart and above are C++ code from a shared object that is dlopen() ed. It may also be relevant that it is only the dlopen of this shared object that at all brings libstdc++ into the process.

As it turns out, this is a bug in certain versions of glibc, including the version currently in Debian Stable (namely, 2.13), but which has been since fixed. When running this same program on a Debian Testing setup (which uses glibc 2.19), the memory leak does not occur.

Apparently, glibc 2.13 does not properly clean up thread-local memory that is introduced by dlopen() 'ed objects. It occurs here because libstdc++ was only loaded as a consequence of the dlopen() . The issue is previously described in these two bug reports:

The glibc commit which fixed the issue was e6c61494 .

Thanks @quantdev, @DavidSchwartz. Your comments made me realize what to look for.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM