Uploaded image for project: 'WiredTiger'
  1. WiredTiger
  2. WT-607

referencing application memory after a cursor operation

    • Type: Icon: Task Task
    • Resolution: Done
    • WT1.6.4
    • Affects Version/s: None
    • Component/s: None
    • Labels:

      @michaelcahill, we talked about referencing application memory after a cursor operation, and my understanding is we were going to add documentation saying we only reference application memory between the WT_CURSOR.set_key call and the subsequent WT_CURSOR.XXX operation.

      It occurred to me that it's not as simple as that:

      I think the interesting operations are WT_CURSOR compare, search, insert, update and remove (all other cursor operations either don't require a key or will set the key in all cases as part of the operation).

      A quick smoke test makes me think we are currently enforcing this guarantee only for search, not for compare, insert, update, and remove.

      What we do, however, is on a subsequent operation, if WT_CURSTD_KEY_RET is set, we copy the key. In other words:

      cursor = self.session.open_cursor(uri) 
      cursor.set_key(key_populate(cursor, 5))
      cursor.remove() 
      cursor.set_value('XXXXXXXXXX')
      cursor.insert()        <<< key gets copied here
      

      Which means this sequence of code (where the key_format is 'u' and I'm passing in WT_ITEMs), changes the key's contents for the subsequent insert call.

      key.data = kbuf;
      key.size = snprintf(kbuf, sizeof(kbuf), "%010d KEY------", 5);
      cursor->set_key(cursor, &key);
      assert(cursor->remove(cursor) == 0);
      
      strcpy(kbuf, "OVERWRITE");        <<< modify my local buffer
      snprintf(vbuf, sizeof(vbuf), "YYYYYYYYYYYYYYYYYYYYYYYYYY");
      cursor->set_value(cursor, vbuf);
      assert(cursor->insert(cursor) == 0);
      

      And, of course, if the WT_ITEM referenced buffer is free'd or goes out of scope, I think we're going to fault.

      Q1: should we do a key copy as part of the successful return from the functions that don't naturally overwrite the key?
      Q2: should we disallow multiple uses of a single WT_CURSOR.set_key call (it seems to me they're not the common case, I'd hate to slow down the common case for them).

      Also, there's the question of errors. Imagine this sequence:

      cursor = self.session.open_cursor(uri, None, "overwrite=false")
      cursor.set_key("no such key")
      ret = cursor.remove()        <<< returns WT_NOTFOUND
      
      cursor.set_value('XXXXXXXXXX')
      cursor.insert()         <<< no copy of the key
      

      Because remove returned WT_NOTFOUND, WT_CURSTD_KEY_RET was never set and the key isn't copied as part of the cursor.insert call.

      Q3: should we clear WT_CURSTD_KEY_APP on error?
      Q4: does this all argue for a copy as part of the WT_CURSOR.set_key call, just to make this all go away? (Obviously, that's a bad thing, I mention it for completeness.)

      Anyway, maybe I'm off in the weeds here, but I wanted to write it up for your review.

            Assignee:
            michael.cahill@mongodb.com Michael Cahill (Inactive)
            Reporter:
            keith.bostic@mongodb.com Keith Bostic (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: