Bug 1151506 - Work around broken binary callers of xptiInterfaceInfo. r=froydnj, a=lizzard FIREFOX_BETA_39_END
authorDavid Major <dmajor@mozilla.com>
Fri, 26 Jun 2015 10:33:44 -0700
changeset 253644 0b0822cabbb95d8509852f90c0b7df5da0a4cabc
parent 253643 dc755335675692c7ed47a905836cc78f8a4857c5
child 261013 d7ae899c30482f2d0c1be5e2f8ad101e45b2aa84
child 354555 97898caf1b72478a85caecff0627bef1eab6671c
push id4829
push userryanvm@gmail.com
push dateFri, 26 Jun 2015 17:50:40 +0000
treeherdermozilla-esr52@0b0822cabbb9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj, lizzard
bugs1151506
milestone39.0
Bug 1151506 - Work around broken binary callers of xptiInterfaceInfo. r=froydnj, a=lizzard CLOSED TREE
xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
xpcom/reflect/xptinfo/xptiprivate.h
--- a/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
+++ b/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
@@ -7,16 +7,20 @@
 
 #include "xptiprivate.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "mozilla/PodOperations.h"
 #include "jsapi.h"
 
+#ifdef XP_WIN
+#include <windows.h>
+#endif
+
 using namespace mozilla;
 
 /***************************************************************************/
 // Debug Instrumentation...
 
 #ifdef SHOW_INFO_COUNT_STATS
 static int DEBUG_TotalInfos = 0;
 static int DEBUG_CurrentInfos = 0;
@@ -761,9 +765,29 @@ xptiInterfaceInfo::Release(void)
         }
 
         delete this;
         return 0;    
     }
     return cnt;
 }
 
+#ifdef XP_WIN
+// static
+void*
+xptiInterfaceInfo::sBrokenModule;
+
+// static
+void*
+xptiInterfaceInfo::GetCaller(void* returnAddress)
+{
+    HMODULE module = nullptr;
+    if (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                            GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                            (LPCTSTR)returnAddress,
+                            &module)) {
+        return module;
+    }
+    return nullptr;
+}
+#endif
+
 /***************************************************************************/
--- a/xpcom/reflect/xptinfo/xptiprivate.h
+++ b/xpcom/reflect/xptinfo/xptiprivate.h
@@ -315,51 +315,79 @@ private:
 
     xptiInterfaceInfo* MOZ_UNSAFE_REF("The safety of this pointer is ensured "
                                       "by the semantics of xptiWorkingSet.")
                             mInfo;        // May come and go.
     xptiInfoFlags           mFlags;
     char                    mName[1];     // Always last. Sized to fit.
 };
 
+// Horrible hack for a high-volume startup crash days before release:
+// Bug 997325 changed the vtable for xptiInterfaceInfo during the Firefox 39
+// cycle. An unknown binary calls these objects with the old vtable offsets.
+// The binary uses a random filename so we can't block it. Our workaround is to
+// detect the broken caller (they pass aConstantCount == 0 to GetConstantCount)
+// and deny further calls on this class from that caller. We do this only for
+// the methods that have different offsets between Firefox 38 and 39.
+#ifdef XP_WIN
+#define MODULE_CHECK \
+    if (sBrokenModule && GetCaller(_ReturnAddress()) == sBrokenModule) \
+        return NS_ERROR_UNEXPECTED
+#else
+#define MODULE_CHECK
+#endif
+
 class xptiInterfaceInfo final : public nsIInterfaceInfo
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
 
     // Use delegation to implement (most!) of nsIInterfaceInfo.
     NS_IMETHOD GetName(char * *aName) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); }
     NS_IMETHOD GetInterfaceIID(nsIID * *aIID) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); }
     NS_IMETHOD IsScriptable(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); }
     NS_IMETHOD IsBuiltinClass(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval); }
-    NS_IMETHOD IsMainProcessScriptableOnly(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsMainProcessScriptableOnly(_retval); }
+    NS_IMETHOD IsMainProcessScriptableOnly(bool *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsMainProcessScriptableOnly(_retval); }
     // Except this one.
     NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) override
     {
+        MODULE_CHECK;
         if(!EnsureResolved() || !EnsureParent())
             return NS_ERROR_UNEXPECTED;
         NS_IF_ADDREF(*aParent = mParent);
         return NS_OK;
     }
-    NS_IMETHOD GetMethodCount(uint16_t *aMethodCount) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); }
-    NS_IMETHOD GetConstantCount(uint16_t *aConstantCount) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); }
-    NS_IMETHOD GetMethodInfo(uint16_t index, const nsXPTMethodInfo * *info) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); }
-    NS_IMETHOD GetMethodInfoForName(const char *methodName, uint16_t *index, const nsXPTMethodInfo * *info) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); }
-    NS_IMETHOD GetConstant(uint16_t index, JS::MutableHandleValue constant, char** name) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant, name); }
-    NS_IMETHOD GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); }
-    NS_IMETHOD GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); }
-    NS_IMETHOD GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, nsXPTType *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); }
-    NS_IMETHOD GetSizeIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, uint8_t *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); }
-    NS_IMETHOD GetInterfaceIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint8_t *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); }
-    NS_IMETHOD IsIID(const nsIID * IID, bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); }
-    NS_IMETHOD GetNameShared(const char **name) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); }
-    NS_IMETHOD GetIIDShared(const nsIID * *iid) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); }
-    NS_IMETHOD IsFunction(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); }
-    NS_IMETHOD HasAncestor(const nsIID * iid, bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); }
-    NS_IMETHOD GetIIDForParamNoAlloc(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID *iid) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); }
+    NS_IMETHOD GetMethodCount(uint16_t *aMethodCount) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); }
+    NS_IMETHOD GetConstantCount(uint16_t *aConstantCount) override
+    {
+        MODULE_CHECK;
+        if (!mEntry)
+            return NS_ERROR_UNEXPECTED;
+        if (!aConstantCount) {
+#ifdef XP_WIN
+            sBrokenModule = GetCaller(_ReturnAddress());
+#endif
+            return NS_ERROR_UNEXPECTED;
+        }
+        return mEntry->GetConstantCount(aConstantCount);
+    }
+    NS_IMETHOD GetMethodInfo(uint16_t index, const nsXPTMethodInfo * *info) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); }
+    NS_IMETHOD GetMethodInfoForName(const char *methodName, uint16_t *index, const nsXPTMethodInfo * *info) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); }
+    NS_IMETHOD GetConstant(uint16_t index, JS::MutableHandleValue constant, char** name) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant, name); }
+    NS_IMETHOD GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); }
+    NS_IMETHOD GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); }
+    NS_IMETHOD GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, nsXPTType *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); }
+    NS_IMETHOD GetSizeIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, uint8_t *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); }
+    NS_IMETHOD GetInterfaceIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint8_t *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); }
+    NS_IMETHOD IsIID(const nsIID * IID, bool *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); }
+    NS_IMETHOD GetNameShared(const char **name) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); }
+    NS_IMETHOD GetIIDShared(const nsIID * *iid) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); }
+    NS_IMETHOD IsFunction(bool *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); }
+    NS_IMETHOD HasAncestor(const nsIID * iid, bool *_retval) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); }
+    NS_IMETHOD GetIIDForParamNoAlloc(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID *iid) override { MODULE_CHECK; return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); }
 
 public:
     explicit xptiInterfaceInfo(xptiInterfaceEntry* entry);
 
     void Invalidate();
 
 private:
 
@@ -379,13 +407,17 @@ private:
 
     bool BuildParent();
 
     xptiInterfaceInfo();  // not implemented
 
 private:
     xptiInterfaceEntry* mEntry;
     nsRefPtr<xptiInterfaceInfo> mParent;
+#ifdef XP_WIN
+    static void* sBrokenModule;
+    static void* GetCaller(void* returnAddress);
+#endif
 };
 
 /***************************************************************************/
 
 #endif /* xptiprivate_h___ */