Можно ли подделать / взломать Thread Local Storage? - PullRequest
4 голосов
/ 27 октября 2011

Я нахожусь в некотором затруднении.

У меня есть большое приложение с движком Google V8 javascript. Некоторые вызовы выполняются движку V8 в потоке пользовательского интерфейса. Чтобы быть добрым к пользователю, как все рекомендуют, некоторые длинные операции выполняются в отдельном потоке, без зависания потока пользовательского интерфейса. Тем не менее, эти длительные операции также вызывают обращения к движку JavaScript V8. Таким образом, несколько потоков вызывают V8.

Дело в том, что V8 использует локальное хранилище потоков. Это, кажется, заставляет мое приложение взорваться случайным образом. Это определенно в классе "Как это возможно работало до сих пор?" ошибки.

Без значительного изменения архитектуры моего приложения я предлагаю ужасный, ужасный и ужасный супер-хак: могу ли я заставить V8 думать, что он работает в другом потоке?

Другими словами, когда я впервые звоню в V8, я записываю ветку. Затем для всех других вызовов V8 я каким-то образом подделываю поток, чтобы локальное хранилище потока / все остальное, зависящее от потока, работало.

Можно ли это сделать? Это будет работать? Разве я глуп, чтобы даже подумать о таком подонке?

Ответы [ 2 ]

19 голосов
/ 28 октября 2011

Вы не должны ничего обманывать. Вместо этого вы должны сказать V8, что вы пытаетесь использовать его из другого потока.

В V8 до версии 3.2 единственный способ сделать это - использовать v8::Locker перед использованием V8 из другого потока. Он гарантирует как исключительный доступ к V8, так и инициализирует внутренние структуры, хранящиеся в TLS. Подробнее см. http://code.google.com/p/v8/source/browse/branches/3.1/include/v8.h#3189

Начиная с версии 3.2 V8 имеет концепцию isolate . Если вы не создаете изоляты явно, V8 неявно создает изолятор по умолчанию для обеспечения совместимости API. В этом случае вы все равно можете просто использовать v8::Locker как в более старых версиях. Если вы создаете изоляты явно, то в дополнение к получению монопольного доступа с помощью v8::Locker вы также должны явно вводить и выходить из них в своих потоках, используя методы v8::Isolate::Enter / v8::Isolate::Exit или v8::Isolate::Scope. Для получения более подробной информации см http://code.google.com/p/v8/source/browse/trunk/include/v8.h#3510

Итак, простой ответ, который будет работать в большинстве случаев: используйте v8::Locker перед использованием V8 из другого потока.

1 голос
/ 28 октября 2011

У меня была такая же проблема, и мне удалось частично найти решение через эту ветку.Чтобы уточнить ответ VE, вы не можете использовать v8 из нескольких потоков по умолчанию.Если вы хотите, вы должны использовать изоляты и замки.

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

  1. Создайте свой собственный v8::Isolate.Вы можете сделать это глобальным, но (насколько я понимаю) он не может быть стандартным (потому что стандартный уже находится в введенном состоянии).

  2. Во всех ваших функциях, которые вызывают v8 (и не обязательно являются внутренними), вы должны ввести свой изолят (используйте v8::Isolate::Scope) и

  3. также используют объекты 'v8 :: Locker'.

Я написал небольшой вспомогательный объект, который я использую в своих открытых методах, и он выглядит примерно так:

class SessionLock {
private:
    v8::Isolate::Scope scope;
    v8::Locker lock;

public:
    SessionLock() : scope(getSessionIsolate()), lock(getSessionIsolate()) {}
};
...