[SERVER-31721] Invalid $expr within $and can segfault on call to optimize Created: 25/Oct/17  Updated: 30/Oct/23  Resolved: 27/Oct/17

Status: Closed
Project: Core Server
Component/s: Querying
Affects Version/s: 3.6.0-rc1
Fix Version/s: 3.6.0-rc2

Type: Bug Priority: Major - P3
Reporter: James Wahlin Assignee: James Wahlin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Backwards Compatibility: Fully Compatible
Operating System: ALL
Steps To Reproduce:

db.coll.drop();
db.coll.insert({});
db.coll.find({$and: [{x: 1}, {$expr: { $anyElementTrue: undefined }}]});

Sprint: Query 2017-11-13
Participants:
Linked BF Score: 0

 Description   

This is only an issue in 3.5/3.6 and not in 3.4 or earlier.



 Comments   
Comment by Githook User [ 27/Oct/17 ]

Author:

{'email': 'james@mongodb.com', 'name': 'James Wahlin', 'username': 'jameswahlin'}

Message: SERVER-31721 invalid $expr within $and/$or can segfault on call to optimize
Branch: master
https://github.com/mongodb/mongo/commit/1032951961fdd2fabb580e5e5bafd9201cfcf678

Comment by James Wahlin [ 25/Oct/17 ]

I believe this is double free during ListOfMatchExpression::getOptimizer() call.

In ListOfMatchExpression::getOptimizer(), we assign ownership for each MatchExpression child to a unique_ptr and MatchExpression::optimize() on the child:
https://github.com/mongodb/mongo/blob/4a03a53a6a420c0baf9fd687a447fd6d942a1c84/src/mongo/db/matcher/expression_tree.cpp#L73-L75

If an exception is thrown during this call then we will free the child MatchExpression as part of the unique_ptr going out of scope.

As the stack unwinds, the ListOfMatchExpression parent object is freed. As part of its destruction, it attempts to free each of its children, resulting in the double free:
https://github.com/mongodb/mongo/blob/4a03a53a6a420c0baf9fd687a447fd6d942a1c84/src/mongo/db/matcher/expression_tree.cpp#L40-L44

Comment by James Wahlin [ 25/Oct/17 ]

Looks like this is due to an attempt to free a pointer which does not point to an allocated object:

mongod(73870,0x7000107cf000) malloc: *** error for object 0x103d38730: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Process 73870 stopped
* thread #2, name = 'conn1', stop reason = signal SIGABRT
    frame #0: 0x00007fffc7939d42 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fffc7939d42 <+10>: jae    0x7fffc7939d4c            ; <+20>
    0x7fffc7939d44 <+12>: movq   %rax, %rdi
    0x7fffc7939d47 <+15>: jmp    0x7fffc7932caf            ; cerror_nocancel
    0x7fffc7939d4c <+20>: retq   
Target 0: (mongod) stopped.
(lldb) bt
* thread #2, name = 'conn1', stop reason = signal SIGABRT
  * frame #0: 0x00007fffc7939d42 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fffc7a27457 libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x00007fffc789f420 libsystem_c.dylib`abort + 129
    frame #3: 0x00007fffc798efe7 libsystem_malloc.dylib`free + 530
    frame #4: 0x000000010132aa22 mongod`mongo::ListOfMatchExpression::~ListOfMatchExpression(this=0x0000000103d38700) at expression_tree.cpp:42
    frame #5: 0x000000010132b7de mongod`mongo::AndMatchExpression::~AndMatchExpression() [inlined] mongo::AndMatchExpression::~AndMatchExpression(this=0x0000000103d38700) at expression_tree.h:112
    frame #6: 0x000000010132b7d9 mongod`mongo::AndMatchExpression::~AndMatchExpression() [inlined] mongo::AndMatchExpression::~AndMatchExpression(this=0x0000000103d38700) at expression_tree.h:112
    frame #7: 0x000000010132b7d9 mongod`mongo::AndMatchExpression::~AndMatchExpression(this=0x0000000103d38700) at expression_tree.h:112
    frame #8: 0x000000010132c388 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator()(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) [inlined] std::__1::default_delete<mongo::MatchExpression>::operator(__ptr=0x0000000103d38700)(mongo::MatchExpression*) const at memory:2397
    frame #9: 0x000000010132c382 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator()(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) [inlined] std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >::reset(mongo::MatchExpression*) at memory:2603
    frame #10: 0x000000010132c377 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator()(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) [inlined] std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >::~unique_ptr() at memory:2571
    frame #11: 0x000000010132c377 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator()(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) [inlined] std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >::~unique_ptr() at memory:2571
    frame #12: 0x000000010132c377 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator()(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) [inlined] decltype(std::__1::forward<mongo::ListOfMatchExpression::getOptimizer() const::$_0&>(fp)(std::__1::forward<std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > >(fp0))) std::__1::__invoke<mongo::ListOfMatchExpression::getOptimizer() const::$_0&, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > >(mongo::ListOfMatchExpression::getOptimizer() const::$_0&&&, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) at type_traits:4291
    frame #13: 0x000000010132c2c0 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator()(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) [inlined] std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > std::__1::__invoke_void_return_wrapper<std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > >::__call<mongo::ListOfMatchExpression::getOptimizer() const::$_0&, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > >(mongo::ListOfMatchExpression::getOptimizer() const::$_0&&&, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) at __functional_base:328
    frame #14: 0x000000010132c2c0 mongod`std::__1::__function::__func<mongo::ListOfMatchExpression::getOptimizer() const::$_0, std::__1::allocator<mongo::ListOfMatchExpression::getOptimizer() const::$_0>, std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator(this=<unavailable>, __arg=<unavailable>)(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >&&) at functional:1552
    frame #15: 0x00000001007eeb18 mongod`mongo::MatchExpression::optimize(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >) [inlined] std::__1::function<std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > (std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >)>::operator(this=0x000000010132bfb0)(std::__1::unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> >) const at functional:1911
    frame #16: 0x00000001007eeb02 mongod`mongo::MatchExpression::optimize(expression=unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > @ 0x00007000107cca30) at expression.h:135
    frame #17: 0x000000010128c516 mongod`mongo::CanonicalQuery::init(this=0x0000000103d39690, opCtx=0x0000000103d38b50, qr=<unavailable>, canHaveNoopMatchNodes=false, root=unique_ptr<mongo::MatchExpression, std::__1::default_delete<mongo::MatchExpression> > @ 0x00007000107ccac0, collator=unique_ptr<mongo::CollatorInterface, std::__1::default_delete<mongo::CollatorInterface> > @ 0x00007000107ccab8) at canonical_query.cpp:226

Generated at Thu Feb 08 04:28:00 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.