https://bugs.openldap.org/show_bug.cgi?id=9567
Issue ID: 9567 Summary: Double free error after attempt to insert a duplicate entry Product: LMDB Version: 0.9.17 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: --- Component: liblmdb Assignee: bugs@openldap.org Reporter: wietse@porcupine.org Target Milestone: ---
This problem was originally discovered by Adi Prasaja on Ubuntu with lmdb-0.9.24, and reproduced by me on Fedora with lmdb-0.9.25, as well as multiple source repo branches from github.com/openldap.
The problem was introduced with lmdb version 0.9.17 and still exists in the 'head' version 0.9.70 as retrieved from github.com on May 28, 2021.
Quick demo (any Postfix version with LMDB support): create a key-value store from a file containing one (key, value) per line.
$ cat /tmp/aa aa 1 aa 2 $ postmap lmdb:/tmp/aa postmap: warning: lmdb:/tmp/aa: duplicate entry: "aa" <== Postfix message free(): double free detected in tcache 2 <== libc message Aborted (core dumped)
Commenting out the free(env->me_txn0) call mdb_env_close0() will prevent the double free() error. Of course, that results in a memory leak when the input contains no duplicate line.
The remainder of this message show the steps to reproduce this with lmdb version 0.9.70 (from github 'head') on Fedora 32 with postfix-3.7-20210424. These steps have been verified to also work for Postfix 3.2.
The steps assume that the LMDB library and header files are installed in /usr/local, by using the default lmdb Makefile.
$ cat >makemakefiles-lmdb-local <<'EOF' #!/bin/sh
export OPT="" export CCARGS="-DNO_NIS" export AUXLIBS="" # Add LMDB export CCARGS="$CCARGS -DHAS_LMDB" export AUXLIBS_LMDB="-L/usr/local/lib -Wl,-rpath,/usr/local/lib -llmdb"
unset shlib_directory make -f Makefile.in makefiles shared=no dynamicmaps=no CCARGS="-I/usr/local/include $CCARGS" AUXLIBS="$AUXLIBS $AUXLIBS_LMDB" EOF $ make tidy [some output] $ sh makemakefiles-lmdb-local $ make -j8 [lots of output] $ cat >/tmp/aa << EOF aa 1 aa 2 EOF $ valgrind --tool=memcheck bin/postmap lmdb:/tmp/aa ==340318== Memcheck, a memory error detector ==340318== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==340318== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info ==340318== Command: bin/postmap lmdb:/tmp/aa ==340318== postmap: warning: lmdb:/tmp/aa: duplicate entry: "aa" ==340318== Invalid free() / delete / delete[] / realloc() ==340318== at 0x483B9F5: free (vg_replace_malloc.c:538) ==340318== by 0x4858CFD: mdb_env_close0 (in /usr/local/lib/liblmdb.so) ==340318== by 0x4859B0C: mdb_env_close (in /usr/local/lib/liblmdb.so) ==340318== by 0x13CBC3: slmdb_close (slmdb.c:780) ==340318== by 0x13B297: dict_lmdb_close (dict_lmdb.c:475) ==340318== by 0x113DFF: mkmap_close (mkmap_open.c:211) ==340318== by 0x10F080: postmap (postmap.c:557) ==340318== by 0x1108E4: main (postmap.c:1140) ==340318== Address 0x7320c30 is 0 bytes inside a block of size 258 free'd ==340318== at 0x483B9F5: free (vg_replace_malloc.c:538) ==340318== by 0x48561DE: mdb_txn_commit (mdb.c:4130) ==340318== by 0x13CB7D: slmdb_close (slmdb.c:771) ==340318== by 0x13B297: dict_lmdb_close (dict_lmdb.c:475) ==340318== by 0x113DFF: mkmap_close (mkmap_open.c:211) ==340318== by 0x10F080: postmap (postmap.c:557) ==340318== by 0x1108E4: main (postmap.c:1140) ==340318== Block was alloc'd at ==340318== at 0x483CAE9: calloc (vg_replace_malloc.c:760) ==340318== by 0x48599F2: mdb_env_open (in /usr/local/lib/liblmdb.so) ==340318== by 0x13CD91: slmdb_open (slmdb.c:851) ==340318== by 0x13B6C6: dict_lmdb_open (dict_lmdb.c:612) ==340318== by 0x113F50: mkmap_open (mkmap_open.c:283) ==340318== by 0x10EC02: postmap (postmap.c:438) ==340318== by 0x1108E4: main (postmap.c:1140) ==340318== ==340318== ==340318== HEAP SUMMARY: ==340318== in use at exit: 27,608 bytes in 634 blocks ==340318== total heap usage: 1,430 allocs, 797 frees, 3,356,293 bytes allocated ==340318== ==340318== LEAK SUMMARY: ==340318== definitely lost: 0 bytes in 0 blocks ==340318== indirectly lost: 0 bytes in 0 blocks ==340318== possibly lost: 27,582 bytes in 633 blocks ==340318== still reachable: 26 bytes in 1 blocks ==340318== suppressed: 0 bytes in 0 blocks ==340318== Rerun with --leak-check=full to see details of leaked memory ==340318== ==340318== For lists of detected and suppressed errors, rerun with: -s ==340318== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Similar errors happen with lmdb-0.9.17. The problem does not exist in lmdb-0.9.16 or earlier versions.