1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86

android_webview / js_sandbox / service / js_sandbox_array_buffer_allocator.h [blame]

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ARRAY_BUFFER_ALLOCATOR_H_
#define ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ARRAY_BUFFER_ALLOCATOR_H_

#include <cstddef>

#include "base/memory/raw_ref.h"
#include "v8/include/v8-array-buffer.h"

namespace android_webview {

// A v8::ArrayBuffer::Allocator which imposes a limit on the amount of
// simultaneously allocated memory. See also the V8 documentation for
// v8::ArrayBuffer::Allocator.
//
// This allocator must only be used from one thread at a time. Allocation and
// deallocation methods should only happen on the isolate thread, but
// construction and destruction will typically happen outside of the isolate
// thread.
class JsSandboxArrayBufferAllocator final : public v8::ArrayBuffer::Allocator {
 public:
  // Value to supply as a budget to indicate an unlimited budget.
  static constexpr size_t kUnlimitedBudget = SIZE_MAX;

  // Wrap the given inner allocator and impose a maximum allocation budget.
  //
  // The JsSandboxArrayBufferAllocator allocator does NOT assume ownership of or
  // copy the inner allocator, so the caller must ensure that it outlives the
  // JsSandboxArrayBufferAllocator.
  //
  // The memory budget specifies the maximum amount of memory which can be
  // allocated at any given time. Note that a value of 0 will disallow all
  // allocations. Use kUnlimitedBudget if you want no effective limit.
  //
  // The page size should desribe the page size of the allocator used (this is
  // not necessarily the OS page size), and is used to (pessimistically) account
  // for possible internal memory fragmentation in the budget.
  explicit JsSandboxArrayBufferAllocator(v8::ArrayBuffer::Allocator& inner,
                                         size_t memory_budget,
                                         size_t page_size);
  JsSandboxArrayBufferAllocator(const JsSandboxArrayBufferAllocator&) = delete;
  JsSandboxArrayBufferAllocator& operator=(
      const JsSandboxArrayBufferAllocator&) = delete;
  // All prior allocations must be freed before the allocator is destructed.
  ~JsSandboxArrayBufferAllocator() override;
  // Attempt to allocate length bytes (zero-initialized).
  //
  // The tracked memory usage may be rounded up to a multiple of the page size.
  //
  // nullptr will be returned if the request exceeds the memory budget or the
  // inner allocator returns nullptr.
  void* Allocate(size_t length) override;
  // Similar to Allocate(), but does not explicitly zero-(re)initialize memory
  // in userspace.
  void* AllocateUninitialized(size_t length) override;
  // Deallocate a currently allocated memory region that was previously returned
  // by Allocate.
  //
  // The length must match the current length associated with the region.
  void Free(void* data, size_t length) override;

  // Return the amount of allocated (used) memory budget.
  size_t GetUsage() const;

 private:
  // Try to allocate some budget and return true iff successful
  bool AllocateBudget(size_t amount);
  // Deallocate some budget
  void FreeBudget(size_t amount);

  // The underlying allocator which does the actual memory management.
  const raw_ref<v8::ArrayBuffer::Allocator> inner_allocator_;
  // The amount of unused budget
  size_t remaining_;
  // The overall memory budget this allocator has to stay within
  const size_t budget_;
  // Page size for rounding up allocation amounts.
  const size_t page_size_;
};

}  // namespace android_webview

#endif  // ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ARRAY_BUFFER_ALLOCATOR_H_