[Extensions Bindings] Fix a bad check

crrev.com/33ac37fdb8da49817a14b12205afa06d928476cb added checks that
deleting a property on an object would always succeed, but this isn't
the case. Fix the check and add a test to exercise it.

BUG=None

Review-Url: https://codereview.chromium.org/2835643004
Cr-Commit-Position: refs/heads/master@{#466741}
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc
index a1bb5098..7fba82b 100644
--- a/extensions/renderer/module_system.cc
+++ b/extensions/renderer/module_system.cc
@@ -447,6 +447,16 @@
   }
   std::string name = *v8::String::Utf8Value(v8_module_name);
 
+  // As part of instantiating a module, we delete the getter and replace it with
+  // the property directly. If we're trying to load the same module a second
+  // time, it means something went wrong. Bail out early rather than going
+  // through the initialization process again (since bindings may not expect to
+  // run multiple times).
+  if (!module_system->loaded_modules_.insert(name).second) {
+    Warn(isolate, "Previous API instantiation failed.");
+    return;
+  }
+
   // Switch to our v8 context because we need functions created while running
   // the require()d module to belong to our context, not the current one.
   v8::Context::Scope context_scope(context);
@@ -495,7 +505,17 @@
   if (val->IsObject()) {
     v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(val);
     auto maybe = object->Delete(context, property);
-    CHECK(IsTrue(maybe));
+    if (!maybe.IsJust()) {
+      // In theory, deletion should never result in throwing an error. But
+      // crazier things have happened.
+      NOTREACHED();
+      return;
+    }
+    if (!maybe.FromJust()) {
+      // Deletion can *fail* in certain cases, such as when the script does
+      // Object.freeze(chrome).
+      return;
+    }
     SetProperty(context, object, property, new_field);
   } else {
     NOTREACHED();
@@ -524,6 +544,9 @@
   v8::HandleScope handle_scope(GetIsolate());
   v8::Local<v8::Object> parameters = v8::Object::New(GetIsolate());
   v8::Local<v8::Context> context = context_->v8_context();
+  // Since we reset the accessor here, we remove the record of having loaded the
+  // module.
+  loaded_modules_.erase(module_name);
   SetPrivateProperty(context, parameters, kModuleName,
               ToV8StringUnsafe(GetIsolate(), module_name.c_str()));
   SetPrivateProperty(context, parameters, kModuleField,