Browse Source

chore: cherry-pick 8 changes from Release-1-M113 (#38332)

* chore: [22-x-y] cherry-pick 8 changes from Release-1-M113

* f4c70bc5e89b from v8
* 257a63512782 from v8
* 9964ff18eada from chromium
* a1abaf29e189 from angle
* fe45418c6592 from angle
* d2ce640f16f2 from chromium
* bae60787d3e9 from dawn

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Keeley Hammond 1 year ago
parent
commit
399d2b2d2c

+ 2 - 0
patches/angle/.patches

@@ -2,3 +2,5 @@ fix_rename_webswapcgllayer_to_webswapcgllayerchromium.patch
 cherry-pick-55e2b6daba9d.patch
 cherry-pick-ce029c91a662.patch
 cherry-pick-aed05b609629.patch
+translator_limit_the_size_of_private_variables_in_webgl_shaders.patch
+webgl_limit_total_size_of_private_data.patch

+ 87 - 0
patches/angle/translator_limit_the_size_of_private_variables_in_webgl_shaders.patch

@@ -0,0 +1,87 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Shahbaz Youssefi <[email protected]>
+Date: Tue, 28 Mar 2023 11:43:23 -0400
+Subject: Translator: Limit the size of private variables in WebGL shaders
+
+As a follow up to
+https://chromium-review.googlesource.com/c/angle/angle/+/3023033, the
+limit to shader-private variables (locals and globals) is further
+reduced to 1MB.  A variable that large will not fit in GPU registers and
+will spill to memory, killing performance.
+
+Bug: chromium:1427865
+Change-Id: I77314d4b891c591cd9a83ad2aebb77d7256f3ada
+Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4377639
+Reviewed-by: Kenneth Russell <[email protected]>
+
+diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+index c9607db74b53487950d31f6a56d55f3e834556a0..6097b6d236b547710aeaf37a6fb45df97d621ca0 100644
+--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
++++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+@@ -20,9 +20,13 @@ namespace sh
+ namespace
+ {
+ 
+-// Arbitrarily enforce that types - even local variables' - declared
+-// with a size in bytes of over 2 GB will cause compilation failure.
+-constexpr size_t kMaxTypeSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
++// Arbitrarily enforce that all types declared with a size in bytes of over 2 GB will cause
++// compilation failure.
++//
++// For local and global variables, the limit is much lower (1MB) as that much memory won't fit in
++// the GPU registers anyway.
++constexpr size_t kMaxVariableSizeInBytes        = static_cast<size_t>(2) * 1024 * 1024 * 1024;
++constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(1) * 1024 * 1024;
+ 
+ // Traverses intermediate tree to ensure that the shader does not
+ // exceed certain implementation-defined limits on the sizes of types.
+@@ -78,13 +82,24 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
+             // whether the row-major layout is correctly determined.
+             bool isRowMajorLayout = false;
+             TraverseShaderVariable(shaderVar, isRowMajorLayout, &visitor);
+-            if (layoutEncoder.getCurrentOffset() > kMaxTypeSizeInBytes)
++            if (layoutEncoder.getCurrentOffset() > kMaxVariableSizeInBytes)
+             {
+                 error(asSymbol->getLine(),
+                       "Size of declared variable exceeds implementation-defined limit",
+                       asSymbol->getName());
+                 return false;
+             }
++
++            const bool isPrivate = variableType.getQualifier() == EvqTemporary ||
++                                   variableType.getQualifier() == EvqGlobal ||
++                                   variableType.getQualifier() == EvqConst;
++            if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes && isPrivate)
++            {
++                error(asSymbol->getLine(),
++                      "Size of declared private variable exceeds implementation-defined limit",
++                      asSymbol->getName());
++                return false;
++            }
+         }
+ 
+         return true;
+diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+index 7dc56cddbc63add1aca6fca3bfd031f3da8d04fc..f4bd19baf3582c0b4a840d73a57ea6fc385159a6 100644
+--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
++++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+@@ -5283,8 +5283,8 @@ void main()
+ 
+     constexpr char kVSArrayTooLarge[] =
+         R"(varying vec4 color;
+-// 2 GB / 32 aligned bytes per mat2 = 67108864
+-const int array_size = 67108865;
++// 1 MB / 32 aligned bytes per mat2 = 32768
++const int array_size = 32769;
+ void main()
+ {
+     mat2 array[array_size];
+@@ -5296,7 +5296,7 @@ void main()
+ 
+     constexpr char kVSArrayMuchTooLarge[] =
+         R"(varying vec4 color;
+-const int array_size = 556007917;
++const int array_size = 55600;
+ void main()
+ {
+     mat2 array[array_size];

+ 207 - 0
patches/angle/webgl_limit_total_size_of_private_data.patch

@@ -0,0 +1,207 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Shahbaz Youssefi <[email protected]>
+Date: Wed, 3 May 2023 13:41:36 -0400
+Subject: WebGL: Limit total size of private data
+
+... not just individual arrays.
+
+Bug: chromium:1431761
+Change-Id: I721e29aeceeaf12c3f6a67b668abffb8dfbc89b0
+Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4503753
+Reviewed-by: Kenneth Russell <[email protected]>
+Commit-Queue: Shahbaz Youssefi <[email protected]>
+
+diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+index 6097b6d236b547710aeaf37a6fb45df97d621ca0..2a033ad9d9422349865a9f2af7084bbf1c2c23d9 100644
+--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
++++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+@@ -35,7 +35,9 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
+ {
+   public:
+     ValidateTypeSizeLimitationsTraverser(TSymbolTable *symbolTable, TDiagnostics *diagnostics)
+-        : TIntermTraverser(true, false, false, symbolTable), mDiagnostics(diagnostics)
++        : TIntermTraverser(true, false, false, symbolTable),
++          mDiagnostics(diagnostics),
++          mTotalPrivateVariablesSize(0)
+     {
+         ASSERT(diagnostics);
+     }
+@@ -93,18 +95,33 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
+             const bool isPrivate = variableType.getQualifier() == EvqTemporary ||
+                                    variableType.getQualifier() == EvqGlobal ||
+                                    variableType.getQualifier() == EvqConst;
+-            if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes && isPrivate)
++            if (isPrivate)
+             {
+-                error(asSymbol->getLine(),
+-                      "Size of declared private variable exceeds implementation-defined limit",
+-                      asSymbol->getName());
+-                return false;
++                if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes)
++                {
++                    error(asSymbol->getLine(),
++                          "Size of declared private variable exceeds implementation-defined limit",
++                          asSymbol->getName());
++                    return false;
++                }
++                mTotalPrivateVariablesSize += layoutEncoder.getCurrentOffset();
+             }
+         }
+ 
+         return true;
+     }
+ 
++    void validateTotalPrivateVariableSize()
++    {
++        if (mTotalPrivateVariablesSize > kMaxPrivateVariableSizeInBytes)
++        {
++            mDiagnostics->error(
++                TSourceLoc{},
++                "Total size of declared private variables exceeds implementation-defined limit",
++                "");
++        }
++    }
++
+   private:
+     void error(TSourceLoc loc, const char *reason, const ImmutableString &token)
+     {
+@@ -213,6 +230,8 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
+ 
+     TDiagnostics *mDiagnostics;
+     std::vector<int> mLoopSymbolIds;
++
++    size_t mTotalPrivateVariablesSize;
+ };
+ 
+ }  // namespace
+@@ -223,6 +242,7 @@ bool ValidateTypeSizeLimitations(TIntermNode *root,
+ {
+     ValidateTypeSizeLimitationsTraverser validate(symbolTable, diagnostics);
+     root->traverse(&validate);
++    validate.validateTotalPrivateVariableSize();
+     return diagnostics->numErrors() == 0;
+ }
+ 
+diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+index f4bd19baf3582c0b4a840d73a57ea6fc385159a6..1b265568fc8a87280cc192fbd573a8b11dfb29ec 100644
+--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
++++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+@@ -5271,11 +5271,12 @@ TEST_P(WebGLCompatibilityTest, ValidateArraySizes)
+     // fairly small array.
+     constexpr char kVSArrayOK[] =
+         R"(varying vec4 color;
+-const int array_size = 1000;
++const int array_size = 500;
+ void main()
+ {
+     mat2 array[array_size];
+-    if (array[0][0][0] == 2.0)
++    mat2 array2[array_size];
++    if (array[0][0][0] + array2[0][0][0] == 2.0)
+         color = vec4(0.0, 1.0, 0.0, 1.0);
+     else
+         color = vec4(1.0, 0.0, 0.0, 1.0);
+@@ -5353,6 +5354,103 @@ void main()
+     EXPECT_EQ(0u, program);
+ }
+ 
++// Reject attempts to allocate too much private memory.
++// This is an implementation-defined limit - crbug.com/1431761.
++TEST_P(WebGLCompatibilityTest, ValidateTotalPrivateSize)
++{
++    constexpr char kTooLargeGlobalMemory1[] =
++        R"(precision mediump float;
++
++// 1 MB / 16 bytes per vec4 = 65536
++vec4 array[32768];
++vec4 array2[32769];
++
++void main()
++{
++    if (array[0].x + array[1].x == 0.)
++        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
++    else
++        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
++})";
++
++    constexpr char kTooLargeGlobalMemory2[] =
++        R"(precision mediump float;
++
++// 1 MB / 16 bytes per vec4 = 65536
++vec4 array[32767];
++vec4 array2[32767];
++vec4 x, y, z;
++
++void main()
++{
++    if (array[0].x + array[1].x == x.w + y.w + z.w)
++        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
++    else
++        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
++})";
++
++    constexpr char kTooLargeGlobalAndLocalMemory1[] =
++        R"(precision mediump float;
++
++// 1 MB / 16 bytes per vec4 = 65536
++vec4 array[32768];
++
++void main()
++{
++    vec4 array2[32769];
++    if (array[0].x + array[1].x == 2.0)
++        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
++    else
++        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
++})";
++
++    // Note: The call stack is not taken into account for the purposes of total memory calculation.
++    constexpr char kTooLargeGlobalAndLocalMemory2[] =
++        R"(precision mediump float;
++
++// 1 MB / 16 bytes per vec4 = 65536
++vec4 array[32768];
++
++float f()
++{
++    vec4 array2[16384];
++    return array2[0].x;
++}
++
++float g()
++{
++    vec4 array3[16383];
++    return array3[0].x;
++}
++
++float h()
++{
++    vec4 value;
++    float value2
++    return value.x + value2;
++}
++
++void main()
++{
++    if (array[0].x + f() + g() + h() == 2.0)
++        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
++    else
++        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
++})";
++
++    GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1);
++    EXPECT_EQ(0u, program);
++
++    program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory2);
++    EXPECT_EQ(0u, program);
++
++    program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory1);
++    EXPECT_EQ(0u, program);
++
++    program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
++    EXPECT_EQ(0u, program);
++}
++
+ // Linking should fail when corresponding vertex/fragment uniform blocks have different precision
+ // qualifiers.
+ TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)

+ 2 - 0
patches/chromium/.patches

@@ -159,3 +159,5 @@ cherry-pick-f58218891f8c.patch
 wayland_ensure_dnd_buffer_size_is_a_multiple_of_scale.patch
 m112_cherry_pick_libxml_cve_fix.patch
 m112_fix_scopedobservation_uaf_in.patch
+cherry-pick-48785f698b1c.patch
+m108-lts_return_after_readycommitnavigation_call_in_commiterrorpage.patch

+ 107 - 0
patches/chromium/cherry-pick-48785f698b1c.patch

@@ -0,0 +1,107 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Arthur Sonzogni <[email protected]>
+Date: Tue, 2 May 2023 09:40:37 +0000
+Subject: Avoid buffer overflow read in HFSReadNextNonIgnorableCodePoint
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Unicode codepoints goes beyond 0xFFFF.
+
+It exists upper and lower case characters there: `𞤡 `vs `𞥃`.
+
+The buffer overflow occurred when using the lookup table:
+```
+lower_case_table[codepoint >> 8]
+```
+
+Bug: 1425115
+Fixed: 1425115
+Change-Id: I679da02dbe570283a68176fbd3c0c620caa4f9ce
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4481260
+Reviewed-by: Alexander Timin <[email protected]>
+Commit-Queue: Arthur Sonzogni <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1138234}
+
+diff --git a/base/files/file_path.cc b/base/files/file_path.cc
+index a43c09317da96332584286fdb67284b2bedd753f..3a7cca6fad051816d6d018857c8039594c51ec65 100644
+--- a/base/files/file_path.cc
++++ b/base/files/file_path.cc
+@@ -775,7 +775,7 @@ int FilePath::CompareIgnoreCase(StringPieceType string1,
+ #elif BUILDFLAG(IS_APPLE)
+ // Mac OS X specific implementation of file string comparisons.
+ 
+-// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
++// cf. https://developer.apple.com/library/archive/technotes/tn/tn1150.html#UnicodeSubtleties
+ //
+ // "When using CreateTextEncoding to create a text encoding, you should set
+ // the TextEncodingBase to kTextEncodingUnicodeV2_0, set the
+@@ -801,11 +801,12 @@ int FilePath::CompareIgnoreCase(StringPieceType string1,
+ // Ignored characters are mapped to zero.
+ //
+ // cf. downloadable file linked in
+-// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
++// https://developer.apple.com/library/archive/technotes/tn/tn1150.html#Downloads
+ 
+ namespace {
+ 
+-const UInt16 lower_case_table[] = {
++// clang-format off
++const UInt16 lower_case_table[11 * 256] = {
+   // High-byte indices ( == 0 iff no case mapping and no ignorables )
+ 
+   /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
+@@ -1191,11 +1192,12 @@ const UInt16 lower_case_table[] = {
+   /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
+           0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+ };
++// clang-format on
+ 
+-// Returns the next non-ignorable codepoint within string starting from the
+-// position indicated by index, or zero if there are no more.
+-// The passed-in index is automatically advanced as the characters in the input
+-// HFS-decomposed UTF-8 strings are read.
++// Returns the next non-ignorable codepoint within `string` starting from the
++// position indicated by `index`, or zero if there are no more.
++// The passed-in `index` is automatically advanced as the characters in the
++// input HFS-decomposed UTF-8 strings are read.
+ inline base_icu::UChar32 HFSReadNextNonIgnorableCodepoint(const char* string,
+                                                           size_t length,
+                                                           size_t* index) {
+@@ -1206,12 +1208,16 @@ inline base_icu::UChar32 HFSReadNextNonIgnorableCodepoint(const char* string,
+     CBU8_NEXT(reinterpret_cast<const uint8_t*>(string), *index, length,
+               codepoint);
+     DCHECK_GT(codepoint, 0);
+-    if (codepoint > 0) {
++
++    // Note: Here, there are no lower case conversion implemented in the
++    // Supplementary Multilingual Plane (codepoint > 0xFFFF).
++
++    if (codepoint > 0 && codepoint <= 0xFFFF) {
+       // Check if there is a subtable for this upper byte.
+       int lookup_offset = lower_case_table[codepoint >> 8];
+       if (lookup_offset != 0)
+         codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)];
+-      // Note: codepoint1 may be again 0 at this point if the character was
++      // Note: `codepoint` may be again 0 at this point if the character was
+       // an ignorable.
+     }
+   }
+diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc
+index b9b14c1ebb6a7046f6432531913fd72b045d6cb0..90457a001c2f0d5652ae1394c9d142bfd0003ca6 100644
+--- a/base/files/file_path_unittest.cc
++++ b/base/files/file_path_unittest.cc
+@@ -1188,6 +1188,13 @@ TEST_F(FilePathTest, CompareIgnoreCase) {
+     {{FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n")}, 0},
+     {{FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n")}, 0},
+     {{FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n")}, 1},
++
++    // Codepoints > 0xFFFF
++    // Here, we compare the `Adlam Letter Shu` in its capital and small version.
++    {{FPL("\U0001E921"), FPL("\U0001E943")}, -1},
++    {{FPL("\U0001E943"), FPL("\U0001E921")}, 1},
++    {{FPL("\U0001E921"), FPL("\U0001E921")}, 0},
++    {{FPL("\U0001E943"), FPL("\U0001E943")}, 0},
+ #endif
+   };
+ 

+ 142 - 0
patches/chromium/m108-lts_return_after_readycommitnavigation_call_in_commiterrorpage.patch

@@ -0,0 +1,142 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Rakina Zata Amni <[email protected]>
+Date: Tue, 30 May 2023 16:24:26 +0000
+Subject: Return after ReadyCommitNavigation call in CommitErrorPage if it
+ deletes NavigationRequest
+
+M108 merge issue:
+  content/browser/renderer_host/navigation_request.cc:
+    topics_eligible_ isn't present in M108
+
+NavigationRequest::ReadyToCommitNavigation() can cause deletion of the
+NavigationRequest, so callers should check for that possibility after
+calling the function. A caller in CommitErrorPage is missing that
+check, which this CL adds, along with a regression test.
+
+(cherry picked from commit 42db806805ef2be64ee92803d3a784631b2a7df0)
+
+Bug: 1444360
+Change-Id: I3964da4909a6709b7730d25d6497b19c098f4f21
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4520493
+Commit-Queue: Charlie Reis <[email protected]>
+Cr-Original-Commit-Position: refs/heads/main@{#1143298}
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4567848
+Reviewed-by: Rakina Zata Amni <[email protected]>
+Commit-Queue: Roger Felipe Zanoni da Silva <[email protected]>
+Cr-Commit-Position: refs/branch-heads/5359@{#1460}
+Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933}
+
+diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
+index f6f25544bd36fceb60ada013178cc8fb67e7b10a..ebc0a0c57fb78b3f0044979cca115c78f98f8c2d 100644
+--- a/content/browser/renderer_host/navigation_request.cc
++++ b/content/browser/renderer_host/navigation_request.cc
+@@ -4913,7 +4913,13 @@ void NavigationRequest::CommitErrorPage(
+     }
+   }
+ 
++  base::WeakPtr<NavigationRequest> weak_self(weak_factory_.GetWeakPtr());
+   ReadyToCommitNavigation(true /* is_error */);
++  // The caller above might result in the deletion of `this`. Return immediately
++  // if so.
++  if (!weak_self) {
++    return;
++  }
+ 
+   PopulateDocumentTokenForCrossDocumentNavigation();
+   // Use a separate cache shard, and no cookies, for error pages.
+diff --git a/content/browser/renderer_host/navigation_request_browsertest.cc b/content/browser/renderer_host/navigation_request_browsertest.cc
+index 486a6871d9ff5256123c47accf9f714b67bc30fc..cc4f9acf9e5ec5f8c8dfa8a812a2cc6fb4505526 100644
+--- a/content/browser/renderer_host/navigation_request_browsertest.cc
++++ b/content/browser/renderer_host/navigation_request_browsertest.cc
+@@ -43,6 +43,7 @@
+ #include "content/public/test/prerender_test_util.h"
+ #include "content/public/test/test_frame_navigation_observer.h"
+ #include "content/public/test/test_navigation_observer.h"
++#include "content/public/test/test_service.mojom.h"
+ #include "content/public/test/test_utils.h"
+ #include "content/public/test/url_loader_interceptor.h"
+ #include "content/shell/browser/shell.h"
+@@ -3850,4 +3851,83 @@ IN_PROC_BROWSER_TEST_P(NavigationRequestMPArchBrowserTest,
+   }
+ }
+ 
++// Tests that when trying to commit an error page for a failed navigation, but
++// the renderer process of the, the navigation won't commit and won't crash.
++// Regression test for https://crbug.com/1444360.
++IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
++                       RendererCrashedBeforeCommitErrorPage) {
++  // Navigate to `url_a` first.
++  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
++  ASSERT_TRUE(NavigateToURL(shell(), url_a));
++
++  // Set up an URLLoaderInterceptor which will cause future navigations to fail.
++  auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
++      base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
++        network::URLLoaderCompletionStatus status;
++        status.error_code = net::ERR_NOT_IMPLEMENTED;
++        params->client->OnComplete(status);
++        return true;
++      }));
++
++  // Do a navigation to `url_b1` that will fail and commit an error page. This
++  // is important so that the next error page navigation won't need to create a
++  // speculative RenderFrameHost (unless RenderDocument is enabled) and won't
++  // get cancelled earlier than commit time due to speculative RFH deletion.
++  GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
++  EXPECT_FALSE(NavigateToURL(shell(), url_b1));
++  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url_b1);
++  EXPECT_TRUE(
++      shell()->web_contents()->GetPrimaryMainFrame()->IsErrorDocument());
++
++  // For the next navigation, set up a throttle that will be used to wait for
++  // WillFailRequest() and then defer the navigation, so that we can crash the
++  // error page process first.
++  TestNavigationThrottleInstaller installer(
++      shell()->web_contents(),
++      NavigationThrottle::PROCEED /* will_start_result */,
++      NavigationThrottle::PROCEED /* will_redirect_result */,
++      NavigationThrottle::DEFER /* will_fail_result */,
++      NavigationThrottle::PROCEED /* will_process_result */);
++
++  // Start a navigation to `url_b2` that will also fail, but before it commits
++  // an error page, cause the error page process to crash.
++  GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
++  TestNavigationManager manager(shell()->web_contents(), url_b2);
++  shell()->LoadURL(url_b2);
++  EXPECT_TRUE(manager.WaitForRequestStart());
++
++  // Resume the navigation and wait for WillFailRequest(). After this point, we
++  // will have picked the final RenderFrameHost & RenderProcessHost for the
++  // failed navigation.
++  manager.ResumeNavigation();
++  installer.WaitForThrottleWillFail();
++
++  // Kill the error page process. This will cause for the navigation to `url_b2`
++  // to return early in `NavigationRequest::ReadyToCommitNavigation()` and not
++  // commit a new error page.
++  RenderProcessHost* process_to_kill =
++      manager.GetNavigationHandle()->GetRenderFrameHost()->GetProcess();
++  ASSERT_TRUE(process_to_kill->IsInitializedAndNotDead());
++  {
++    // Trigger a renderer kill by calling DoSomething() which will cause a bad
++    // message to be reported.
++    RenderProcessHostBadIpcMessageWaiter kill_waiter(process_to_kill);
++    mojo::Remote<mojom::TestService> service;
++    process_to_kill->BindReceiver(service.BindNewPipeAndPassReceiver());
++    service->DoSomething(base::DoNothing());
++    EXPECT_EQ(bad_message::RPH_MOJO_PROCESS_ERROR, kill_waiter.Wait());
++  }
++  ASSERT_FALSE(process_to_kill->IsInitializedAndNotDead());
++
++  // Resume the navigation, which won't commit.
++  if (!ShouldCreateNewHostForAllFrames()) {
++    installer.navigation_throttle()->ResumeNavigation();
++  }
++  manager.WaitForNavigationFinished();
++  EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
++
++  // The tab stayed at `url_b1` as the `url_b2` navigation didn't commit.
++  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url_b1);
++}
++
+ }  // namespace content

+ 3 - 1
patches/config.json

@@ -25,5 +25,7 @@
 
   "src/electron/patches/pdfium": "src/third_party/pdfium",
 
-  "src/electron/patches/skia": "src/third_party/skia"
+  "src/electron/patches/skia": "src/third_party/skia",
+
+  "src/electron/patches/dawn": "src/third_party/dawn"
 }

+ 1 - 0
patches/dawn/.patches

@@ -0,0 +1 @@
+change_d3d12_descriptor_allocator_to_invalidate_submitted_descriptors.patch

+ 42 - 0
patches/dawn/change_d3d12_descriptor_allocator_to_invalidate_submitted_descriptors.patch

@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Brandon Jones <[email protected]>
+Date: Fri, 5 May 2023 18:02:42 +0000
+Subject: Change D3D12 Descriptor Allocator To Invalidate Submitted Descriptors
+
+Changes D3D12 descriptor allocator to invalidate existing descriptors
+after the descriptor heap was submitted for use. This fixes a
+synchonization issue where stale descriptors were seen as valid because
+command list execution ran long.
+
+Bug: dawn:1701
+Bug: chromium:1442263
+No-Try: true
+Change-Id: Ibfd450b3be6cf91d66e8dce4ffd19ecf1a37f7f5
+Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129920
+Kokoro: Kokoro <[email protected]>
+Reviewed-by: Corentin Wallez <[email protected]>
+Commit-Queue: Brandon1 Jones <[email protected]>
+(cherry picked from commit df6cb236493da101dad79fe50d4e6df0d5d1e915)
+Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131508
+Kokoro: Austin Eng <[email protected]>
+Reviewed-by: Austin Eng <[email protected]>
+
+diff --git a/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp b/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp
+index fe99a63ac9d2d082c2c23eb7940a733a9d13846a..aedb28ad58a0a972879f07a6037499f901fcf04a 100644
+--- a/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp
++++ b/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp
+@@ -237,9 +237,11 @@ bool ShaderVisibleDescriptorAllocator::IsLastShaderVisibleHeapInLRUForTesting()
+ 
+ bool ShaderVisibleDescriptorAllocator::IsAllocationStillValid(
+     const GPUDescriptorHeapAllocation& allocation) const {
+-    // Consider valid if allocated for the pending submit and the shader visible heaps
+-    // have not switched over.
+-    return (allocation.GetLastUsageSerial() > mDevice->GetCompletedCommandSerial() &&
++    // Descriptor allocations are only valid for the serial they were created for and are
++    // re-allocated every submit. For this reason, we view any descriptors allocated prior to the
++    // pending submit as invalid. We must also verify the descriptor heap has not switched (because
++    // a larger descriptor heap was needed).
++    return (allocation.GetLastUsageSerial() == mDevice->GetPendingCommandSerial() &&
+             allocation.GetHeapSerial() == mHeapSerial);
+ }
+ 

+ 2 - 0
patches/v8/.patches

@@ -17,3 +17,5 @@ cherry-pick-c605df24af3c.patch
 cherry-pick-f4b66ae451c2.patch
 merged_ic_fix_store_handler_selection_for_arguments_objects.patch
 cherry-pick-73af1a19a901.patch
+merged_regexp_fix_clobbered_register_in_global_unicode_special.patch
+m108-lts_api_fix_v8_object_setaccessorproperty.patch

+ 366 - 0
patches/v8/m108-lts_api_fix_v8_object_setaccessorproperty.patch

@@ -0,0 +1,366 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Igor Sheludko <[email protected]>
+Date: Thu, 27 Apr 2023 11:11:32 +0200
+Subject: Fix v8::Object::SetAccessorProperty
+
+... by using JavaScript spec compliant JSReceiver::DefineOwnProperty.
+
+Drive-by:
+- cleanup comments in include/v8-object.h, insert links to
+respective pages of https://tc39.es/ecma262/ when referencing spec,
+- rename JSObject::DefineAccessor() to
+  JSObject::DefineOwnAccessorIgnoreAttributes().
+
+(cherry picked from commit b8020e1973d7d3a50b17c076cd948f079e59f9e5)
+
+Bug: chromium:1433211
+Change-Id: Ia9edaadd68f1986f18581156ad8f79c438b77744
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4458947
+Commit-Queue: Igor Sheludko <[email protected]>
+Cr-Original-Commit-Position: refs/heads/main@{#87302}
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4573392
+Commit-Queue: Roger Felipe Zanoni da Silva <[email protected]>
+Reviewed-by: Michael Lippautz <[email protected]>
+Reviewed-by: Igor Sheludko <[email protected]>
+Cr-Commit-Position: refs/branch-heads/10.8@{#62}
+Cr-Branched-From: f1bc03fd6b4c201abd9f0fd9d51fb989150f97b9-refs/heads/10.8.168@{#1}
+Cr-Branched-From: 237de893e1c0a0628a57d0f5797483d3add7f005-refs/heads/main@{#83672}
+
+diff --git a/include/v8-object.h b/include/v8-object.h
+index d7332ba0c88d12e8086f56117631dfb3e1e514b4..dfeda2d39431d481dbeab6698c3d3e7f02a1b19c 100644
+--- a/include/v8-object.h
++++ b/include/v8-object.h
+@@ -247,13 +247,16 @@ class V8_EXPORT Object : public Value {
+   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
+                                         Local<Value> value);
+ 
+-  // Implements CreateDataProperty (ECMA-262, 7.3.4).
+-  //
+-  // Defines a configurable, writable, enumerable property with the given value
+-  // on the object unless the property already exists and is not configurable
+-  // or the object is not extensible.
+-  //
+-  // Returns true on success.
++  /**
++   * Implements CreateDataProperty(O, P, V), see
++   * https://tc39.es/ecma262/#sec-createdataproperty.
++   *
++   * Defines a configurable, writable, enumerable property with the given value
++   * on the object unless the property already exists and is not configurable
++   * or the object is not extensible.
++   *
++   * Returns true on success.
++   */
+   V8_WARN_UNUSED_RESULT Maybe<bool> CreateDataProperty(Local<Context> context,
+                                                        Local<Name> key,
+                                                        Local<Value> value);
+@@ -261,29 +264,35 @@ class V8_EXPORT Object : public Value {
+                                                        uint32_t index,
+                                                        Local<Value> value);
+ 
+-  // Implements DefineOwnProperty.
+-  //
+-  // In general, CreateDataProperty will be faster, however, does not allow
+-  // for specifying attributes.
+-  //
+-  // Returns true on success.
++  /**
++   * Implements [[DefineOwnProperty]] for data property case, see
++   * https://tc39.es/ecma262/#table-essential-internal-methods.
++   *
++   * In general, CreateDataProperty will be faster, however, does not allow
++   * for specifying attributes.
++   *
++   * Returns true on success.
++   */
+   V8_WARN_UNUSED_RESULT Maybe<bool> DefineOwnProperty(
+       Local<Context> context, Local<Name> key, Local<Value> value,
+       PropertyAttribute attributes = None);
+ 
+-  // Implements Object.DefineProperty(O, P, Attributes), see Ecma-262 19.1.2.4.
+-  //
+-  // The defineProperty function is used to add an own property or
+-  // update the attributes of an existing own property of an object.
+-  //
+-  // Both data and accessor descriptors can be used.
+-  //
+-  // In general, CreateDataProperty is faster, however, does not allow
+-  // for specifying attributes or an accessor descriptor.
+-  //
+-  // The PropertyDescriptor can change when redefining a property.
+-  //
+-  // Returns true on success.
++  /**
++   * Implements Object.defineProperty(O, P, Attributes), see
++   * https://tc39.es/ecma262/#sec-object.defineproperty.
++   *
++   * The defineProperty function is used to add an own property or
++   * update the attributes of an existing own property of an object.
++   *
++   * Both data and accessor descriptors can be used.
++   *
++   * In general, CreateDataProperty is faster, however, does not allow
++   * for specifying attributes or an accessor descriptor.
++   *
++   * The PropertyDescriptor can change when redefining a property.
++   *
++   * Returns true on success.
++   */
+   V8_WARN_UNUSED_RESULT Maybe<bool> DefineProperty(
+       Local<Context> context, Local<Name> key, PropertyDescriptor& descriptor);
+ 
+@@ -302,14 +311,15 @@ class V8_EXPORT Object : public Value {
+       Local<Context> context, Local<Value> key);
+ 
+   /**
+-   * Returns Object.getOwnPropertyDescriptor as per ES2016 section 19.1.2.6.
++   * Implements Object.getOwnPropertyDescriptor(O, P), see
++   * https://tc39.es/ecma262/#sec-object.getownpropertydescriptor.
+    */
+   V8_WARN_UNUSED_RESULT MaybeLocal<Value> GetOwnPropertyDescriptor(
+       Local<Context> context, Local<Name> key);
+ 
+   /**
+-   * Object::Has() calls the abstract operation HasProperty(O, P) described
+-   * in ECMA-262, 7.3.10. Has() returns
++   * Object::Has() calls the abstract operation HasProperty(O, P), see
++   * https://tc39.es/ecma262/#sec-hasproperty. Has() returns
+    * true, if the object has the property, either own or on the prototype chain.
+    * Interceptors, i.e., PropertyQueryCallbacks, are called if present.
+    *
+@@ -347,7 +357,7 @@ class V8_EXPORT Object : public Value {
+ 
+   void SetAccessorProperty(Local<Name> name, Local<Function> getter,
+                            Local<Function> setter = Local<Function>(),
+-                           PropertyAttribute attribute = None,
++                           PropertyAttribute attributes = None,
+                            AccessControl settings = DEFAULT);
+ 
+   /**
+diff --git a/src/api/api-natives.cc b/src/api/api-natives.cc
+index 8624c279d66e4fa54a7a20681e1398c453b6cdbd..742d3c17a3e7def43813f44b004c8dc41a27ed68 100644
+--- a/src/api/api-natives.cc
++++ b/src/api/api-natives.cc
+@@ -92,10 +92,10 @@ MaybeHandle<Object> DefineAccessorProperty(Isolate* isolate,
+                             Handle<FunctionTemplateInfo>::cast(setter)),
+         Object);
+   }
+-  RETURN_ON_EXCEPTION(
+-      isolate,
+-      JSObject::DefineAccessor(object, name, getter, setter, attributes),
+-      Object);
++  RETURN_ON_EXCEPTION(isolate,
++                      JSObject::DefineOwnAccessorIgnoreAttributes(
++                          object, name, getter, setter, attributes),
++                      Object);
+   return object;
+ }
+ 
+diff --git a/src/api/api.cc b/src/api/api.cc
+index 0bc26565403fa1a9827ced3bc6a49ca87bbf46c0..29e163c2e3073ae1f9a86e88f317e9fd44c6c112 100644
+--- a/src/api/api.cc
++++ b/src/api/api.cc
+@@ -4932,7 +4932,7 @@ Maybe<bool> Object::SetAccessor(Local<Context> context, Local<Name> name,
+ 
+ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter,
+                                  Local<Function> setter,
+-                                 PropertyAttribute attribute,
++                                 PropertyAttribute attributes,
+                                  AccessControl settings) {
+   // TODO(verwaest): Remove |settings|.
+   DCHECK_EQ(v8::DEFAULT, settings);
+@@ -4944,9 +4944,20 @@ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter,
+   i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
+   i::Handle<i::Object> setter_i = v8::Utils::OpenHandle(*setter, true);
+   if (setter_i.is_null()) setter_i = i_isolate->factory()->null_value();
+-  i::JSObject::DefineAccessor(i::Handle<i::JSObject>::cast(self),
+-                              v8::Utils::OpenHandle(*name), getter_i, setter_i,
+-                              static_cast<i::PropertyAttributes>(attribute));
++
++  i::PropertyDescriptor desc;
++  desc.set_enumerable(!(attributes & v8::DontEnum));
++  desc.set_configurable(!(attributes & v8::DontDelete));
++  desc.set_get(getter_i);
++  desc.set_set(setter_i);
++
++  i::Handle<i::Name> name_i = v8::Utils::OpenHandle(*name);
++  // DefineOwnProperty might still throw if the receiver is a JSProxy and it
++  // might fail if the receiver is non-extensible or already has this property
++  // as non-configurable.
++  Maybe<bool> success = i::JSReceiver::DefineOwnProperty(
++      i_isolate, self, name_i, &desc, Just(i::kDontThrow));
++  USE(success);
+ }
+ 
+ Maybe<bool> Object::SetNativeDataProperty(
+diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
+index fc7b17d582e79b956362e0db46a7aefebd594ed0..8a81c4acda9a92b1d25491aa00278a0e929da695 100644
+--- a/src/init/bootstrapper.cc
++++ b/src/init/bootstrapper.cc
+@@ -634,7 +634,9 @@ V8_NOINLINE void SimpleInstallGetterSetter(Isolate* isolate,
+   Handle<JSFunction> setter =
+       SimpleCreateFunction(isolate, setter_name, call_setter, 1, true);
+ 
+-  JSObject::DefineAccessor(base, name, getter, setter, DONT_ENUM).Check();
++  JSObject::DefineOwnAccessorIgnoreAttributes(base, name, getter, setter,
++                                              DONT_ENUM)
++      .Check();
+ }
+ 
+ void SimpleInstallGetterSetter(Isolate* isolate, Handle<JSObject> base,
+@@ -658,7 +660,8 @@ V8_NOINLINE Handle<JSFunction> SimpleInstallGetter(Isolate* isolate,
+ 
+   Handle<Object> setter = isolate->factory()->undefined_value();
+ 
+-  JSObject::DefineAccessor(base, property_name, getter, setter, DONT_ENUM)
++  JSObject::DefineOwnAccessorIgnoreAttributes(base, property_name, getter,
++                                              setter, DONT_ENUM)
+       .Check();
+ 
+   return getter;
+diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
+index 15356b6c58d2f7355fa8b0dce4d3ea779a2884f9..834f83c0b0e68b9dcbe3fd0595dc2861cdd2c017 100644
+--- a/src/objects/js-objects.cc
++++ b/src/objects/js-objects.cc
+@@ -1519,7 +1519,8 @@ Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
+                 ? desc->set()
+                 : Handle<Object>::cast(isolate->factory()->null_value()));
+         MaybeHandle<Object> result =
+-            JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
++            JSObject::DefineOwnAccessorIgnoreAttributes(it, getter, setter,
++                                                        desc->ToAttributes());
+         if (result.is_null()) return Nothing<bool>();
+       }
+     }
+@@ -1700,8 +1701,8 @@ Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
+               : current->has_set()
+                     ? current->set()
+                     : Handle<Object>::cast(isolate->factory()->null_value()));
+-      MaybeHandle<Object> result =
+-          JSObject::DefineAccessor(it, getter, setter, attrs);
++      MaybeHandle<Object> result = JSObject::DefineOwnAccessorIgnoreAttributes(
++          it, getter, setter, attrs);
+       if (result.is_null()) return Nothing<bool>();
+     }
+   }
+@@ -4635,22 +4636,19 @@ bool JSObject::HasEnumerableElements() {
+   UNREACHABLE();
+ }
+ 
+-MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
+-                                             Handle<Name> name,
+-                                             Handle<Object> getter,
+-                                             Handle<Object> setter,
+-                                             PropertyAttributes attributes) {
++MaybeHandle<Object> JSObject::DefineOwnAccessorIgnoreAttributes(
++    Handle<JSObject> object, Handle<Name> name, Handle<Object> getter,
++    Handle<Object> setter, PropertyAttributes attributes) {
+   Isolate* isolate = object->GetIsolate();
+ 
+   PropertyKey key(isolate, name);
+   LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
+-  return DefineAccessor(&it, getter, setter, attributes);
++  return DefineOwnAccessorIgnoreAttributes(&it, getter, setter, attributes);
+ }
+ 
+-MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
+-                                             Handle<Object> getter,
+-                                             Handle<Object> setter,
+-                                             PropertyAttributes attributes) {
++MaybeHandle<Object> JSObject::DefineOwnAccessorIgnoreAttributes(
++    LookupIterator* it, Handle<Object> getter, Handle<Object> setter,
++    PropertyAttributes attributes) {
+   Isolate* isolate = it->isolate();
+ 
+   it->UpdateProtector();
+diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
+index 06489c2b7bae61ecadbd8f020060e86ef50e11b6..ff96bd4be2ff8d2fe03f75b6bca35a744e2084af 100644
+--- a/src/objects/js-objects.h
++++ b/src/objects/js-objects.h
+@@ -531,13 +531,14 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
+   GetPropertyAttributesWithFailedAccessCheck(LookupIterator* it);
+ 
+   // Defines an AccessorPair property on the given object.
+-  V8_EXPORT_PRIVATE static MaybeHandle<Object> DefineAccessor(
+-      Handle<JSObject> object, Handle<Name> name, Handle<Object> getter,
+-      Handle<Object> setter, PropertyAttributes attributes);
+-  static MaybeHandle<Object> DefineAccessor(LookupIterator* it,
+-                                            Handle<Object> getter,
+-                                            Handle<Object> setter,
+-                                            PropertyAttributes attributes);
++  V8_EXPORT_PRIVATE static MaybeHandle<Object>
++  DefineOwnAccessorIgnoreAttributes(Handle<JSObject> object, Handle<Name> name,
++                                    Handle<Object> getter,
++                                    Handle<Object> setter,
++                                    PropertyAttributes attributes);
++  static MaybeHandle<Object> DefineOwnAccessorIgnoreAttributes(
++      LookupIterator* it, Handle<Object> getter, Handle<Object> setter,
++      PropertyAttributes attributes);
+ 
+   // Defines an AccessorInfo property on the given object.
+   V8_WARN_UNUSED_RESULT static MaybeHandle<Object> SetAccessor(
+diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
+index 56e58bea3e1c7add75729e590b628d9a78558ce6..01111be8d6ea28ed1e1e81255b29da5a77ab1e39 100644
+--- a/src/runtime/runtime-object.cc
++++ b/src/runtime/runtime-object.cc
+@@ -1109,7 +1109,8 @@ RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
+   auto attrs = PropertyAttributesFromInt(args.smi_value_at(4));
+ 
+   RETURN_FAILURE_ON_EXCEPTION(
+-      isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs));
++      isolate, JSObject::DefineOwnAccessorIgnoreAttributes(obj, name, getter,
++                                                           setter, attrs));
+   return ReadOnlyRoots(isolate).undefined_value();
+ }
+ 
+@@ -1215,8 +1216,8 @@ RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) {
+ 
+   RETURN_FAILURE_ON_EXCEPTION(
+       isolate,
+-      JSObject::DefineAccessor(object, name, getter,
+-                               isolate->factory()->null_value(), attrs));
++      JSObject::DefineOwnAccessorIgnoreAttributes(
++          object, name, getter, isolate->factory()->null_value(), attrs));
+   return ReadOnlyRoots(isolate).undefined_value();
+ }
+ 
+@@ -1360,8 +1361,8 @@ RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
+ 
+   RETURN_FAILURE_ON_EXCEPTION(
+       isolate,
+-      JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
+-                               setter, attrs));
++      JSObject::DefineOwnAccessorIgnoreAttributes(
++          object, name, isolate->factory()->null_value(), setter, attrs));
+   return ReadOnlyRoots(isolate).undefined_value();
+ }
+ 
+diff --git a/src/sandbox/testing.cc b/src/sandbox/testing.cc
+index fead4aa222ceb81d76f6dfec7e7797e337e7ba94..aab72a18015bf7ac1d0949e9497e85d9d089b4b8 100644
+--- a/src/sandbox/testing.cc
++++ b/src/sandbox/testing.cc
+@@ -156,7 +156,8 @@ void InstallGetter(Isolate* isolate, Handle<JSObject> object,
+   Handle<String> property_name = factory->NewStringFromAsciiChecked(name);
+   Handle<JSFunction> getter = CreateFunc(isolate, func, property_name, false);
+   Handle<Object> setter = factory->null_value();
+-  JSObject::DefineAccessor(object, property_name, getter, setter, FROZEN);
++  JSObject::DefineOwnAccessorIgnoreAttributes(object, property_name, getter,
++                                              setter, FROZEN);
+ }
+ 
+ void InstallFunction(Isolate* isolate, Handle<JSObject> holder,
+diff --git a/test/cctest/test-code-stub-assembler.cc b/test/cctest/test-code-stub-assembler.cc
+index 53ad0a95e2e63f32610a77ee7195d15f7037898d..4152456d1a7962da4a0d88e15bc68107da585613 100644
+--- a/test/cctest/test-code-stub-assembler.cc
++++ b/test/cctest/test-code-stub-assembler.cc
+@@ -1179,7 +1179,9 @@ void AddProperties(Handle<JSObject> object, Handle<Name> names[],
+       Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
+       Handle<Object> getter(pair->getter(), isolate);
+       Handle<Object> setter(pair->setter(), isolate);
+-      JSObject::DefineAccessor(object, names[i], getter, setter, NONE).Check();
++      JSObject::DefineOwnAccessorIgnoreAttributes(object, names[i], getter,
++                                                  setter, NONE)
++          .Check();
+     } else {
+       JSObject::AddProperty(isolate, object, names[i], value, NONE);
+     }

+ 304 - 0
patches/v8/merged_regexp_fix_clobbered_register_in_global_unicode_special.patch

@@ -0,0 +1,304 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Shu-yu Guo <[email protected]>
+Date: Wed, 26 Apr 2023 10:56:03 -0700
+Subject: Merged: [regexp] Fix clobbered register in global Unicode special
+ case
+
+Bug: chromium:1439691
+(cherry picked from commit 2c8a019f39d29b403f881d9b5932e3219fdcc832)
+
+Change-Id: Ia418ae04bf4352e3618700c55ecd37447023e6eb
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4503810
+Reviewed-by: Jakob Linke <[email protected]>
+Commit-Queue: Shu-yu Guo <[email protected]>
+Cr-Commit-Position: refs/branch-heads/11.2@{#43}
+Cr-Branched-From: 755511a138609ac5939449a8ac615c15603a4454-refs/heads/11.2.214@{#1}
+Cr-Branched-From: e6b1ccefb0f0f1ff8d310578878130dc53d73749-refs/heads/main@{#86014}
+
+diff --git a/src/regexp/arm/regexp-macro-assembler-arm.cc b/src/regexp/arm/regexp-macro-assembler-arm.cc
+index 2658068b6f94b97f024b1400c8c0b20eefdc5143..5de110c8495ef5bd261df92ca8f459c5f0cc7e5b 100644
+--- a/src/regexp/arm/regexp-macro-assembler-arm.cc
++++ b/src/regexp/arm/regexp-macro-assembler-arm.cc
+@@ -877,19 +877,18 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
+       __ add(r2, r2, Operand(num_saved_registers_ * kPointerSize));
+       __ str(r2, MemOperand(frame_pointer(), kRegisterOutput));
+ 
+-      // Prepare r0 to initialize registers with its value in the next run.
+-      __ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
+-
+       // Restore the original regexp stack pointer value (effectively, pop the
+       // stored base pointer).
+       PopRegExpBasePointer(backtrack_stackpointer(), r2);
+ 
++      Label reload_string_start_minus_one;
++
+       if (global_with_zero_length_check()) {
+         // Special case for zero-length matches.
+         // r4: capture start index
+         __ cmp(current_input_offset(), r4);
+         // Not a zero-length match, restart.
+-        __ b(ne, &load_char_start_regexp);
++        __ b(ne, &reload_string_start_minus_one);
+         // Offset from the end is zero if we already reached the end.
+         __ cmp(current_input_offset(), Operand::Zero());
+         __ b(eq, &exit_label_);
+@@ -901,6 +900,11 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
+         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+       }
+ 
++      __ bind(&reload_string_start_minus_one);
++      // Prepare r0 to initialize registers with its value in the next run.
++      // Must be immediately before the jump to avoid clobbering.
++      __ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
++
+       __ b(&load_char_start_regexp);
+     } else {
+       __ mov(r0, Operand(SUCCESS));
+diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/src/regexp/ia32/regexp-macro-assembler-ia32.cc
+index 600234542042ce9a06ceb3b415fece83f6f271bf..6c3df5da7d6c28619902b20419c9cf437325c1d1 100644
+--- a/src/regexp/ia32/regexp-macro-assembler-ia32.cc
++++ b/src/regexp/ia32/regexp-macro-assembler-ia32.cc
+@@ -915,19 +915,18 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
+       __ add(Operand(ebp, kRegisterOutput),
+              Immediate(num_saved_registers_ * kSystemPointerSize));
+ 
+-      // Prepare eax to initialize registers with its value in the next run.
+-      __ mov(eax, Operand(ebp, kStringStartMinusOne));
+-
+       // Restore the original regexp stack pointer value (effectively, pop the
+       // stored base pointer).
+       PopRegExpBasePointer(backtrack_stackpointer(), ebx);
+ 
++      Label reload_string_start_minus_one;
++
+       if (global_with_zero_length_check()) {
+         // Special case for zero-length matches.
+         // edx: capture start index
+         __ cmp(edi, edx);
+         // Not a zero-length match, restart.
+-        __ j(not_equal, &load_char_start_regexp);
++        __ j(not_equal, &reload_string_start_minus_one);
+         // edi (offset from the end) is zero if we already reached the end.
+         __ test(edi, edi);
+         __ j(zero, &exit_label_, Label::kNear);
+@@ -941,6 +940,12 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
+         }
+         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+       }
++
++      __ bind(&reload_string_start_minus_one);
++      // Prepare eax to initialize registers with its value in the next run.
++      // Must be immediately before the jump to avoid clobbering.
++      __ mov(eax, Operand(ebp, kStringStartMinusOne));
++
+       __ jmp(&load_char_start_regexp);
+     } else {
+       __ mov(eax, Immediate(SUCCESS));
+diff --git a/src/regexp/loong64/regexp-macro-assembler-loong64.cc b/src/regexp/loong64/regexp-macro-assembler-loong64.cc
+index 35fd95bd0f2d210419b4057ced6e16ffd5aec051..d5c52b4134ccbfecef85328e181dae1bbda7bf63 100644
+--- a/src/regexp/loong64/regexp-macro-assembler-loong64.cc
++++ b/src/regexp/loong64/regexp-macro-assembler-loong64.cc
+@@ -850,18 +850,17 @@ Handle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode(Handle<String> source) {
+         __ Add_d(a2, a2, num_saved_registers_ * kIntSize);
+         __ St_d(a2, MemOperand(frame_pointer(), kRegisterOutput));
+ 
+-        // Prepare a0 to initialize registers with its value in the next run.
+-        __ Ld_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
+-
+         // Restore the original regexp stack pointer value (effectively, pop the
+         // stored base pointer).
+         PopRegExpBasePointer(backtrack_stackpointer(), a2);
+ 
++        Label reload_string_start_minus_one;
++
+         if (global_with_zero_length_check()) {
+           // Special case for zero-length matches.
+           // t3: capture start index
+           // Not a zero-length match, restart.
+-          __ Branch(&load_char_start_regexp, ne, current_input_offset(),
++          __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
+                     Operand(t3));
+           // Offset from the end is zero if we already reached the end.
+           __ Branch(&exit_label_, eq, current_input_offset(),
+@@ -874,6 +873,11 @@ Handle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode(Handle<String> source) {
+           if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+         }
+ 
++        __ bind(&reload_string_start_minus_one);
++        // Prepare a0 to initialize registers with its value in the next run.
++        // Must be immediately before the jump to avoid clobbering.
++        __ Ld_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
++
+         __ Branch(&load_char_start_regexp);
+       } else {
+         __ li(a0, Operand(SUCCESS));
+diff --git a/src/regexp/mips64/regexp-macro-assembler-mips64.cc b/src/regexp/mips64/regexp-macro-assembler-mips64.cc
+index 456e166adefc72b7bcaa9245798f3885c2a4c2e7..6ee4c709cf96f68a32a0b3c1ebdc42817293bf29 100644
+--- a/src/regexp/mips64/regexp-macro-assembler-mips64.cc
++++ b/src/regexp/mips64/regexp-macro-assembler-mips64.cc
+@@ -898,19 +898,18 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
+         __ Daddu(a2, a2, num_saved_registers_ * kIntSize);
+         __ Sd(a2, MemOperand(frame_pointer(), kRegisterOutput));
+ 
+-        // Prepare a0 to initialize registers with its value in the next run.
+-        __ Ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
+-
+         // Restore the original regexp stack pointer value (effectively, pop the
+         // stored base pointer).
+         PopRegExpBasePointer(backtrack_stackpointer(), a2);
+ 
++        Label reload_string_start_minus_one;
++
+         if (global_with_zero_length_check()) {
+           // Special case for zero-length matches.
+           // t3: capture start index
+           // Not a zero-length match, restart.
+-          __ Branch(
+-              &load_char_start_regexp, ne, current_input_offset(), Operand(t3));
++          __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
++                    Operand(t3));
+           // Offset from the end is zero if we already reached the end.
+           __ Branch(&exit_label_, eq, current_input_offset(),
+                     Operand(zero_reg));
+@@ -922,6 +921,11 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
+           if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+         }
+ 
++        __ bind(&reload_string_start_minus_one);
++        // Prepare a0 to initialize registers with its value in the next run.
++        // Must be immediately before the jump to avoid clobbering.
++        __ Ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
++
+         __ Branch(&load_char_start_regexp);
+       } else {
+         __ li(v0, Operand(SUCCESS));
+diff --git a/src/regexp/riscv/regexp-macro-assembler-riscv.cc b/src/regexp/riscv/regexp-macro-assembler-riscv.cc
+index c8f3eb551e05805003d30a1786acdd9aab96d906..c03be100849c50f471d6839d4cd960e5a78d67d3 100644
+--- a/src/regexp/riscv/regexp-macro-assembler-riscv.cc
++++ b/src/regexp/riscv/regexp-macro-assembler-riscv.cc
+@@ -869,18 +869,17 @@ Handle<HeapObject> RegExpMacroAssemblerRISCV::GetCode(Handle<String> source) {
+         __ AddWord(a2, a2, num_saved_registers_ * kIntSize);
+         __ StoreWord(a2, MemOperand(frame_pointer(), kRegisterOutput));
+ 
+-        // Prepare a0 to initialize registers with its value in the next run.
+-        __ LoadWord(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
+-
+         // Restore the original regexp stack pointer value (effectively, pop the
+         // stored base pointer).
+         PopRegExpBasePointer(backtrack_stackpointer(), a2);
+ 
++        Label reload_string_start_minus_one;
++
+         if (global_with_zero_length_check()) {
+           // Special case for zero-length matches.
+           // s3: capture start index
+           // Not a zero-length match, restart.
+-          __ Branch(&load_char_start_regexp, ne, current_input_offset(),
++          __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
+                     Operand(s3));
+           // Offset from the end is zero if we already reached the end.
+           __ Branch(&exit_label_, eq, current_input_offset(),
+@@ -893,6 +892,12 @@ Handle<HeapObject> RegExpMacroAssemblerRISCV::GetCode(Handle<String> source) {
+           if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+         }
+ 
++        __ bind(&reload_string_start_minus_one);
++        // Prepare a0 to initialize registers with its value in the next run.
++        // Must be immediately before the jump to avoid clobbering.
++        __ LoadWord(a0,
++                    MemOperand(frame_pointer(), kStringStartMinusOne));
++
+         __ Branch(&load_char_start_regexp);
+       } else {
+         __ li(a0, Operand(SUCCESS));
+diff --git a/src/regexp/s390/regexp-macro-assembler-s390.cc b/src/regexp/s390/regexp-macro-assembler-s390.cc
+index a61bc379ba6c265ecb0c5cd7aa8d7a2e35ca6c1e..de184b95862e7f2e64d69cff6b60d866eb212f36 100644
+--- a/src/regexp/s390/regexp-macro-assembler-s390.cc
++++ b/src/regexp/s390/regexp-macro-assembler-s390.cc
+@@ -947,19 +947,18 @@ Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
+       __ AddS64(r4, Operand(num_saved_registers_ * kIntSize));
+       __ StoreU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
+ 
+-      // Prepare r2 to initialize registers with its value in the next run.
+-      __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
+-
+       // Restore the original regexp stack pointer value (effectively, pop the
+       // stored base pointer).
+       PopRegExpBasePointer(backtrack_stackpointer(), r4);
+ 
++      Label reload_string_start_minus_one;
++
+       if (global_with_zero_length_check()) {
+         // Special case for zero-length matches.
+         // r6: capture start index
+         __ CmpS64(current_input_offset(), r6);
+         // Not a zero-length match, restart.
+-        __ bne(&load_char_start_regexp);
++        __ bne(&reload_string_start_minus_one);
+         // Offset from the end is zero if we already reached the end.
+         __ CmpS64(current_input_offset(), Operand::Zero());
+         __ beq(&exit_label_);
+@@ -970,6 +969,11 @@ Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
+         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+       }
+ 
++      __ bind(&reload_string_start_minus_one);
++      // Prepare r2 to initialize registers with its value in the next run.
++      // Must be immediately before the jump to avoid clobbering.
++      __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
++
+       __ b(&load_char_start_regexp);
+     } else {
+       __ mov(r2, Operand(SUCCESS));
+diff --git a/src/regexp/x64/regexp-macro-assembler-x64.cc b/src/regexp/x64/regexp-macro-assembler-x64.cc
+index 89fd2e34f1296113c43f16896d8f35d741782709..7c59534aa46c4c1c6fed151d7dad13070d133f47 100644
+--- a/src/regexp/x64/regexp-macro-assembler-x64.cc
++++ b/src/regexp/x64/regexp-macro-assembler-x64.cc
+@@ -951,19 +951,18 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
+       __ addq(Operand(rbp, kRegisterOutput),
+               Immediate(num_saved_registers_ * kIntSize));
+ 
+-      // Prepare rax to initialize registers with its value in the next run.
+-      __ movq(rax, Operand(rbp, kStringStartMinusOne));
+-
+       // Restore the original regexp stack pointer value (effectively, pop the
+       // stored base pointer).
+       PopRegExpBasePointer(backtrack_stackpointer(), kScratchRegister);
+ 
++      Label reload_string_start_minus_one;
++
+       if (global_with_zero_length_check()) {
+         // Special case for zero-length matches.
+         // rdx: capture start index
+         __ cmpq(rdi, rdx);
+         // Not a zero-length match, restart.
+-        __ j(not_equal, &load_char_start_regexp);
++        __ j(not_equal, &reload_string_start_minus_one);
+         // rdi (offset from the end) is zero if we already reached the end.
+         __ testq(rdi, rdi);
+         __ j(zero, &exit_label_, Label::kNear);
+@@ -978,6 +977,11 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
+         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
+       }
+ 
++      __ bind(&reload_string_start_minus_one);
++      // Prepare rax to initialize registers with its value in the next run.
++      // Must be immediately before the jump to avoid clobbering.
++      __ movq(rax, Operand(rbp, kStringStartMinusOne));
++
+       __ jmp(&load_char_start_regexp);
+     } else {
+       __ Move(rax, SUCCESS);
+diff --git a/test/mjsunit/regress/regress-crbug-1439691.js b/test/mjsunit/regress/regress-crbug-1439691.js
+new file mode 100644
+index 0000000000000000000000000000000000000000..6c55835535ab4f42ef0446abf863986962df9e9b
+--- /dev/null
++++ b/test/mjsunit/regress/regress-crbug-1439691.js
+@@ -0,0 +1,7 @@
++// Copyright 2023 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.
++
++function f0() {
++}
++/(?!(a))\1/gudyi[Symbol.replace]("f\uD83D\uDCA9ba\u2603", f0);