Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-41011

Server may crash when running $where on non-existent collection

    • Type: Icon: Bug Bug
    • Resolution: Duplicate
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 4.1.10
    • Component/s: Querying
    • Labels:
      None
    • ALL
    • Execution Team 2019-06-03
    • 6

      As discovered by gregory.wlodarek, this will crash the server with an invariant when run on a secondary:

      db.system.js.insertOne({x: 1});
      db.createView('someView', 'anyBaseColl', []);
      db.js_protection.find({$where: 'aaa'}).toArray();
      
      resmoke --suites=jstestfuzz_sharded_causal_consistency repro.js
      

      Here is the sequence of events that cause the find() command to trigger an invariant:
      1) The find command makes an AutoGetCollectionForReadCommand on test.js_protection.

      1a) The construction of the AutoGetCollection causes a view catalog lookup and thus, refresh because of the recently created view.

      1b) The refresh causes us to read from system.views, which "activates" the recovery unit when the WiredTigerCursor is created. Note that this refresh only happens when the collection does not exist.

      1c) After the AutoGetCollection is constructed This entire block of AutoGetCollectionForRead() is skipped because the collection does not exist.

      2) We initialize the WhereMatchExpression which creates a JS scope. As part of creating the JS scope, we create a DBDirectClient for reading from system.js.

      3) We run a find() query using the DBDirectClient, and enter FindCmd::Invocation::run() again. We create an AutoGetCollectionForReadCommand, but this time, on system.js.

      3a) Inside of AutoGetCollectionForRead() we decide that since we're on a secondary and the readConcern is "local", we should read from the last applied timestamp.

      3b) We try to set the recovery unit's timestamp read source to kLastApplied here, which triggers this invariant, because the recovery unit was made "active" during the view catalog lookup:

      // wiredtiger_recovery_unit.cpp L786-L791
      invariant(!_isActive() || _timestampReadSource == readSource,
                str::stream() << "Current state: " << toString(_state)
                              << ". Invalid internal state while setting timestamp read source: "
                              << static_cast<int>(readSource)
                              << ", provided timestamp: "
                              << (provided ? provided->toString() : "none"));
      

      I could not repro this on 4.0 because in that branch, the invariant allows for _timestampReadSource to be kUnset. See here

      Unable to find source-code formatter for language: java. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      invariant(!_active || _timestampReadSource == ReadSource::kUnset ||
               _timestampReadSource == readSource);
      

            Assignee:
            xiangyu.yao@mongodb.com Xiangyu Yao (Inactive)
            Reporter:
            ian.boros@mongodb.com Ian Boros
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: