Bug 828472 - Introduce AutoJSContext and SafeAutoJSContext helpers and use them for date handling in nsHTMLInputElement. f=bz r=bholley a=bajaj
authorMounir Lamouri <mounir.lamouri@gmail.com>
Wed, 23 Jan 2013 19:25:44 +0000
changeset 128037 87a9433cbc1cebe3119ed48f33ee4d431f7a22de
parent 128036 771d87a4fc1a39a01db8555b6d3c105b11df8af4
child 128038 d8040799b82aeab7ba9a15b3d5182d6bc6cb64b1
push id297
push userlsblakk@mozilla.com
push dateTue, 26 Mar 2013 17:28:00 +0000
treeherdermozilla-release@64d7b45c34e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley, bajaj
bugs828472
milestone20.0a2
Bug 828472 - Introduce AutoJSContext and SafeAutoJSContext helpers and use them for date handling in nsHTMLInputElement. f=bz r=bholley a=bajaj
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/html/content/crashtests/828472.html
content/html/content/crashtests/crashtests.list
content/html/content/src/nsHTMLInputElement.cpp
mfbt/GuardObjects.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -2285,16 +2285,53 @@ public:
     nsContentUtils::EnterMicroTask();
   }
   ~nsAutoMicroTask()
   {
     nsContentUtils::LeaveMicroTask();
   }
 };
 
+namespace mozilla {
+
+/**
+ * Use AutoJSContext when you need a JS context on the stack but don't have one
+ * passed as a parameter. AutoJSContext will take care of finding the most
+ * appropriate JS context and release it when leaving the stack.
+ */
+class NS_STACK_CLASS AutoJSContext {
+public:
+  AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
+  operator JSContext*();
+
+protected:
+  AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+private:
+  // We need this Init() method because we can't use delegating constructor for
+  // the moment. It is a C++11 feature and we do not require C++11 to be
+  // supported to be able to compile Gecko.
+  void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+  JSContext* mCx;
+  nsCxPusher mPusher;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/**
+ * SafeAutoJSContext is similar to AutoJSContext but will only return the safe
+ * JS context. That means it will never call ::GetCurrentJSContext().
+ */
+class NS_STACK_CLASS SafeAutoJSContext : public AutoJSContext {
+public:
+  SafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
+};
+
+} // namespace mozilla
+
 #define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator)                \
   if (aIID.Equals(NS_GET_IID(_interface))) {                                  \
     foundInterface = static_cast<_interface *>(_allocator);                   \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nullptr;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } else
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6964,8 +6964,50 @@ nsContentUtils::InternalIsSupported(nsIS
     return (aVersion.IsEmpty() || aVersion.EqualsLiteral("1.0") ||
             aVersion.EqualsLiteral("1.1")) &&
            nsSVGFeatures::HasFeature(aObject, aFeature);
   }
 
   // Otherwise, we claim to support everything
   return true;
 }
+
+AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
+  : mCx(nullptr)
+{
+  Init(false MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
+}
+
+AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+  : mCx(nullptr)
+{
+  Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
+}
+
+void
+AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+{
+  MOZ_ASSERT(!mCx, "mCx should not be initialized!");
+
+  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+
+  if (!aSafe) {
+    mCx = nsContentUtils::GetCurrentJSContext();
+  }
+
+  if (!mCx) {
+    mCx = nsContentUtils::GetSafeJSContext();
+    bool result = mPusher.Push(mCx);
+    if (!result || !mCx) {
+      MOZ_CRASH();
+    }
+  }
+}
+
+AutoJSContext::operator JSContext*()
+{
+  return mCx;
+}
+
+SafeAutoJSContext::SafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
+  : AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
+{
+}
new file mode 100644
--- /dev/null
+++ b/content/html/content/crashtests/828472.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type='date' value='2013-01-01'>
+</body>
+</html>
--- a/content/html/content/crashtests/crashtests.list
+++ b/content/html/content/crashtests/crashtests.list
@@ -39,9 +39,10 @@ load 741250.xhtml
 load 795221-1.html
 load 795221-2.html
 load 795221-3.html
 load 795221-4.html
 load 795221-5.xml
 load 798802-1.html
 load 811226.html
 load 819745.html
+pref(dom.experimental_forms,true) load 828472.html
 load 828180.html
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -31,17 +31,16 @@
 #include "nsFormSubmissionConstants.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsIFormControlFrame.h"
 #include "nsITextControlFrame.h"
 #include "nsIFrame.h"
 #include "nsEventStates.h"
 #include "nsIServiceManager.h"
-#include "nsIScriptSecurityManager.h"
 #include "nsError.h"
 #include "nsIEditor.h"
 #include "nsGUIEvent.h"
 #include "nsIIOService.h"
 #include "nsDocument.h"
 #include "nsAttrValueOrString.h"
 
 #include "nsPresState.h"
@@ -1075,20 +1074,18 @@ nsHTMLInputElement::ConvertStringToNumbe
         if (NS_FAILED(ec)) {
           return false;
         }
 
         return true;
       }
     case NS_FORM_INPUT_DATE:
       {
-        JSContext* ctx = nsContentUtils::GetContextFromDocument(OwnerDoc());
-        if (!ctx) {
-          return false;
-        }
+        SafeAutoJSContext ctx;
+        JSAutoRequest ar(ctx);
 
         uint32_t year, month, day;
         if (!GetValueAsDate(aValue, year, month, day)) {
           return false;
         }
 
         JSObject* date = JS_NewDateObjectMsec(ctx, 0);
         if (!date) {
@@ -1235,20 +1232,18 @@ nsHTMLInputElement::ConvertNumberToStrin
   aResultString.Truncate();
 
   switch (mType) {
     case NS_FORM_INPUT_NUMBER:
       aResultString.AppendFloat(aValue);
       return true;
     case NS_FORM_INPUT_DATE:
       {
-        JSContext* ctx = nsContentUtils::GetContextFromDocument(OwnerDoc());
-        if (!ctx) {
-          return false;
-        }
+        SafeAutoJSContext ctx;
+        JSAutoRequest ar(ctx);
 
         // The specs require |aValue| to be truncated.
         aValue = floor(aValue);
 
         JSObject* date = JS_NewDateObjectMsec(ctx, aValue);
         if (!date) {
           JS_ClearPendingException(ctx);
           return false;
--- a/mfbt/GuardObjects.h
+++ b/mfbt/GuardObjects.h
@@ -121,27 +121,30 @@ class MOZ_EXPORT GuardObjectNotification
 #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \
      , const mozilla::detail::GuardObjectNotifier& _notifier = \
          mozilla::detail::GuardObjectNotifier()
 #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \
      const mozilla::detail::GuardObjectNotifier& _notifier = \
          mozilla::detail::GuardObjectNotifier()
 #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \
      , const mozilla::detail::GuardObjectNotifier& _notifier
+#  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \
+     const mozilla::detail::GuardObjectNotifier& _notifier
 #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \
      , _notifier
 #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \
        _notifier
 #  define MOZ_GUARD_OBJECT_NOTIFIER_INIT \
      do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0)
 #else
 #  define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM
 #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM
 #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL
+#  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL
 #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT
 #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
 #  define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0)
 #endif
 
 #endif /* __cplusplus */
 
 #endif /* mozilla_GuardObjects_h */