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

Fix a double free inside DocumentSource::optimizeAt()

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 4.4.14, 5.0.4, 5.1.0-rc0, 4.2.20
    • Affects Version/s: None
    • Component/s: None
    • None
    • Fully Compatible
    • ALL
    • Hide
      $ cat jstestfuzz/repro.js
      var joinColl = db.lookup_non_correlated_prefix_join;
      var testColl = db.lookup_non_correlated_prefix;
      testColl.insert(\{
          textField: 'yo hablo espanol',
          language: 'spa'
      });
      testColl.aggregate([\{
          $lookup: {
              as: 'items_check',
              from: joinColl.getName(),
              let: { id: '$_id' },
              pipeline: [
                  { $addFields: { id: '$_id' } },
                  { $match: {} },
                  { $facet: { all: [{ $match: {} }] } }
              ]
          }
      }]);
       
      $ buildscripts/resmoke.py run --suites=jstestfuzz_replication --repeat 2 jstestfuzz/repro.js
      
      Show
      $ cat jstestfuzz/repro.js var joinColl = db.lookup_non_correlated_prefix_join; var testColl = db.lookup_non_correlated_prefix; testColl.insert(\{ textField: 'yo hablo espanol' , language: 'spa' }); testColl.aggregate([\{ $lookup: { as: 'items_check' , from: joinColl.getName(), let: { id: '$_id' }, pipeline: [ { $addFields: { id: '$_id' } }, { $match: {} }, { $facet: { all: [{ $match: {} }] } } ] } }]);   $ buildscripts/resmoke.py run --suites=jstestfuzz_replication --repeat 2 jstestfuzz/repro.js
    • QO 2021-09-06
    • 137

      According to address sanitizer report, a double free is happening inside DocumentSource::optimizeAt().

      Here’s the sanitizer output:

      2705 [j0:prim] ==608==ERROR: AddressSanitizer: heap-use-after-free on address 0x612000234f40 at pc 0x55dd2553a7b8 bp 0x7f29c3e52870 sp 0x7f29c3e52868
      2706 [j0:prim] READ of size 8 at 0x612000234f40 thread T118 (conn50)
      2713 [j0:prim]     #0 0x55dd2553a7b7 in mongo::DocumentSource::dispose() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source.h:328:9
      2714 [j0:prim]     #1 0x55dd25884e77 in mongo::TeeBuffer::dispose(unsigned long) /home/ubuntu/mongo/src/mongo/db/pipeline/tee_buffer.h:74:26
      2715 [j0:prim]     #2 0x55dd25883664 in mongo::DocumentSourceTeeConsumer::doDispose() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source_tee_consumer     .cpp:62:20
      2716 [j0:prim]     #3 0x55dd2553a7f0 in mongo::DocumentSource::dispose() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source.h:328:9
      2717 [j0:prim]     #4 0x55dd2553a85c in mongo::DocumentSource::dispose() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source.h:330:22
      2718 [j0:prim]     #5 0x55dd2590210f in mongo::pipeline::dispose(mongo::OperationContext*) /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:338:30
      2719 [j0:prim]     #6 0x55dd255c3862 in mongo::DocumentSourceFacet::doDispose() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source_facet.cpp:145:25
      2720 [j0:prim]     #7 0x55dd2553a7f0 in mongo::DocumentSource::dispose() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source.h:328:9
      2721 [j0:prim]     #8 0x55dd2583faaf in mongo::DocumentSourceSequentialDocumentCache::doOptimizeAt(std::_List_iterator<boost::intrusive_ptr<mongo::Document     Source> >, std::__cxx11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubun     tu/mongo/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp:145:18
      2722 [j0:prim]     #9 0x55dd254e1d3b in mongo::DocumentSource::optimizeAt(std::_List_iterator<boost::intrusive_ptr<mongo::DocumentSource> >, std::__cxx11::     list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubuntu/mongo/src/mongo/db/pip     eline/document_source.cpp:234:12
      2723 [j0:prim]     #10 0x55dd2590041c in mongo::pipeline::optimizeContainer(std::__cxx11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<     boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:275:33
      2724 [j0:prim]     #11 0x55dd258ffffd in mongo::pipeline::optimizePipeline() /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:265:5
      2725 [j0:prim]     #12 0x55dd2571f2df in mongo::DocumentSourceLookUp::buildPipeline(mongo::Document const&) /home/ubuntu/mongo/src/mongo/db/pipeline/docume     nt_source_lookup.cpp:527:15
      2726 [j0:prim]     #13 0x55dd257195d4 in mongo::DocumentSourceLookUp::doGetNext() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source_lookup.cpp:377:2     0
      2727 [j0:prim]     #14 0x55dd2099ecef in mongo::DocumentSource::getNext() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source.h:293:20
      2728 [j0:prim]     #15 0x55dd25905e66 in mongo::pipeline::getNext() /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:469:40
      2729 [j0:prim]     #16 0x55dd23c12c94 in mongo::PlanExecutorPipeline::_tryGetNext() /home/ubuntu/mongo/src/mongo/db/pipeline/plan_executor_pipeline.cpp:129     :23
      2730 [j0:prim]     #17 0x55dd23c12917 in mongo::PlanExecutorPipeline::_getNext() /home/ubuntu/mongo/src/mongo/db/pipeline/plan_executor_pipeline.cpp:117:20
      ...
       
      2834 [j0:prim] 0x612000234f40 is located 0 bytes inside of 280-byte region [0x612000234f40,0x612000235058)
      2835 [j0:prim] freed by thread T118 (conn50) here:
      2836 [j0:prim]     #0 0x55dd1e259315 in operator delete(void*, unsigned long) /data/mci/a0a92963d3836bdfa3c974d486c10ee5/toolchain-builder/tmp/build-llvm.s     h-DWL/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:179:3
      2837 [j0:prim]     #1 0x55dd2575a698 in mongo::DocumentSourceMatch::~DocumentSourceMatch() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source_match.h     :104:44
      2838 [j0:prim]     #2 0x55dd1e2cd3b7 in mongo::intrusive_ptr_release(mongo::RefCountable const*) /home/ubuntu/mongo/src/mongo/util/intrusive_counter.h:74:1     3
      2839 [j0:prim]     #3 0x55dd205ced68 in boost::intrusive_ptr<mongo::DocumentSource>::~intrusive_ptr() /home/ubuntu/mongo/src/third_party/boost/boost/smart_     ptr/intrusive_ptr.hpp:98:23
      2840 [j0:prim]     #4 0x55dd205cecf8 in void __gnu_cxx::new_allocator<std::_List_node<boost::intrusive_ptr<mongo::DocumentSource> > >::destroy<boost::intru     sive_ptr<mongo::DocumentSource> >(boost::intrusive_ptr<mongo::DocumentSource>*) /opt/mongodbtoolchain/revisions/39699409944dd532c7cbdce2f62da11361ac22     0a/stow/gcc-v3.Me0/lib/gcc/x86_64-mongodb-linux/8.2.0/../../../../include/c++/8.2.0/ext/new_allocator.h:140:28
      2841 [j0:prim]     #5 0x55dd205cec27 in void std::allocator_traits<std::allocator<std::_List_node<boost::intrusive_ptr<mongo::DocumentSource> > > >::destro     y<boost::intrusive_ptr<mongo::DocumentSource> >(std::allocator<std::_List_node<boost::intrusive_ptr<mongo::DocumentSource> > >&, boost::intrusive_ptr<     mongo::DocumentSource>*) /opt/mongodbtoolchain/revisions/39699409944dd532c7cbdce2f62da11361ac220a/stow/gcc-v3.Me0/lib/gcc/x86_64-mongodb-linux/8.2.0/.     ./../../../include/c++/8.2.0/bits/alloc_traits.h:487:8
      2842 [j0:prim]     #6 0x55dd22b3ee92 in std::__cxx11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::Document     Source> > >::_M_erase(std::_List_iterator<boost::intrusive_ptr<mongo::DocumentSource> >) /opt/mongodbtoolchain/revisions/39699409944dd532c7cbdce2f62da     11361ac220a/stow/gcc-v3.Me0/lib/gcc/x86_64-mongodb-linux/8.2.0/../../../../include/c++/8.2.0/bits/stl_list.h:1916:2
      2843 [j0:prim]     #7 0x55dd22b3ec31 in std::__cxx11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::Document     Source> > >::erase(std::_List_const_iterator<boost::intrusive_ptr<mongo::DocumentSource> >) /opt/mongodbtoolchain/revisions/39699409944dd532c7cbdce2f6     2da11361ac220a/stow/gcc-v3.Me0/lib/gcc/x86_64-mongodb-linux/8.2.0/../../../../include/c++/8.2.0/bits/list.tcc:158:7
      2844 [j0:prim]     #8 0x55dd254df923 in mongo::DocumentSource::pushMatchBefore(std::_List_iterator<boost::intrusive_ptr<mongo::DocumentSource> >, std::__cx     x11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubuntu/mongo/src/mongo/d     b/pipeline/document_source.cpp:185:24
      2845 [j0:prim]     #9 0x55dd254f00ec in mongo::DocumentSource::attemptToPushStageBefore(std::_List_iterator<boost::intrusive_ptr<mongo::DocumentSource> >,      std::__cxx11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubuntu/mongo/sr     c/mongo/db/pipeline/document_source.h:465:16
      2846 [j0:prim]     #10 0x55dd254e19ad in mongo::DocumentSource::optimizeAt(std::_List_iterator<boost::intrusive_ptr<mongo::DocumentSource> >, std::__cxx11:     :list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubuntu/mongo/src/mongo/db/pi     peline/document_source.cpp:228:9
      2847 [j0:prim]     #11 0x55dd2590041c in mongo::pipeline::optimizeContainer(std::__cxx11::list<boost::intrusive_ptr<mongo::DocumentSource>, std::allocator<     boost::intrusive_ptr<mongo::DocumentSource> > >*) /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:275:33
      2848 [j0:prim]     #12 0x55dd258ffffd in mongo::pipeline::optimizePipeline() /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:265:5
      2849 [j0:prim]     #13 0x55dd2571f2df in mongo::DocumentSourceLookUp::buildPipeline(mongo::Document const&) /home/ubuntu/mongo/src/mongo/db/pipeline/docume     nt_source_lookup.cpp:527:15
      2850 [j0:prim]     #14 0x55dd257195d4 in mongo::DocumentSourceLookUp::doGetNext() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source_lookup.cpp:377:2     0
      2851 [j0:prim]     #15 0x55dd2099ecef in mongo::DocumentSource::getNext() /home/ubuntu/mongo/src/mongo/db/pipeline/document_source.h:293:20
      2852 [j0:prim]     #16 0x55dd25905e66 in mongo::pipeline::getNext() /home/ubuntu/mongo/src/mongo/db/pipeline/pipeline.cpp:469:40
      2853 [j0:prim]     #17 0x55dd23c12c94 in mongo::PlanExecutorPipeline::_tryGetNext() /home/ubuntu/mongo/src/mongo/db/pipeline/plan_executor_pipeline.cpp:129     :23
      2854 [j0:prim]     #18 0x55dd23c12917 in mongo::PlanExecutorPipeline::_getNext() /home/ubuntu/mongo/src/mongo/db/pipeline/plan_executor_pipeline.cpp:117:20
      

      It looks like that we’re deleting some document source at attemptToPushStageBefore() and then delete it again at doOptimizeAt().

      Pipeline::SourceContainer::iterator DocumentSource::optimizeAt(
          Pipeline::SourceContainer::iterator itr, Pipeline::SourceContainer* container) \{
          invariant(*itr == this);
      
          // Attempt to swap 'itr' with a subsequent stage, if applicable.
          if (attemptToPushStageBefore(itr, container)) {
              // The stage before the pushed before stage may be able to optimize further, if there is
              // such a stage.
              return std::prev(itr) == container->begin() ? std::prev(itr) : std::prev(std::prev(itr));
          }
      
          return doOptimizeAt(itr, container);
      }
      

       

            Assignee:
            david.percy@mongodb.com David Percy
            Reporter:
            yoonsoo.kim@mongodb.com Yoon Soo Kim
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: