1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /* Library-private header for Interface Info system. */
7 
8 #ifndef xptiprivate_h___
9 #define xptiprivate_h___
10 
11 #include "nscore.h"
12 #include <new>
13 #include "nsISupports.h"
14 
15 // this after nsISupports, to pick up IID
16 // so that xpt stuff doesn't try to define it itself...
17 #include "xpt_struct.h"
18 #include "xpt_xdr.h"
19 
20 #include "nsIInterfaceInfo.h"
21 #include "nsIInterfaceInfoManager.h"
22 #include "xptinfo.h"
23 #include "ShimInterfaceInfo.h"
24 
25 #include "nsIServiceManager.h"
26 #include "nsIFile.h"
27 #include "nsIDirectoryService.h"
28 #include "nsDirectoryServiceDefs.h"
29 #include "nsAppDirectoryServiceDefs.h"
30 #include "nsIWeakReference.h"
31 
32 #include "mozilla/ReentrantMonitor.h"
33 #include "mozilla/Mutex.h"
34 #include "mozilla/Attributes.h"
35 
36 #include "js/TypeDecls.h"
37 
38 #include "nsCRT.h"
39 #include "nsMemory.h"
40 
41 #include "nsCOMArray.h"
42 #include "nsQuickSort.h"
43 
44 #include "nsString.h"
45 
46 #include "nsIInputStream.h"
47 
48 #include "nsHashKeys.h"
49 #include "nsDataHashtable.h"
50 #include "plstr.h"
51 #include "prprf.h"
52 #include "prio.h"
53 #include "prtime.h"
54 #include "prenv.h"
55 
56 #include <stdio.h>
57 #include <stdarg.h>
58 
59 /***************************************************************************/
60 
61 class xptiInterfaceInfo;
62 class xptiInterfaceEntry;
63 class xptiTypelibGuts;
64 
65 extern XPTArena *gXPTIStructArena;
66 
67 /***************************************************************************/
68 
69 /***************************************************************************/
70 
71 // No virtuals.
72 // These are always constructed in the struct arena using placement new.
73 // dtor need not be called.
74 
75 class xptiTypelibGuts {
76  public:
77   static xptiTypelibGuts *Create(const XPTHeader *aHeader);
78 
GetEntryCount()79   uint16_t GetEntryCount() const { return mHeader->mNumInterfaces; }
80 
SetEntryAt(uint16_t i,xptiInterfaceEntry * ptr)81   void SetEntryAt(uint16_t i, xptiInterfaceEntry *ptr) {
82     NS_ASSERTION(mHeader, "bad state!");
83     NS_ASSERTION(i < GetEntryCount(), "bad param!");
84     mEntryArray[i] = ptr;
85   }
86 
87   xptiInterfaceEntry *GetEntryAt(uint16_t i);
88   const char *GetEntryNameAt(uint16_t i);
89 
90  private:
xptiTypelibGuts(const XPTHeader * aHeader)91   explicit xptiTypelibGuts(const XPTHeader *aHeader) : mHeader(aHeader) {}
92   ~xptiTypelibGuts();
93 
94  private:
95   const XPTHeader *mHeader;            // hold pointer into arena
96   xptiInterfaceEntry *mEntryArray[1];  // Always last. Sized to fit.
97 };
98 
99 /***************************************************************************/
100 
101 /***************************************************************************/
102 
103 // This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value
104 // and a set of bitflags in one 8bit value. See below.
105 
106 class xptiInfoFlags {
107   enum { STATE_MASK = 3 };
108 
109  public:
xptiInfoFlags(uint8_t n)110   explicit xptiInfoFlags(uint8_t n) : mData(n) {}
xptiInfoFlags(const xptiInfoFlags & r)111   xptiInfoFlags(const xptiInfoFlags &r) : mData(r.mData) {}
112 
GetStateMask()113   static uint8_t GetStateMask() { return uint8_t(STATE_MASK); }
114 
Clear()115   void Clear() { mData = 0; }
116 
GetData()117   uint8_t GetData() const { return mData; }
118 
GetState()119   uint8_t GetState() const { return mData & GetStateMask(); }
120 
SetState(uint8_t state)121   void SetState(uint8_t state) {
122     mData &= ~GetStateMask();
123     mData |= state;
124   }
125 
SetFlagBit(uint8_t flag,bool on)126   void SetFlagBit(uint8_t flag, bool on) {
127     if (on)
128       mData |= ~GetStateMask() & flag;
129     else
130       mData &= GetStateMask() | ~flag;
131   }
132 
GetFlagBit(uint8_t flag)133   bool GetFlagBit(uint8_t flag) const { return (mData & flag) ? true : false; }
134 
135  private:
136   uint8_t mData;
137 };
138 
139 /****************************************************/
140 
141 // No virtual methods.
142 // We always create in the struct arena and construct using "placement new".
143 // No members need dtor calls.
144 
145 class xptiInterfaceEntry {
146  public:
147   static xptiInterfaceEntry *Create(const char *aName, const nsID &aIID,
148                                     const XPTInterfaceDescriptor *aDescriptor,
149                                     xptiTypelibGuts *aTypelib);
150 
151   enum { PARTIALLY_RESOLVED = 1, FULLY_RESOLVED = 2, RESOLVE_FAILED = 3 };
152 
153   // Additional bit flags...
154   enum {
155     SCRIPTABLE = 4,
156     BUILTINCLASS = 8,
157     HASNOTXPCOM = 16,
158     MAIN_PROCESS_SCRIPTABLE_ONLY = 32
159   };
160 
GetResolveState()161   uint8_t GetResolveState() const { return mFlags.GetState(); }
162 
IsFullyResolved()163   bool IsFullyResolved() const {
164     return GetResolveState() == (uint8_t)FULLY_RESOLVED;
165   }
166 
SetScriptableFlag(bool on)167   void SetScriptableFlag(bool on) {
168     mFlags.SetFlagBit(uint8_t(SCRIPTABLE), on);
169   }
GetScriptableFlag()170   bool GetScriptableFlag() const {
171     return mFlags.GetFlagBit(uint8_t(SCRIPTABLE));
172   }
SetBuiltinClassFlag(bool on)173   void SetBuiltinClassFlag(bool on) {
174     mFlags.SetFlagBit(uint8_t(BUILTINCLASS), on);
175   }
GetBuiltinClassFlag()176   bool GetBuiltinClassFlag() const {
177     return mFlags.GetFlagBit(uint8_t(BUILTINCLASS));
178   }
SetMainProcessScriptableOnlyFlag(bool on)179   void SetMainProcessScriptableOnlyFlag(bool on) {
180     mFlags.SetFlagBit(uint8_t(MAIN_PROCESS_SCRIPTABLE_ONLY), on);
181   }
GetMainProcessScriptableOnlyFlag()182   bool GetMainProcessScriptableOnlyFlag() const {
183     return mFlags.GetFlagBit(uint8_t(MAIN_PROCESS_SCRIPTABLE_ONLY));
184   }
185 
186   // AddRef/Release are special and are not considered for the NOTXPCOM flag.
SetHasNotXPCOMFlag()187   void SetHasNotXPCOMFlag() { mFlags.SetFlagBit(HASNOTXPCOM, true); }
GetHasNotXPCOMFlag()188   bool GetHasNotXPCOMFlag() const { return mFlags.GetFlagBit(HASNOTXPCOM); }
189 
GetTheIID()190   const nsID *GetTheIID() const { return &mIID; }
GetTheName()191   const char *GetTheName() const { return mName; }
192 
EnsureResolved()193   bool EnsureResolved() { return IsFullyResolved() ? true : Resolve(); }
194 
195   already_AddRefed<xptiInterfaceInfo> InterfaceInfo();
InterfaceInfoEquals(const xptiInterfaceInfo * info)196   bool InterfaceInfoEquals(const xptiInterfaceInfo *info) const {
197     return info == mInfo;
198   }
199 
200   void LockedInvalidateInterfaceInfo();
LockedInterfaceInfoDeathNotification()201   void LockedInterfaceInfoDeathNotification() { mInfo = nullptr; }
202 
Parent()203   xptiInterfaceEntry *Parent() const {
204     NS_ASSERTION(IsFullyResolved(), "Parent() called while not resolved?");
205     return mParent;
206   }
207 
IID()208   const nsID &IID() const { return mIID; }
209 
210   //////////////////////
211   // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
212 
213   nsresult GetName(char **aName);
214   nsresult GetIID(nsIID **aIID);
215   nsresult IsScriptable(bool *_retval);
IsBuiltinClass(bool * _retval)216   nsresult IsBuiltinClass(bool *_retval) {
217     *_retval = GetBuiltinClassFlag();
218     return NS_OK;
219   }
IsMainProcessScriptableOnly(bool * _retval)220   nsresult IsMainProcessScriptableOnly(bool *_retval) {
221     *_retval = GetMainProcessScriptableOnlyFlag();
222     return NS_OK;
223   }
224   // Except this one.
225   // nsresult GetParent(nsIInterfaceInfo * *aParent);
226   nsresult GetMethodCount(uint16_t *aMethodCount);
227   nsresult GetConstantCount(uint16_t *aConstantCount);
228   nsresult GetMethodInfo(uint16_t index, const nsXPTMethodInfo **info);
229   nsresult GetMethodInfoForName(const char *methodName, uint16_t *index,
230                                 const nsXPTMethodInfo **info);
231   nsresult GetConstant(uint16_t index, JS::MutableHandleValue, char **constant);
232   nsresult GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
233                            nsIInterfaceInfo **_retval);
234   nsresult GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
235                           nsIID **_retval);
236   nsresult GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
237                            uint16_t dimension, nsXPTType *_retval);
238   nsresult GetSizeIsArgNumberForParam(uint16_t methodIndex,
239                                       const nsXPTParamInfo *param,
240                                       uint16_t dimension, uint8_t *_retval);
241   nsresult GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
242                                            const nsXPTParamInfo *param,
243                                            uint8_t *_retval);
244   nsresult IsIID(const nsIID *IID, bool *_retval);
245   nsresult GetNameShared(const char **name);
246   nsresult GetIIDShared(const nsIID **iid);
247   nsresult IsFunction(bool *_retval);
248   nsresult HasAncestor(const nsIID *iid, bool *_retval);
249   nsresult GetIIDForParamNoAlloc(uint16_t methodIndex,
250                                  const nsXPTParamInfo *param, nsIID *iid);
251 
252  private:
253   xptiInterfaceEntry(const char *aName, const nsID &aIID,
254                      const XPTInterfaceDescriptor *aDescriptor,
255                      xptiTypelibGuts *aTypelib);
256   ~xptiInterfaceEntry();
257 
SetResolvedState(int state)258   void SetResolvedState(int state) { mFlags.SetState(uint8_t(state)); }
259 
260   bool Resolve();
261 
262   // We only call these "*Locked" variants after locking. This is done to
263   // allow reentrace as files are loaded and various interfaces resolved
264   // without having to worry about the locked state.
265 
EnsureResolvedLocked()266   bool EnsureResolvedLocked() {
267     return IsFullyResolved() ? true : ResolveLocked();
268   }
269   bool ResolveLocked();
270 
271   // private helpers
272 
273   nsresult GetEntryForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
274                             xptiInterfaceEntry **entry);
275 
276   nsresult GetTypeInArray(const nsXPTParamInfo *param, uint16_t dimension,
277                           const XPTTypeDescriptor **type);
278 
279   nsresult GetInterfaceIndexForParam(uint16_t methodIndex,
280                                      const nsXPTParamInfo *param,
281                                      uint16_t *interfaceIndex);
282 
283   already_AddRefed<ShimInterfaceInfo> GetShimForParam(
284       uint16_t methodIndex, const nsXPTParamInfo *param);
285 
286  private:
287   nsID mIID;
288   const XPTInterfaceDescriptor *mDescriptor;
289 
290   xptiTypelibGuts *mTypelib;
291 
292   xptiInterfaceEntry *mParent;  // Valid only when fully resolved
293 
294   xptiInterfaceInfo *MOZ_UNSAFE_REF(
295       "The safety of this pointer is ensured "
296       "by the semantics of xptiWorkingSet.") mInfo;  // May come and go.
297 
298   uint16_t mMethodBaseIndex;
299   uint16_t mConstantBaseIndex;
300 
301   xptiInfoFlags mFlags;
302 
303   const char *mName;
304 };
305 
306 class xptiInterfaceInfo final : public nsIInterfaceInfo {
307  public:
308   NS_DECL_THREADSAFE_ISUPPORTS
309 
310   // Use delegation to implement (most!) of nsIInterfaceInfo.
GetName(char ** aName)311   NS_IMETHOD GetName(char **aName) override {
312     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName);
313   }
GetInterfaceIID(nsIID ** aIID)314   NS_IMETHOD GetInterfaceIID(nsIID **aIID) override {
315     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID);
316   }
IsScriptable(bool * _retval)317   NS_IMETHOD IsScriptable(bool *_retval) override {
318     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval);
319   }
IsBuiltinClass(bool * _retval)320   NS_IMETHOD IsBuiltinClass(bool *_retval) override {
321     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval);
322   }
IsMainProcessScriptableOnly(bool * _retval)323   NS_IMETHOD IsMainProcessScriptableOnly(bool *_retval) override {
324     return !mEntry ? NS_ERROR_UNEXPECTED
325                    : mEntry->IsMainProcessScriptableOnly(_retval);
326   }
327   // Except this one.
GetParent(nsIInterfaceInfo ** aParent)328   NS_IMETHOD GetParent(nsIInterfaceInfo **aParent) override {
329     if (!EnsureResolved() || !EnsureParent()) return NS_ERROR_UNEXPECTED;
330     NS_IF_ADDREF(*aParent = mParent);
331     return NS_OK;
332   }
GetMethodCount(uint16_t * aMethodCount)333   NS_IMETHOD GetMethodCount(uint16_t *aMethodCount) override {
334     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount);
335   }
GetConstantCount(uint16_t * aConstantCount)336   NS_IMETHOD GetConstantCount(uint16_t *aConstantCount) override {
337     return !mEntry ? NS_ERROR_UNEXPECTED
338                    : mEntry->GetConstantCount(aConstantCount);
339   }
GetMethodInfo(uint16_t index,const nsXPTMethodInfo ** info)340   NS_IMETHOD GetMethodInfo(uint16_t index,
341                            const nsXPTMethodInfo **info) override {
342     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info);
343   }
GetMethodInfoForName(const char * methodName,uint16_t * index,const nsXPTMethodInfo ** info)344   NS_IMETHOD GetMethodInfoForName(const char *methodName, uint16_t *index,
345                                   const nsXPTMethodInfo **info) override {
346     return !mEntry ? NS_ERROR_UNEXPECTED
347                    : mEntry->GetMethodInfoForName(methodName, index, info);
348   }
GetConstant(uint16_t index,JS::MutableHandleValue constant,char ** name)349   NS_IMETHOD GetConstant(uint16_t index, JS::MutableHandleValue constant,
350                          char **name) override {
351     return !mEntry ? NS_ERROR_UNEXPECTED
352                    : mEntry->GetConstant(index, constant, name);
353   }
GetInfoForParam(uint16_t methodIndex,const nsXPTParamInfo * param,nsIInterfaceInfo ** _retval)354   NS_IMETHOD GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
355                              nsIInterfaceInfo **_retval) override {
356     return !mEntry ? NS_ERROR_UNEXPECTED
357                    : mEntry->GetInfoForParam(methodIndex, param, _retval);
358   }
GetIIDForParam(uint16_t methodIndex,const nsXPTParamInfo * param,nsIID ** _retval)359   NS_IMETHOD GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
360                             nsIID **_retval) override {
361     return !mEntry ? NS_ERROR_UNEXPECTED
362                    : mEntry->GetIIDForParam(methodIndex, param, _retval);
363   }
GetTypeForParam(uint16_t methodIndex,const nsXPTParamInfo * param,uint16_t dimension,nsXPTType * _retval)364   NS_IMETHOD GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo *param,
365                              uint16_t dimension, nsXPTType *_retval) override {
366     return !mEntry ? NS_ERROR_UNEXPECTED
367                    : mEntry->GetTypeForParam(methodIndex, param, dimension,
368                                              _retval);
369   }
GetSizeIsArgNumberForParam(uint16_t methodIndex,const nsXPTParamInfo * param,uint16_t dimension,uint8_t * _retval)370   NS_IMETHOD GetSizeIsArgNumberForParam(uint16_t methodIndex,
371                                         const nsXPTParamInfo *param,
372                                         uint16_t dimension,
373                                         uint8_t *_retval) override {
374     return !mEntry ? NS_ERROR_UNEXPECTED
375                    : mEntry->GetSizeIsArgNumberForParam(methodIndex, param,
376                                                         dimension, _retval);
377   }
GetInterfaceIsArgNumberForParam(uint16_t methodIndex,const nsXPTParamInfo * param,uint8_t * _retval)378   NS_IMETHOD GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
379                                              const nsXPTParamInfo *param,
380                                              uint8_t *_retval) override {
381     return !mEntry ? NS_ERROR_UNEXPECTED
382                    : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param,
383                                                              _retval);
384   }
IsIID(const nsIID * IID,bool * _retval)385   NS_IMETHOD IsIID(const nsIID *IID, bool *_retval) override {
386     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval);
387   }
GetNameShared(const char ** name)388   NS_IMETHOD GetNameShared(const char **name) override {
389     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name);
390   }
GetIIDShared(const nsIID ** iid)391   NS_IMETHOD GetIIDShared(const nsIID **iid) override {
392     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid);
393   }
IsFunction(bool * _retval)394   NS_IMETHOD IsFunction(bool *_retval) override {
395     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval);
396   }
HasAncestor(const nsIID * iid,bool * _retval)397   NS_IMETHOD HasAncestor(const nsIID *iid, bool *_retval) override {
398     return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval);
399   }
GetIIDForParamNoAlloc(uint16_t methodIndex,const nsXPTParamInfo * param,nsIID * iid)400   NS_IMETHOD GetIIDForParamNoAlloc(uint16_t methodIndex,
401                                    const nsXPTParamInfo *param,
402                                    nsIID *iid) override {
403     return !mEntry ? NS_ERROR_UNEXPECTED
404                    : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid);
405   }
406 
407  public:
408   explicit xptiInterfaceInfo(xptiInterfaceEntry *entry);
409 
410   void Invalidate();
411 
412  private:
413   ~xptiInterfaceInfo();
414 
415   // Note that mParent might still end up as nullptr if we don't have one.
EnsureParent()416   bool EnsureParent() {
417     NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call");
418     return mParent || !mEntry->Parent() || BuildParent();
419   }
420 
EnsureResolved()421   bool EnsureResolved() { return mEntry && mEntry->EnsureResolved(); }
422 
423   bool BuildParent();
424 
425   xptiInterfaceInfo();  // not implemented
426 
427  private:
428   xptiInterfaceEntry *mEntry;
429   RefPtr<xptiInterfaceInfo> mParent;
430 };
431 
432 /***************************************************************************/
433 
434 #endif /* xptiprivate_h___ */
435