v8 - Сбой в HeapObject :: GetHeap () - неинициализированное значение

0

Из JS я вызываю функцию C++ следующим образом:

var req = new IO.HttpRequest(IO.RequestType.get);
req.data({ i: 'jTKvNf9w' }).send('http://pastebin.com/raw.php', function (content) { console.log(content); });

Запрос обрабатывается асинхронно, и после его завершения обращается вызов. В C++ функция отправки выглядит так:

void XmlHttpRequest::open(const Utils::String& str, ::JS::FunctionObjPtr callback) {
    mCallback = callback;
    mRequest->open(str);
}

И позже, если запрос будет завершен:

void XmlHttpRequest::onComplete(Utils::String content) {
    sUIMgr->getDispatcher()->pushFrame(Gl::Dispatcher::Priority::Low, [this, content]() {
        ::JS::FunctionObjPtr f = mCallback;
        f->callVoid(content);
    });
}

Рамка push помещает функцию в очередь для выполнения в основном потоке, где настроены все сценарии.

Теперь проблема в callVoid Я получаю нарушение прав доступа, когда HeapObject :: GetHeap() вызывает MemoryChunk::FromAddress(reinterpret_cast<Address>(this))->heap(); , Это функции v8. Проблема в том, что this -Pointer в HeapObject равен 0xCCCCCCCC, что означает его неинициализированное значение. this -Pointer происходит от ручки, хранящейся в JS :: FunctionObjPtr (ЬурейаЯ для станд :: shared_ptr).

Сначала я думал, что с моим FunctionObj что-то не так. Я получаю это:

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);
}

TYPE_RET просто выполняет некоторые метапрограммирование шаблонов. Функция FunctionObj выглядит так:

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());
        }
    }
};

Когда я вызываю функцию в XmlHttpRequest::open где ее "зарегистрировано", она работает. Поэтому сначала я думал, что объект получает gc'ed, но для того, чтобы убедиться, что он никогда не будет собран в FunctionObj :: FunctionObj, я создал v8 :: Persistent из дескриптора. Тем не менее он падает. Я даже сделал v8 :: Persistent слабым, чтобы посмотреть, действительно ли он собирается, но слабый callback никогда не вызван.

Другие вещи, которые я проверил прямо перед вызовом:

  1. v8 :: Изоляция :: GetCurrent() → Возвращает правильный, введенный изолятор
  2. v8 :: Контекст :: GetCurrent() → Тот же
  3. Глобальный HandleScope не оставлен
  4. XmlHttpRequest :: open и лямбда с вызовом вызываются в том же потоке

Дополнительная информация: это не ограничивается только v8 :: Handle <v8 :: Function>. Это также происходит, если я попытаюсь сохранить объект и позже получить доступ к его свойствам. Я просто наклоняюсь к чему-либо внутри этой лямбды, которая использует ручку.

  • 0
    Не знаю, поможет ли это, но если вы храните объект и хотите получить доступ к его свойствам позже, попробуйте использовать тип постоянного указателя. например, Persistent <Object> module_handle = Persistent <Object> :: New (target);
  • 0
    Это помогло. Это не было непосредственно причиной проблемы напрямую (поскольку я уже пытался найти устойчивое решение), но это заставляло меня идти по постоянному пути, который был правильным путем, см. Мой ответ.
Теги:
v8

1 ответ

0

Как я уже сказал в том, что я пробовал, я посмотрел на v8::Persistent. Оказывается, я использовал это неправильно.

Что я сделал:

class FunctionObj
{
    v8::Handle<v8::Value> mHandle;
    v8::Persistent<v8::Value> mPersistent;
public:
    FunctionObj(v8::Handle<v8::Value>& fun) {
        mPersistent.Reset(v8::Isolate::GetCurrent(), 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());
        }
    }
};

Что я должен был сделать

class FunctionObj
{
    v8::Persistent<v8::Value> mPersistent;
public:
    FunctionObj(v8::Handle<v8::Value>& fun) {
        mPersistent.Reset(v8::Isolate::GetCurrent(), fun);
    }

    FunctionObj() { if(mPersistent) { mPersistent.Dispose(); } }

    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::Local<v8::Function> fun = v8::Local<v8::Function>::New(v8::Isolate::GetCurrent(), mPersistent.As<v8::Function>());

        v8::TryCatch tc;
        fun->Call(fun, arguments.size(), arguments.data());
        if (tc.HasCaught()) {
            throw JS::Exception(tc.Exception(), tc.StackTrace());
        }
    }
};

Постоянное я создал не означает, что хранимый мной дескриптор не уничтожается, а только то, что позже будет возможно запросить новый дескриптор объекта и что объект не будет удален.

Теперь все работает как шарм!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню