| Index: src/trap-handler/trap-handler.cc
|
| diff --git a/src/trap-handler/trap-handler.cc b/src/trap-handler/trap-handler.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2b3a0691d6b35f4a1b5fa781c52a57ef8463c9fc
|
| --- /dev/null
|
| +++ b/src/trap-handler/trap-handler.cc
|
| @@ -0,0 +1,158 @@
|
| +// Copyright 2016 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// PLEASE READ BEFORE CHANGING THIS FILE!
|
| +//
|
| +// This file implements the out of bounds signal handler for
|
| +// WebAssembly. Signal handlers are notoriously difficult to get
|
| +// right, and getting it wrong can lead to security
|
| +// vulnerabilities. In order to minimize this risk, here are some
|
| +// rules to follow.
|
| +//
|
| +// 1. Do not introduce any new external dependencies. This file needs
|
| +// to be self contained so it is easy to audit everything that a
|
| +// signal handler might do.
|
| +//
|
| +// 2. Any changes must be reviewed by someone from the crash reporting
|
| +// or security team.
|
| +
|
| +// This file contains general support code for trap handling, and is mostly
|
| +// used by other parts of V8. For the code that runs in the signal handler
|
| +// itself, see signal-handler.cc.
|
| +
|
| +#include <signal.h>
|
| +#include <stddef.h>
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +
|
| +#include <atomic>
|
| +
|
| +#include "src/flags.h"
|
| +#include "src/trap-handler/trap-handler-internal.h"
|
| +#include "src/trap-handler/trap-handler.h"
|
| +
|
| +#define TRACE(...)
|
| +// #define TRACE(...) fprintf(stderr, __VA_ARGS__)
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace trap_handler {
|
| +
|
| +__thread bool gThreadInWasmCode = false;
|
| +
|
| +const size_t kInitialCodeObjectSize = 1024;
|
| +const size_t kCodeObjectGrowthFactor = 2;
|
| +size_t gNumCodeObjects = 0;
|
| +CodeObjectData **gCodeObjects = nullptr;
|
| +
|
| +std::atomic_flag MetadataLock::spinlock_ = ATOMIC_FLAG_INIT;
|
| +
|
| +constexpr size_t HandlerDataSize(size_t num_protected_instructions) {
|
| + return sizeof(CodeObjectData) +
|
| + num_protected_instructions * sizeof(ProtectedInstructionData);
|
| +}
|
| +
|
| +CodeObjectData *CreateHandlerData(
|
| + void *base, size_t size, size_t num_protected_instructions,
|
| + ProtectedInstructionData *protected_instructions) {
|
| + const size_t alloc_size = HandlerDataSize(num_protected_instructions);
|
| + CodeObjectData *data = reinterpret_cast<CodeObjectData *>(malloc(alloc_size));
|
| +
|
| + if (data == nullptr) {
|
| + return nullptr;
|
| + }
|
| +
|
| + data->base = base;
|
| + data->size = size;
|
| + data->num_protected_instructions = num_protected_instructions;
|
| +
|
| + memcpy(data->instructions, protected_instructions,
|
| + num_protected_instructions * sizeof(ProtectedInstructionData));
|
| +
|
| + return data;
|
| +}
|
| +
|
| +CodeObjectData *CloneHandlerData(CodeObjectData *data) {
|
| + const size_t alloc_size = HandlerDataSize(data->num_protected_instructions);
|
| + CodeObjectData *new_data =
|
| + reinterpret_cast<CodeObjectData *>(malloc(alloc_size));
|
| +
|
| + memcpy(new_data, data, alloc_size);
|
| + return new_data;
|
| +}
|
| +
|
| +void UpdateCodePointer(int index, void *base) {
|
| + MetadataLock _;
|
| + CodeObjectData *data = gCodeObjects[index];
|
| + data->base = base;
|
| +}
|
| +
|
| +int RegisterHandlerData(CodeObjectData *data) {
|
| + // TODO(eholk): in debug builds, make sure this data isn't already registered.
|
| + MetadataLock _;
|
| +
|
| + size_t i;
|
| + for (i = 0; i < gNumCodeObjects; ++i) {
|
| + if (gCodeObjects[i] == nullptr) {
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // We didn't find an opening in the available space, so grow.
|
| + if (i == gNumCodeObjects) {
|
| + size_t new_size = gNumCodeObjects > 0
|
| + ? gNumCodeObjects * kCodeObjectGrowthFactor
|
| + : kInitialCodeObjectSize;
|
| + gCodeObjects = static_cast<CodeObjectData **>(
|
| + realloc(gCodeObjects, sizeof(*gCodeObjects) * new_size));
|
| +
|
| + if (gCodeObjects == nullptr) {
|
| + return -1;
|
| + }
|
| +
|
| + memset(gCodeObjects + gNumCodeObjects, 0,
|
| + sizeof(*gCodeObjects) * (new_size - gNumCodeObjects));
|
| + gNumCodeObjects = new_size;
|
| + }
|
| +
|
| + gCodeObjects[i] = data;
|
| + TRACE("Registered handler data %p at index %d\n", data, i);
|
| + return static_cast<int>(i);
|
| +}
|
| +
|
| +void ReleaseHandlerData(int index) {
|
| + // Remove the data from the global list if it's there.
|
| +
|
| + MetadataLock _;
|
| +
|
| + CodeObjectData *data = gCodeObjects[index];
|
| + gCodeObjects[index] = nullptr;
|
| +
|
| + TRACE("Released handler data %p at index %d\n", data, index);
|
| +
|
| + // TODO(eholk): on debug builds, ensure there are no more copies in
|
| + // the list.
|
| + free(data);
|
| +}
|
| +
|
| +void SetThreadInWasm() {
|
| + TRACE("Transitioning to Wasm\n");
|
| + gThreadInWasmCode = true;
|
| +}
|
| +
|
| +void ClearThreadInWasm() {
|
| + TRACE("Transitioning from Wasm\n");
|
| + gThreadInWasmCode = false;
|
| +}
|
| +
|
| +bool IsThreadInWasm() { return gThreadInWasmCode; }
|
| +
|
| +bool EnableTrapHandler() {
|
| + return FLAG_wasm_trap_handler && kTrapHandlerSupported;
|
| +}
|
| +
|
| +} // namespace trap_handler
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|