[SERVER-7705] ReferenceError executing stored JS with V8 causes nightly to segfault. Created: 18/Nov/12  Updated: 11/Jul/16  Resolved: 19/Nov/12

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: 2.3.1

Type: Bug Priority: Major - P3
Reporter: Bernie Hackett Assignee: Tad Marshall
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to SERVER-7710 V8 build isn't supporting some stored... Closed
Backwards Compatibility: Fully Compatible
Operating System: ALL
Participants:

 Description   

Found this running PyMongo's tests against the latest (as of this ticket's creation) nightly (mongodb-linux-x86_64-2012-11-13).

Sun Nov 18 09:10:34.674 [initandlisten] db version v2.3.1-pre-, pdfile version 4.5
Sun Nov 18 09:10:34.674 [initandlisten] git version: 88055d1a66ba7daefe681900a79cd9c01896304f

You can't actually store the Javascript to cause this using the JS shell so the repro steps require PyMongo:

First insert the bad JS:

>>> c = pymongo.Connection(port=20000)
>>> db = c.foo
>>> db.system_js.foo = "baz"

Trying to execute this in a Spider Monkey build raises an exception:

>>> db.system_js.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pymongo/database.py", line 848, in <lambda>
    scope={'name': name}), *args)
  File "pymongo/database.py", line 788, in eval
    result = self.command("$eval", code, args=args)
  File "pymongo/database.py", line 392, in command
    msg, allowable_errors)
  File "pymongo/helpers.py", line 144, in _check_command_response
    raise OperationFailure(msg % details["errmsg"])
pymongo.errors.OperationFailure: command SON([('$eval', Code('function() { return this[name].apply(this, arguments); }', {'name': 'foo'})), ('args', ())]) failed: invoke failed: JS Error: ReferenceError: baz is not defined nofile_a:0

To reproduce the segfault with V8 start by doing a system_js call with nothing in the system.js collection, add the invalid JS, then execute the function again:

>>> import pymongo
>>> c = pymongo.Connection()
>>> db = c.foo
>>> db.system_js.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pymongo/database.py", line 848, in <lambda>
    scope={'name': name}), *args)
  File "pymongo/database.py", line 788, in eval
    result = self.command("$eval", code, args=args)
  File "pymongo/database.py", line 392, in command
    msg, allowable_errors)
  File "pymongo/helpers.py", line 144, in _check_command_response
    raise OperationFailure(msg % details["errmsg"])
pymongo.errors.OperationFailure: command SON([('$eval', Code('function() { return this[name].apply(this, arguments); }', {'name': 'foo'})), ('args', ())]) failed: invoke failed: error in invoke: _funcs1:1 TypeError: Cannot call method 'apply' of undefined
_funcs1 = function() { return this[name].apply(this, arguments); }
                                         ^
 
>>> db.system_js.foo = "baz"
>>> db.system_js.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pymongo/database.py", line 848, in <lambda>
    scope={'name': name}), *args)
  File "pymongo/database.py", line 788, in eval
    result = self.command("$eval", code, args=args)
  File "pymongo/database.py", line 387, in command
    result = self["$cmd"].find_one(command, **extra_opts)
  File "pymongo/collection.py", line 582, in find_one
    for result in self.find(spec_or_id, *args, **kwargs).limit(-1):
  File "pymongo/cursor.py", line 799, in next
    if len(self.__data) or self._refresh():
  File "pymongo/cursor.py", line 748, in _refresh
    self.__uuid_subtype))
  File "pymongo/cursor.py", line 685, in __send_message
    **kwargs)
  File "pymongo/mongo_client.py", line 917, in _send_message_with_response
    raise AutoReconnect(str(e))
pymongo.errors.AutoReconnect: connection closed

Backtrace from the mongod log:

<unknown>:33: Uncaught ReferenceError: baz is not defined
Sun Nov 18 09:45:31.929 Invalid access at address: 0 from thread: conn1
 
Sun Nov 18 09:45:31.929 Got signal: 11 (Segmentation fault).
 
Sun Nov 18 09:45:31.938 Backtrace:
0xcd1d31 0x6cdae9 0x6ce072 0x7f403e388b80 0xf81587 0xfe0592 0xe7461d 0xdd3002 0xc7a9fa 0xc64a1e 0xc65bea 0x8aa8f9 0x8ab791 0x882286 0x883593 0x884651 0x9e1ca8 0x9e51e0 0x9567dc 0x959043 
 ./mongod(_ZN5mongo15printStackTraceERSo+0x21) [0xcd1d31]
 ./mongod(_ZN5mongo10abruptQuitEi+0x399) [0x6cdae9]
 ./mongod(_ZN5mongo24abruptQuitWithAddrSignalEiP7siginfoPv+0x262) [0x6ce072]
 /lib64/libpthread.so.0(+0x10b80) [0x7f403e388b80]
 ./mongod(_ZN2v88internal10JSReceiver11SetPropertyENS0_6HandleIS1_EENS2_INS0_6StringEEENS2_INS0_6ObjectEEE18PropertyAttributesNS0_14StrictModeFlagE+0x37) [0xf81587]
 ./mongod(_ZN2v88internal7Runtime17SetObjectPropertyEPNS0_7IsolateENS0_6HandleINS0_6ObjectEEES6_S6_18PropertyAttributesNS0_14StrictModeFlagE+0x492) [0xfe0592]
 ./mongod(_ZN2v88internal11SetPropertyENS0_6HandleINS0_6ObjectEEES3_S3_18PropertyAttributesNS0_14StrictModeFlagE+0x5d) [0xe7461d]
 ./mongod(_ZN2v86Object3SetENS_6HandleINS_5ValueEEES3_NS_17PropertyAttributeE+0xf2) [0xdd3002]
 ./mongod(_ZN5mongo7V8Scope10setElementEPKcRKNS_11BSONElementE+0xba) [0xc7a9fa]
 ./mongod(_ZN5mongo5Scope10loadStoredEb+0x40e) [0xc64a1e]
 ./mongod(_ZN5mongo12ScriptEngine14getPooledScopeERKSs+0xea) [0xc65bea]
 ./mongod(_ZN5mongo6dbEvalERKSsRNS_7BSONObjERNS_14BSONObjBuilderERSs+0xa9) [0x8aa8f9]
 ./mongod(_ZN5mongo7CmdEval3runERKSsRNS_7BSONObjEiRSsRNS_14BSONObjBuilderEb+0x231) [0x8ab791]
 ./mongod(_ZN5mongo12_execCommandEPNS_7CommandERKSsRNS_7BSONObjEiRNS_14BSONObjBuilderEb+0x56) [0x882286]
 ./mongod(_ZN5mongo11execCommandEPNS_7CommandERNS_6ClientEiPKcRNS_7BSONObjERNS_14BSONObjBuilderEb+0xde3) [0x883593]
 ./mongod(_ZN5mongo12_runCommandsEPKcRNS_7BSONObjERNS_11_BufBuilderINS_16TrivialAllocatorEEERNS_14BSONObjBuilderEbi+0x2b1) [0x884651]
 ./mongod(_ZN5mongo11runCommandsEPKcRNS_7BSONObjERNS_5CurOpERNS_11_BufBuilderINS_16TrivialAllocatorEEERNS_14BSONObjBuilderEbi+0x38) [0x9e1ca8]
 ./mongod(_ZN5mongo8runQueryERNS_7MessageERNS_12QueryMessageERNS_5CurOpES1_+0xc70) [0x9e51e0]
 ./mongod() [0x9567dc]
 ./mongod(_ZN5mongo16assembleResponseERNS_7MessageERNS_10DbResponseERKNS_11HostAndPortE+0x3a3) [0x959043]



 Comments   
Comment by auto [ 19/Nov/12 ]

Author:

{u'date': u'2012-11-19T12:27:30Z', u'email': u'tad@10gen.com', u'name': u'Tad Marshall'}

Message: SERVER-7705 Test return value from Run() call on assignment

In newFunction() in mongo/scripting/engine_v8.cpp, do not return the
return value from running the compiled assignment statement if it is
empty; return JavaScript 'null' instead.
Branch: master
https://github.com/mongodb/mongo/commit/73d153e44e75197115944b60ab4fca6f7bb6f2d0

Comment by auto [ 19/Nov/12 ]

Author:

{u'date': u'2012-11-19T14:51:23Z', u'email': u'bernie@10gen.com', u'name': u'Bernie Hackett'}

Message: Work around V8 issues in tests.

See SERVER-7705 for details.
Branch: master
https://github.com/mongodb/mongo-python-driver/commit/e0c373038ed07988a4c890c0a507d4293ecaa21d

Comment by Tad Marshall [ 19/Nov/12 ]

The code builds a command to assign the "function" to a variable and checks to see if the assignment command can be compiled, like this:

____MongoToV8_newFunction_temp == baz

It then runs this assignment statement, but it doesn't check that the assigment worked, and returns an empty handle (a handle pointing to NULL, i.e. zero) to the caller to be stored. The code then segfaults when it tries to dereference the empty handle. Returning a handle pointing to the value "null", which is what would happen if the assignment statement could not be compiled, would prevent the segfault.

The error handling it still not as good as what the SpiderMonkey version was doing; it manages to propagate the error ("ReferenceError: baz is not defined") back to the caller, but we can leave that to another ticket.

Generated at Thu Feb 08 03:15:21 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.