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.

Reply via email to