jstedfast / gmime

A C/C++ MIME creation and parser library with support for S/MIME, PGP, and Unix mbox spools.
GNU Lesser General Public License v2.1
111 stars 36 forks source link

GLib-CRITICAL **: 22:58:34.070: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed #160

Closed lsem closed 5 months ago

lsem commented 5 months ago

I have a piece of C++ code that parses headers. If I run it once and then exit it works fine (so apparently g_object_unref works as expected). But when I run it twice, it produces stderr output and ASan complains about memory leaks. Am I doing something wrong?

expected<imap_parser::rfc822_headers_t> parse_headers_from_rfc822_message(
    std::string_view message_data) {
    //     ::g_mime_init(); -- INITIALIZATION is implicitly here

    GMimeStream* stream =
        g_mime_stream_mem_new_with_buffer(message_data.data(), message_data.size());
    if (!stream) {
        log_error("failed creating stream");
        return unexpected(make_error_code(parser_errc::parser_fail_l2));
    }

    auto stream_guard = sg::make_scope_guard([stream] { g_object_unref(stream); });

    GMimeParser* parser = g_mime_parser_new_with_stream(stream);
    if (!parser) {
        log_error("failed creating parser from stream");
        return unexpected(make_error_code(parser_errc::parser_fail_l2));
    }
    log_debug("parser created");

    auto parser_guard = sg::make_scope_guard([parser] { g_object_unref(parser); });

    GMimeMessage* message = g_mime_parser_construct_message(parser, nullptr);
    if (!message) {
        log_error("failed constructing message from parser");
        return unexpected(make_error_code(parser_errc::parser_fail_l2));
    }

    auto message_guard = sg::make_scope_guard([message] { g_object_unref(message); });

    log_debug("message parsed, message id: {}", message->message_id);

    // auto rfc822_headers_or_err = decode_headers_from_part((GMimeObject*)message);
    // if (!rfc822_headers_or_err) {
    //     log_error("no headers in rfc822 message: {}", rfc822_headers_or_err.error());
    //     return unexpected(rfc822_headers_or_err.error());
    // }
    // const rfc822_headers_t& rfc822_headers = *rfc822_headers_or_err;

    // for (auto& [header, value] : rfc822_headers) {
    //     log_info("{}: {}", header, value);
    // }

    //     ::g_mime_shutdown(); -- SHUTDOWN is implicitly here

    return {};
}
lsem commented 5 months ago
Repeating all tests (iteration 1) . . .

Note: Google Test filter = *rfc822_parser_tests*parse_headers_massive_gmail_pack_test*
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from rfc822_parser_tests
[ RUN      ] rfc822_parser_tests.parse_headers_massive_gmail_pack_test
1   :  DBG  parser created (imap_parser__rfc822.cpp:264) 
1   :  DBG  message parsed, message id: W4coKWvd8dMGVXhGXVWxjA@notifications.google.com (imap_parser__rfc822.cpp:276) 
[       OK ] rfc822_parser_tests.parse_headers_massive_gmail_pack_test (1 ms)
[----------] 1 test from rfc822_parser_tests (1 ms total)

[==========] 1 test from 1 test suite ran. (1 ms total)
[  PASSED  ] 1 test.

Repeating all tests (iteration 2) . . .

Note: Google Test filter = *rfc822_parser_tests*parse_headers_massive_gmail_pack_test*
[==========] Running 1 test from 1 test suite.
[----------] 1 test from rfc822_parser_tests
[ RUN      ] rfc822_parser_tests.parse_headers_massive_gmail_pack_test

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:96487): GLib-CRITICAL **: 23:07:14.624: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
2   :  DBG  parser created (imap_parser__rfc822.cpp:264) 
2   :  DBG  message parsed, message id: W4coKWvd8dMGVXhGXVWxjA@notifications.google.com (imap_parser__rfc822.cpp:276) 

(process:96487): GLib-CRITICAL **: 23:07:14.625: g_hash_table_destroy: assertion 'hash_table != NULL' failed
[       OK ] rfc822_parser_tests.parse_headers_massive_gmail_pack_test (1 ms)
[----------] 1 test from rfc822_parser_tests (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (1 ms total)
[  PASSED  ] 1 test.

=================================================================
==96487==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 258 byte(s) in 10 object(s) allocated from:
    #0 0x7fac2ceb4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x7fac2cd1ae28 in g_malloc ../../external_glib/glib/gmem.c:130

SUMMARY: AddressSanitizer: 258 byte(s) leaked in 10 allocation(s).
lsem commented 5 months ago

Oh, seems like I see what is the problem. It is not meant to be reinitialized again after shutdown. I will be doing initialization in main() instead of test case set up. Sorry for bothering with this.

jstedfast commented 5 months ago

Where does it say the leak is?

And are you really not calling g_mime_init()?

lsem commented 5 months ago

It is called by the test framework so I commented it out with comment that in fact it is called.

class rfc822_parser_tests : public ::testing::Test {
   public:
    static void SetUpTestCase()  { ASSERT_TRUE(rfc822::initialize()); } // gmime_init
    static void TearDownTestCase()  { ASSERT_TRUE(rfc822::finalize()); } // gmime_shutdown
};