On Fri, Apr 4, 2014 at 10:40 AM, Muazin Mugadr <[email protected]> wrote: > Hello all > > I am using my wrapper for embedding v8 into my application. I automated all > parameter parsing and so on and so far everything worked fine. But now i > have a problem. I have the following JS-Code: > > var req = new IO.HttpRequest(IO.RequestType.get); > req.data({ i: 'jTKvNf9w' }).send('http://pastebin.com/raw.php', function > (content) { console.log(content); }); > > This is mapped to my XmlHttpRequest-class in C++ and the send-function looks > like this: > void XmlHttpRequest::open(const Utils::String& str, ::JS::FunctionObjPtr > callback) { > mCallback = callback; > mRequest->open(str); > } > > First lets have a look at JS::FunctionObj (the Ptr is just because its a > typedef for a std::shared_ptr): > class FunctionObj > { > v8::Handle<v8::Value> mHandle; > > public: > FunctionObj(v8::Handle<v8::Value>& fun) { > mHandle = fun; > } > > FunctionObj() { } > > operator bool () { > return mHandle.IsEmpty() == false; > } > > template<typename... Args> > void callVoid(const Args&... args) { > std::vector<v8::Handle<v8::Value>> arguments; > addArgument(arguments, args...); > > v8::TryCatch tc; > v8::Handle<v8::Function>::Cast(mHandle)->Call(mHandle, arguments.size(), > arguments.data()); > if (tc.HasCaught()) { > throw JS::Exception(tc.Exception(), tc.StackTrace()); > } > } > }; > > And how i get there from the callback for the function. The argument gets > unwrapped from the FunctionCallbackInfo in the following way: > template<uint32 index, typename T, typename... Rem, typename... CurArgs> > void expand(const v8::FunctionCallbackInfo<v8::Value>& args, const > CurArgs&... curArgs) { > v8::TryCatch tc; > T arg = ObjectWrap::unwrap<typename std::remove_cv<typename > std::remove_reference<T>::type>::type>(args[index]); > if (tc.HasCaught()) { > tc.ReThrow(); > return; > } > > expand<index + 1, Rem...>(args, curArgs..., arg); > } > > In this case T would be ::JS::FunctionObjPtr. ObjectWrap::unwrap for the > template FunctionObjPtr looks like this: > template<typename T> > static TYPE_RET(FunctionObjPtr) ObjectWrap::unwrap(v8::Handle<v8::Value>& > value) { > if (value->IsFunction() == false) { > TYPE_ERR("Value is not a function"); > } > > return std::make_shared<FunctionObj>(value); > } > > The TYPE_RET is merely some template metaprogramming stuff. > > Ok, once im in XmlHttpRequest::send i can call the callback as many times as > id like to, it allways works. But the http request is processed in a > background thread and once its complete the following function gets called: > void XmlHttpRequest::onComplete(Utils::String content) { > sUIMgr->getDispatcher()->pushFrame(Gl::Dispatcher::Priority::Low, [this, > content]() { > ::JS::FunctionObjPtr f = mCallback; > f->callVoid(content); > }); > } > > The pushFrame function enqueues the lambda and calls it later in the main > thread. And here it happens. I get an access violation on the following > line: > inline Heap* heap() { return heap_; } > > And the callstack: > v8::internal::HeapObject::GetHeap() Line 1173 C++ > v8::internal::HeapObject::GetIsolate() Line 1180 C++ > v8::Function::Call(v8::Handle<v8::Value> recv, int argc, > v8::Handle<v8::Value> * argv) Line 4175 C++ > JS::FunctionObj::callVoid<Utils::String>(const Utils::String & <args_0>) > Line 58 C++ > UI::JS::XmlHttpRequest::onComplete::__l3::<lambda>() Line 24 C++ > > After a bit of debugging i have seen that in > v8::internal::HeapObject::GetHeap the this-pointer of HeapObject is > 0xCCCCCCCC. I have investigated the following lines in the source code: > Local<v8::Value> Function::Call(v8::Handle<v8::Value> recv, int argc, > v8::Handle<v8::Value> argv[]) { > i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); > > this is correct, its the actual value in the handle. > > #define MAKE_OPEN_HANDLE(From, To) > \ > v8::internal::Handle<v8::internal::To> Utils::OpenHandle( > \ > const v8::From* that, bool allow_empty_handle) { > \ > EXTRA_CHECK(allow_empty_handle || that != NULL); > \ > EXTRA_CHECK(that == NULL || > \ > !(*reinterpret_cast<v8::internal::To**>( > \ > const_cast<v8::From*>(that)))->IsFailure()); > \ > return v8::internal::Handle<v8::internal::To>( > \ > reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); > \ > } > > with From being v8::Function and To being v8::internal::JSFunction. that is > correct, but here: > (*reinterpret_cast<v8::internal::To**>( \ > const_cast<v8::From*>(that)))->IsFailure()) > > in IsFailure this is 0xCCCCCCCC. That means that *(JSFunction**)that was > 0xCCCCCCCC. I can confirm this here: > ::JS::FunctionObjPtr f = mCallback; > auto handle = f->getHandle(); > auto fObj = v8::Handle<v8::Function>::Cast(handle).operator*(); > void* ptr = *(void**) fObj; > > ptr is 0xCCCCCCCC. in Visual Studio this means that its an uninitialized > stack value. > > What have I tried? > 1. Creating a persistent in the constructor of FunctionObj -> No change > 2. Setting a WeakCallback to the Persistent in FunctionObj to see if it gets > GC'ed -> Not called > 3. Using an object instead of a function and trying to call a method from > the object -> Same crash as soon as I try to query a property from the > object > 4. Running a new script (unrelated to the callback) -> All fine (so context, > isolate, handlescope, ... are all still valid) > 5. Calling a function from the global context -> Works > > The only thing that seems to be impossible is passing a value from JS to C++ > and then later call it. > > Greetings > Cromon
The mHandle member of your FunctionObj class needs to be a Persistent<Function> if it's going to outlive the HandleScope that it was created in. Apropos the bool operator overload, that is something that can come back to bite you, see [1]. [1] http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool -- -- v8-users mailing list [email protected] http://groups.google.com/group/v8-users --- You received this message because you are subscribed to the Google Groups "v8-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
