From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Igor Sheludko <ishell@chromium.org>
Date: Thu, 1 Jun 2023 10:59:39 +0200
Subject: Merged: [lookup] Robustify LookupIterator against own lookups

... on non-JSReceiver objects.

Bug: chromium:1447430
(cherry picked from commit 515f187ba067ee4a99fdf5198cca2c97abd342fd)

Change-Id: Ib9382d90ce19d6b55ee0b236dd299ded03ade04d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4575069
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/branch-heads/11.4@{#35}
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}

diff --git a/src/objects/lookup-inl.h b/src/objects/lookup-inl.h
index 642d83ff070d6b631a755af78627989878f685a2..22960729c64062b9e8a4abaf6b5ed8d44ccaa2de 100644
--- a/src/objects/lookup-inl.h
+++ b/src/objects/lookup-inl.h
@@ -190,7 +190,7 @@ Handle<Name> PropertyKey::GetName(Isolate* isolate) {
 }
 
 Handle<Name> LookupIterator::name() const {
-  DCHECK(!IsElement(*holder_));
+  DCHECK_IMPLIES(!holder_.is_null(), !IsElement(*holder_));
   return name_;
 }
 
@@ -281,6 +281,7 @@ void LookupIterator::UpdateProtector() {
 }
 
 InternalIndex LookupIterator::descriptor_number() const {
+  DCHECK(!holder_.is_null());
   DCHECK(!IsElement(*holder_));
   DCHECK(has_property_);
   DCHECK(holder_->HasFastProperties(isolate_));
@@ -288,6 +289,7 @@ InternalIndex LookupIterator::descriptor_number() const {
 }
 
 InternalIndex LookupIterator::dictionary_entry() const {
+  DCHECK(!holder_.is_null());
   DCHECK(!IsElement(*holder_));
   DCHECK(has_property_);
   DCHECK(!holder_->HasFastProperties(isolate_));
@@ -302,13 +304,14 @@ LookupIterator::Configuration LookupIterator::ComputeConfiguration(
 }
 
 // static
-Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
-                                           Handle<Object> lookup_start_object,
-                                           size_t index) {
+MaybeHandle<JSReceiver> LookupIterator::GetRoot(
+    Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
+    Configuration configuration) {
   if (lookup_start_object->IsJSReceiver(isolate)) {
     return Handle<JSReceiver>::cast(lookup_start_object);
   }
-  return GetRootForNonJSReceiver(isolate, lookup_start_object, index);
+  return GetRootForNonJSReceiver(isolate, lookup_start_object, index,
+                                 configuration);
 }
 
 template <class T>
diff --git a/src/objects/lookup.cc b/src/objects/lookup.cc
index e08ebaff089f8ab0a1b347f9eb5befd85e3c115b..920d28ffa81798c2e5fe9e15db016501d72728c6 100644
--- a/src/objects/lookup.cc
+++ b/src/objects/lookup.cc
@@ -42,27 +42,20 @@ PropertyKey::PropertyKey(Isolate* isolate, Handle<Object> key, bool* success) {
   }
 }
 
-LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
-                               Handle<Name> name, Handle<Map> transition_map,
-                               PropertyDetails details, bool has_property)
-    : configuration_(DEFAULT),
-      state_(TRANSITION),
-      has_property_(has_property),
-      interceptor_state_(InterceptorState::kUninitialized),
-      property_details_(details),
-      isolate_(isolate),
-      name_(name),
-      transition_(transition_map),
-      receiver_(receiver),
-      lookup_start_object_(receiver),
-      index_(kInvalidIndex) {
-  holder_ = GetRoot(isolate, lookup_start_object_);
-}
-
 template <bool is_element>
 void LookupIterator::Start() {
   // GetRoot might allocate if lookup_start_object_ is a string.
-  holder_ = GetRoot(isolate_, lookup_start_object_, index_);
+  MaybeHandle<JSReceiver> maybe_holder =
+      GetRoot(isolate_, lookup_start_object_, index_, configuration_);
+  if (!maybe_holder.ToHandle(&holder_)) {
+    // This is an attempt to perform an own property lookup on a non-JSReceiver
+    // that doesn't have any properties.
+    DCHECK(!lookup_start_object_->IsJSReceiver());
+    DCHECK(!check_prototype_chain());
+    has_property_ = false;
+    state_ = NOT_FOUND;
+    return;
+  }
 
   {
     DisallowGarbageCollection no_gc;
@@ -135,19 +128,27 @@ template void LookupIterator::RestartInternal<true>(InterceptorState);
 template void LookupIterator::RestartInternal<false>(InterceptorState);
 
 // static
-Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
-    Isolate* isolate, Handle<Object> lookup_start_object, size_t index) {
-  // Strings are the only objects with properties (only elements) directly on
-  // the wrapper. Hence we can skip generating the wrapper for all other cases.
-  if (lookup_start_object->IsString(isolate) &&
-      index <
-          static_cast<size_t>(String::cast(*lookup_start_object).length())) {
-    // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
-    // context, ensuring that we don't leak it into JS?
-    Handle<JSFunction> constructor = isolate->string_function();
-    Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
-    Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
-    return result;
+MaybeHandle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
+    Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
+    Configuration configuration) {
+  // Strings are the only non-JSReceiver objects with properties (only elements
+  // and 'length') directly on the wrapper. Hence we can skip generating
+  // the wrapper for all other cases.
+  bool own_property_lookup = (configuration & kPrototypeChain) == 0;
+  if (lookup_start_object->IsString(isolate)) {
+    if (own_property_lookup ||
+        index <
+            static_cast<size_t>(String::cast(*lookup_start_object).length())) {
+      // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the
+      // native context, ensuring that we don't leak it into JS?
+      Handle<JSFunction> constructor = isolate->string_function();
+      Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
+      Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
+      return result;
+    }
+  } else if (own_property_lookup) {
+    // Signal that the lookup will not find anything.
+    return {};
   }
   Handle<HeapObject> root(
       lookup_start_object->GetPrototypeChainRootMap(isolate).prototype(isolate),
@@ -903,6 +904,7 @@ Handle<Object> LookupIterator::FetchValue(
 }
 
 bool LookupIterator::IsConstFieldValueEqualTo(Object value) const {
+  DCHECK(!holder_.is_null());
   DCHECK(!IsElement(*holder_));
   DCHECK(holder_->HasFastProperties(isolate_));
   DCHECK_EQ(PropertyLocation::kField, property_details_.location());
@@ -944,6 +946,7 @@ bool LookupIterator::IsConstFieldValueEqualTo(Object value) const {
 }
 
 bool LookupIterator::IsConstDictValueEqualTo(Object value) const {
+  DCHECK(!holder_.is_null());
   DCHECK(!IsElement(*holder_));
   DCHECK(!holder_->HasFastProperties(isolate_));
   DCHECK(!holder_->IsJSGlobalObject());
@@ -994,6 +997,7 @@ int LookupIterator::GetAccessorIndex() const {
 
 FieldIndex LookupIterator::GetFieldIndex() const {
   DCHECK(has_property_);
+  DCHECK(!holder_.is_null());
   DCHECK(holder_->HasFastProperties(isolate_));
   DCHECK_EQ(PropertyLocation::kField, property_details_.location());
   DCHECK(!IsElement(*holder_));
@@ -1001,6 +1005,7 @@ FieldIndex LookupIterator::GetFieldIndex() const {
 }
 
 Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
+  DCHECK(!holder_.is_null());
   DCHECK(!IsElement(*holder_));
   Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
   return handle(holder->global_dictionary(isolate_, kAcquireLoad)
diff --git a/src/objects/lookup.h b/src/objects/lookup.h
index 67a8bac22e6e29df2d7df36937565e4cc0acde45..78a00d7ca0fab1ab8b2b1e49e3ffb92473b21cc9 100644
--- a/src/objects/lookup.h
+++ b/src/objects/lookup.h
@@ -222,11 +222,6 @@ class V8_EXPORT_PRIVATE LookupIterator final {
                         Handle<Object> lookup_start_object,
                         Configuration configuration);
 
-  // For |ForTransitionHandler|.
-  LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
-                 Handle<Map> transition_map, PropertyDetails details,
-                 bool has_property);
-
   static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver,
                                       Handle<Name> name);
 
@@ -286,12 +281,12 @@ class V8_EXPORT_PRIVATE LookupIterator final {
                                                    Configuration configuration,
                                                    Handle<Name> name);
 
-  static Handle<JSReceiver> GetRootForNonJSReceiver(
-      Isolate* isolate, Handle<Object> lookup_start_object,
-      size_t index = kInvalidIndex);
-  static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
-                                           Handle<Object> lookup_start_object,
-                                           size_t index = kInvalidIndex);
+  static MaybeHandle<JSReceiver> GetRootForNonJSReceiver(
+      Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
+      Configuration configuration);
+  static inline MaybeHandle<JSReceiver> GetRoot(
+      Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
+      Configuration configuration);
 
   State NotFound(JSReceiver const holder) const;
 
diff --git a/test/mjsunit/regress/regress-crbug-1447430.js b/test/mjsunit/regress/regress-crbug-1447430.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7bb3e72e3af1b9f8c2fa82faeeb2d813fe6ab3c
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-1447430.js
@@ -0,0 +1,34 @@
+// 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.
+
+// Flags: --allow-natives-syntax
+
+var s = %CreatePrivateSymbol('x');
+
+(function TestSmi() {
+  function f(o, p) {
+    o[p] = 153;
+  }
+  (1).__proto__[s] = 42;
+  %PrepareFunctionForOptimization(f);
+  assertEquals(f(42, s), undefined);
+}());
+
+(function TestString() {
+  function f(o, p) {
+    o[p] = 153;
+  }
+  ('xyz').__proto__[s] = 42;
+  %PrepareFunctionForOptimization(f);
+  assertEquals(f('abc', s), undefined);
+}());
+
+(function TestSymbol() {
+  function f(o, p) {
+    o[p] = 153;
+  }
+  Symbol('xyz').__proto__[s] = 42;
+  %PrepareFunctionForOptimization(f);
+  assertEquals(f(Symbol('abc'), s), undefined);
+}());
