[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#7511) EINVAL in internal mdb_cursor_del()

Full_Name: Hallvard B Furuseth
Version: master, d235778c71a50da91741b8b17c572a44b143831b
OS: Linux x86_64
Submission from: (NULL) (
Submitted by: hallvard

mdb_cursor_put() can return MDB_SUCCESS with mc.mc_flags == 0.
mdb_cursor_del() requires mc.mc_flags & C_INITIALIZED.
mdb_txn_commit() can call _del() which fails after _put()
succeeds, at the /* was completely used up */ case.

This breaks slapadd -l frontier.ldif (without -q) at ada.openldap.org,
at "uid=smithhehehe,ou=people,dc=frontiernet,dc=net" (line=527182).
Config ~hallvard/frontiercf.ldif.

Or to trigger it a lot quicker, insert
    assert(rc || (mc->mc_flags & C_INITIALIZED));
before 'done:' in mdb_cursor_put().  I'm guessing that is required,
since ldbm.h says _put() positions the cursor at the newly inserted
item.  Or is that only when _inserting_ a new item, not _modifying_
an existing one?

The mdb_cursor_del() check for C_INITIALIZED is incorrect, it is
evaluated as if ((!mc->mc_flags) & C_INITIALIZED).  Maybe that's
why this has not been caught before.  Same with the test in
mdb_cursor_get case MDB_GET_CURRENT.