File: script_forbidden_scope.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (150 lines) | stat: -rw-r--r-- 5,104 bytes parent folder | download | duplicates (5)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_SCRIPT_FORBIDDEN_SCOPE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_SCRIPT_FORBIDDEN_SCOPE_H_

#include <optional>

#include "base/auto_reset.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/stack_util.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"

namespace blink {

class BlinkLifecycleScopeWillBeScriptForbidden;

// Scoped disabling of script execution.
class PLATFORM_EXPORT ScriptForbiddenScope final {
  STACK_ALLOCATED();

 public:
  ScriptForbiddenScope() { Enter(); }
  ScriptForbiddenScope(const ScriptForbiddenScope&) = delete;
  ScriptForbiddenScope& operator=(const ScriptForbiddenScope&) = delete;
  ~ScriptForbiddenScope() { Exit(); }

  class PLATFORM_EXPORT AllowUserAgentScript final {
    STACK_ALLOCATED();

   public:
    AllowUserAgentScript() : saved_counter_(&GetMutableCounter(), 0) {
      if (IsMainThread()) [[likely]] {
        saved_blink_counter_.emplace(&g_blink_lifecycle_counter_, 0);
      }
    }
    AllowUserAgentScript(const AllowUserAgentScript&) = delete;
    AllowUserAgentScript& operator=(const AllowUserAgentScript&) = delete;
    ~AllowUserAgentScript() { DCHECK(!IsScriptForbidden()); }

   private:
    base::AutoReset<unsigned> saved_counter_;
    std::optional<base::AutoReset<unsigned>> saved_blink_counter_;
  };

  static bool IsScriptForbidden() {
#if DCHECK_IS_ON()
    bool extended_check = true;
#else
    bool extended_check =
        RuntimeEnabledFeatures::BlinkLifecycleScriptForbiddenEnabled();
#endif

    if (extended_check && WillBeScriptForbidden()) {
      return true;
    }
    if (!WTF::MayNotBeMainThread()) [[likely]] {
      return g_main_thread_counter_ > 0;
    }
    return GetMutableCounter() > 0;
  }

  // Returns whether we are in a blink lifecycle scope. This should be checked
  // from any location in which we are about to run potentially arbitrary
  // script. It is not safe to run script during the blink lifecycle unless
  // we either check whether it dirtied anything and rerun style/layout, or,
  // can guarantee that script cannot dirty style / layout (e.g. worklet
  // scopes). Use AllowUserAgentScript to annotate known safe points to run
  // script.
  // TODO(crbug.com/1196853): Remove this once we have discovered and fixed
  // sources of attempted script execution during blink lifecycle.
  static bool WillBeScriptForbidden() {
    if (IsMainThread()) [[likely]] {
      return g_blink_lifecycle_counter_ > 0;
    }
    // Blink lifecycle scope is never entered on other threads.
    return false;
  }

  static void ThrowScriptForbiddenException(v8::Isolate* isolate) {
    V8ThrowException::ThrowError(isolate, "Script execution is forbidden.");
  }

 private:
  static void Enter() {
    if (!WTF::MayNotBeMainThread()) [[likely]] {
      ++g_main_thread_counter_;
    } else {
      ++GetMutableCounter();
    }
  }
  static void Exit() {
    DCHECK(IsScriptForbidden());
    if (!WTF::MayNotBeMainThread()) [[likely]] {
      --g_main_thread_counter_;
    } else {
      --GetMutableCounter();
    }
  }

  static void EnterBlinkLifecycle() {
    DCHECK(IsMainThread());
    ++g_blink_lifecycle_counter_;
  }
  static void ExitBlinkLifecycle() {
    DCHECK(IsMainThread());
    --g_blink_lifecycle_counter_;
  }

  static unsigned& GetMutableCounter();

  static unsigned g_main_thread_counter_;

  // TODO(https://crbug.com/1196853): Remove once
  // BlinkLifecycleScopeWillBeScriptForbidden can be removed.
  static unsigned g_blink_lifecycle_counter_;

  // V8GCController is exceptionally allowed to call Enter/Exit.
  friend class V8GCController;
  friend class BlinkLifecycleScopeWillBeScriptForbidden;
};

// Temporarily separate class for identifying cases in which adding a script
// forbidden scope to the blink lifecycle update is causing operations to
// be skipped leading to crashes, see https://crbug.com/1196853.
// TODO(https://crbug.com/1196853): Remove this class and use
// ScriptForbiddenScope once failures are fixed.
class PLATFORM_EXPORT BlinkLifecycleScopeWillBeScriptForbidden final {
  STACK_ALLOCATED();

 public:
  BlinkLifecycleScopeWillBeScriptForbidden() {
    ScriptForbiddenScope::EnterBlinkLifecycle();
  }
  BlinkLifecycleScopeWillBeScriptForbidden(
      const BlinkLifecycleScopeWillBeScriptForbidden&) = delete;
  BlinkLifecycleScopeWillBeScriptForbidden& operator=(
      const BlinkLifecycleScopeWillBeScriptForbidden&) = delete;
  ~BlinkLifecycleScopeWillBeScriptForbidden() {
    ScriptForbiddenScope::ExitBlinkLifecycle();
  }
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_SCRIPT_FORBIDDEN_SCOPE_H_