LCOV - code coverage report
Current view: top level - src/trap-handler - handler-outside.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 50 56 89.3 %
Date: 2019-02-19 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : // PLEASE READ BEFORE CHANGING THIS FILE!
       6             : //
       7             : // This file implements the support code for the out of bounds trap handler.
       8             : // Nothing in here actually runs in the trap handler, but the code here
       9             : // manipulates data structures used by the trap handler so we still need to be
      10             : // careful. In order to minimize this risk, here are some rules to follow.
      11             : //
      12             : // 1. Avoid introducing new external dependencies. The files in src/trap-handler
      13             : //    should be as self-contained as possible to make it easy to audit the code.
      14             : //
      15             : // 2. Any changes must be reviewed by someone from the crash reporting
      16             : //    or security team. See OWNERS for suggested reviewers.
      17             : //
      18             : // For more information, see https://goo.gl/yMeyUY.
      19             : //
      20             : // For the code that runs in the trap handler itself, see handler-inside.cc.
      21             : 
      22             : #include <stddef.h>
      23             : #include <stdio.h>
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : 
      27             : #include <atomic>
      28             : #include <limits>
      29             : 
      30             : #include "src/trap-handler/trap-handler-internal.h"
      31             : #include "src/trap-handler/trap-handler.h"
      32             : 
      33             : namespace {
      34             : size_t gNextCodeObject = 0;
      35             : 
      36             : #ifdef ENABLE_SLOW_DCHECKS
      37             : constexpr bool kEnableSlowChecks = true;
      38             : #else
      39             : constexpr bool kEnableSlowChecks = false;
      40             : #endif
      41             : }
      42             : 
      43             : namespace v8 {
      44             : namespace internal {
      45             : namespace trap_handler {
      46             : 
      47             : constexpr size_t kInitialCodeObjectSize = 1024;
      48             : constexpr size_t kCodeObjectGrowthFactor = 2;
      49             : 
      50             : constexpr size_t HandlerDataSize(size_t num_protected_instructions) {
      51       68427 :   return offsetof(CodeProtectionInfo, instructions) +
      52       68427 :          num_protected_instructions * sizeof(ProtectedInstructionData);
      53             : }
      54             : 
      55             : namespace {
      56             : #ifdef DEBUG
      57             : bool IsDisjoint(const CodeProtectionInfo* a, const CodeProtectionInfo* b) {
      58             :   if (a == nullptr || b == nullptr) {
      59             :     return true;
      60             :   }
      61             :   return a->base >= b->base + b->size || b->base >= a->base + a->size;
      62             : }
      63             : #endif
      64             : 
      65             : // Verify that the code range does not overlap any that have already been
      66             : // registered.
      67             : void VerifyCodeRangeIsDisjoint(const CodeProtectionInfo* code_info) {
      68             :   for (size_t i = 0; i < gNumCodeObjects; ++i) {
      69             :     DCHECK(IsDisjoint(code_info, gCodeObjects[i].code_info));
      70             :   }
      71             : }
      72             : 
      73             : void ValidateCodeObjects() {
      74             :   // Sanity-check the code objects
      75             :   for (unsigned i = 0; i < gNumCodeObjects; ++i) {
      76             :     const auto* data = gCodeObjects[i].code_info;
      77             : 
      78             :     if (data == nullptr) continue;
      79             : 
      80             :     // Do some sanity checks on the protected instruction data
      81             :     for (unsigned i = 0; i < data->num_protected_instructions; ++i) {
      82             :       DCHECK_GE(data->instructions[i].instr_offset, 0);
      83             :       DCHECK_LT(data->instructions[i].instr_offset, data->size);
      84             :       DCHECK_GE(data->instructions[i].landing_offset, 0);
      85             :       DCHECK_LT(data->instructions[i].landing_offset, data->size);
      86             :       DCHECK_GT(data->instructions[i].landing_offset,
      87             :                 data->instructions[i].instr_offset);
      88             :     }
      89             :   }
      90             : 
      91             :   // Check the validity of the free list.
      92             :   size_t free_count = 0;
      93             :   for (size_t i = gNextCodeObject; i != gNumCodeObjects;
      94             :        i = gCodeObjects[i].next_free) {
      95             :     DCHECK_LT(i, gNumCodeObjects);
      96             :     ++free_count;
      97             :     // This check will fail if we encounter a cycle.
      98             :     DCHECK_LE(free_count, gNumCodeObjects);
      99             :   }
     100             : 
     101             :   // Check that all free entries are reachable via the free list.
     102             :   size_t free_count2 = 0;
     103             :   for (size_t i = 0; i < gNumCodeObjects; ++i) {
     104             :     if (gCodeObjects[i].code_info == nullptr) {
     105             :       ++free_count2;
     106             :     }
     107             :   }
     108             :   DCHECK_EQ(free_count, free_count2);
     109             : }
     110             : }  // namespace
     111             : 
     112       68427 : CodeProtectionInfo* CreateHandlerData(
     113             :     Address base, size_t size, size_t num_protected_instructions,
     114             :     const ProtectedInstructionData* protected_instructions) {
     115             :   const size_t alloc_size = HandlerDataSize(num_protected_instructions);
     116             :   CodeProtectionInfo* data =
     117       68427 :       reinterpret_cast<CodeProtectionInfo*>(malloc(alloc_size));
     118             : 
     119       68427 :   if (data == nullptr) {
     120             :     return nullptr;
     121             :   }
     122             : 
     123       68427 :   data->base = base;
     124       68427 :   data->size = size;
     125       68427 :   data->num_protected_instructions = num_protected_instructions;
     126             : 
     127             :   memcpy(data->instructions, protected_instructions,
     128       68427 :          num_protected_instructions * sizeof(ProtectedInstructionData));
     129             : 
     130       68427 :   return data;
     131             : }
     132             : 
     133       68427 : int RegisterHandlerData(
     134             :     Address base, size_t size, size_t num_protected_instructions,
     135             :     const ProtectedInstructionData* protected_instructions) {
     136             : 
     137             :   CodeProtectionInfo* data = CreateHandlerData(
     138       68427 :       base, size, num_protected_instructions, protected_instructions);
     139             : 
     140       68427 :   if (data == nullptr) {
     141           0 :     abort();
     142             :   }
     143             : 
     144       68427 :   MetadataLock lock;
     145             : 
     146             :   if (kEnableSlowChecks) {
     147             :     VerifyCodeRangeIsDisjoint(data);
     148             :   }
     149             : 
     150       68427 :   size_t i = gNextCodeObject;
     151             : 
     152             :   // Explicitly convert std::numeric_limits<int>::max() to unsigned to avoid
     153             :   // compiler warnings about signed/unsigned comparisons. We aren't worried
     154             :   // about sign extension because we know std::numeric_limits<int>::max() is
     155             :   // positive.
     156             :   const size_t int_max = std::numeric_limits<int>::max();
     157             : 
     158             :   // We didn't find an opening in the available space, so grow.
     159       68427 :   if (i == gNumCodeObjects) {
     160             :     size_t new_size = gNumCodeObjects > 0
     161             :                           ? gNumCodeObjects * kCodeObjectGrowthFactor
     162         982 :                           : kInitialCodeObjectSize;
     163             : 
     164             :     // Because we must return an int, there is no point in allocating space for
     165             :     // more objects than can fit in an int.
     166         982 :     if (new_size > int_max) {
     167             :       new_size = int_max;
     168             :     }
     169         982 :     if (new_size == gNumCodeObjects) {
     170           0 :       free(data);
     171           0 :       return kInvalidIndex;
     172             :     }
     173             : 
     174             :     // Now that we know our new size is valid, we can go ahead and realloc the
     175             :     // array.
     176             :     gCodeObjects = static_cast<CodeProtectionInfoListEntry*>(
     177         982 :         realloc(gCodeObjects, sizeof(*gCodeObjects) * new_size));
     178             : 
     179         982 :     if (gCodeObjects == nullptr) {
     180           0 :       abort();
     181             :     }
     182             : 
     183         982 :     memset(gCodeObjects + gNumCodeObjects, 0,
     184         982 :            sizeof(*gCodeObjects) * (new_size - gNumCodeObjects));
     185     1015724 :     for (size_t j = gNumCodeObjects; j < new_size; ++j) {
     186     1013760 :       gCodeObjects[j].next_free = j + 1;
     187             :     }
     188         982 :     gNumCodeObjects = new_size;
     189             :   }
     190             : 
     191             :   DCHECK(gCodeObjects[i].code_info == nullptr);
     192             : 
     193             :   // Find out where the next entry should go.
     194       68427 :   gNextCodeObject = gCodeObjects[i].next_free;
     195             : 
     196       68427 :   if (i <= int_max) {
     197       68427 :     gCodeObjects[i].code_info = data;
     198             : 
     199             :     if (kEnableSlowChecks) {
     200             :       ValidateCodeObjects();
     201             :     }
     202             : 
     203       68427 :     return static_cast<int>(i);
     204             :   } else {
     205           0 :     free(data);
     206           0 :     return kInvalidIndex;
     207       68427 :   }
     208             : }
     209             : 
     210       68417 : void ReleaseHandlerData(int index) {
     211       68417 :   if (index == kInvalidIndex) {
     212       68417 :     return;
     213             :   }
     214             :   DCHECK_GE(index, 0);
     215             : 
     216             :   // Remove the data from the global list if it's there.
     217             :   CodeProtectionInfo* data = nullptr;
     218             :   {
     219       68417 :     MetadataLock lock;
     220             : 
     221       68417 :     data = gCodeObjects[index].code_info;
     222       68417 :     gCodeObjects[index].code_info = nullptr;
     223             : 
     224       68417 :     gCodeObjects[index].next_free = gNextCodeObject;
     225       68417 :     gNextCodeObject = index;
     226             : 
     227             :     if (kEnableSlowChecks) {
     228             :       ValidateCodeObjects();
     229       68417 :     }
     230             :   }
     231             :   // TODO(eholk): on debug builds, ensure there are no more copies in
     232             :   // the list.
     233             :   DCHECK_NOT_NULL(data);  // make sure we're releasing legitimate handler data.
     234       68417 :   free(data);
     235             : }
     236             : 
     237       84476 : int* GetThreadInWasmThreadLocalAddress() { return &g_thread_in_wasm_code; }
     238             : 
     239       16032 : size_t GetRecoveredTrapCount() {
     240       16032 :   return gRecoveredTrapCount.load(std::memory_order_relaxed);
     241             : }
     242             : 
     243             : #if !V8_TRAP_HANDLER_SUPPORTED
     244             : // This version is provided for systems that do not support trap handlers.
     245             : // Otherwise, the correct one should be implemented in the appropriate
     246             : // platform-specific handler-outside.cc.
     247             : bool RegisterDefaultTrapHandler() { return false; }
     248             : 
     249             : void RemoveTrapHandler() {}
     250             : #endif
     251             : 
     252             : bool g_is_trap_handler_enabled;
     253             : 
     254       55426 : bool EnableTrapHandler(bool use_v8_handler) {
     255             :   if (!V8_TRAP_HANDLER_SUPPORTED) {
     256             :     return false;
     257             :   }
     258       55426 :   if (use_v8_handler) {
     259       55420 :     g_is_trap_handler_enabled = RegisterDefaultTrapHandler();
     260       55420 :     return g_is_trap_handler_enabled;
     261             :   }
     262           6 :   g_is_trap_handler_enabled = true;
     263           6 :   return true;
     264             : }
     265             : 
     266             : }  // namespace trap_handler
     267             : }  // namespace internal
     268             : }  // namespace v8

Generated by: LCOV version 1.10