Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
11 KiB

  1. //
  2. // validate.h
  3. //
  4. // Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
  5. //
  6. // Parameter validation macros
  7. //
  8. // Summary:
  9. //
  10. // V_INAME(interfacename) - Set the interface name for error display
  11. // V_STRUCTPTR_READ(ptr,type) - A dwSize struct which we will read
  12. // V_STRUCTPTR_WRITE(ptr,type) - A dwSize struct which we will read/write
  13. // V_PTR_READ(ptr,type) - A typed ptr w/o a dwSize which we will read
  14. // V_PTR_WRITE(ptr,type) - A typed ptr w/o a dwSize which we will read/write
  15. // V_PTR_WRITE_OPT(ptr,type) - An optional typed ptr w/o a dwSize which we will read/write
  16. // V_BUFPTR_READ(ptr,size) - A variable-size buffer that we will read
  17. // V_BUFPTR_READ_OPT(ptr,size) - An optional variable-size buffer that we will read
  18. // V_BUFPTR_WRITE(ptr,size) - A variable-size buffer that we will read/write
  19. // V_BUFPTR_WRITE_OPT(ptr,size) - An optional variable-size buffer that we will read/write
  20. // V_PTRPTR_WRITE(ptrptr) - A pointer to a pointer to write to
  21. // V_PTRPTR_WRITE_OPT(ptrptr) - A pointer to a pointer to write to that is optional
  22. // V_PUNKOUTER(punk) - A pointer to a controlling unknown, aggregation supported
  23. // V_PUNKOUTER_NOADD(punk) - A pointer to a controlling unknown, aggregation not supported
  24. // V_INTERFACE(ptr) - A pointer to a COM interface
  25. // V_INTERFACE_OPT(ptr) - An optional pointer to a COM interface
  26. // V_REFGUID(ref) - A reference to a GUID (type REFGUID)
  27. // V_HWND(hwnd) - A window handle
  28. // V_HWNDOPT(hwnd) - An optional window handle
  29. //
  30. // For handling different versions of structures:
  31. //
  32. // V_STRUCTPTR_READ_VER(ptr,ver) - Begin a struct version block for read access
  33. // At the end, 'ver' will contain the
  34. // discovered version of the struct
  35. // V_STRUCTPTR_READ_VER_CASE(base,ver) - Test struct against version ver of
  36. // type 'base'.
  37. // V_STRUCTPTR_READ_VER_END(base,ptr) - End a struct version block
  38. //
  39. // V_STRUCTPTR_WRITE_VER(ptr,ver) - Struct version block for write access
  40. // V_STRUCTPTR_WRITE_VER_CASE(base,ver)
  41. // V_STRUCTPTR_WRITE_VER_END(base,ptr)
  42. //
  43. // The struct version block expects type names of a base type followed by a
  44. // numeric version, such as
  45. //
  46. // typedef struct { } FOO7;
  47. // typedef struct { } FOO8;
  48. //
  49. // In the header FOO and LPFOO are conditionally typedef'd based on a version
  50. // #define. The DLL will be compiled with the latest version number and hence
  51. // the largest version of the struct.
  52. //
  53. // Since Windows headers are compiled by default with 8-byte alignment, adding
  54. // one DWORD may not cause the size of the structure to change. If this happens
  55. // you will get a 'case label already used' error on one of the VER_CASE macros.
  56. // If this happens, you can get around it by adding a dwReserved field to the
  57. // end of the struct to force the padding.
  58. //
  59. // 'optional' means the pointer is allowed to be NULL by the interface specification.
  60. //
  61. // Sample usage:
  62. //
  63. // int IDirectMusic::SetFooBarInterface(
  64. // LPDMUS_REQUESTED_CAPS pCaps, // Caps w/ dwSize (read-only)
  65. // LPVOID pBuffer, // Buffer we will fill in
  66. // DWORD cbSize, // Size of the buffer
  67. // PDIRECTMUSICBAR pBar) // Callback interface for bar on this buffer
  68. // {
  69. // V_INTERFACE(IDirectMusic::SetFooBarInterface);
  70. // V_BUFPTR_WRITE(pBuffer, cbSize);
  71. // V_INTERFACE(pBar);
  72. // DWORD dwCapsVer; // Must be a DWORD!!!
  73. //
  74. // V_STRUCTPTR_READ_VER(pCaps, dwCapsVer);
  75. // V_STRUCTPTR_READ_VER_CASE(DMUS_REQUESTED_CAPS, 7);
  76. // V_STRUCTPTR_READ_VER_CASE(DMUS_REQUESTED_CAPS, 8);
  77. // V_STRUCTPTR_READ_VER_END_(DMUS_REQUESTED_CAPS, pCaps);
  78. //
  79. // // At this point, if we are still in the function we have a valid pCaps
  80. // // pointer and dwCapsVer is either 7 or 8, indicating the version of
  81. // // the struct passed in.
  82. //
  83. // ...
  84. // }
  85. //
  86. #ifndef _VALIDATE_H_
  87. #define _VALIDATE_H_
  88. #ifdef DBG
  89. #include <stddef.h>
  90. #include "debug.h"
  91. // To turn on DebugBreak on parameter error, use the following or -DRIP_BREAK in the build:
  92. //
  93. //#define RIP_BREAK 1
  94. #ifdef RIP_BREAK
  95. #define _RIP_BREAK DebugBreak();
  96. #else
  97. #define _RIP_BREAK
  98. #endif
  99. #define V_INAME(x) \
  100. static const char __szValidateInterfaceName[] = #x;
  101. #define RIP_E_POINTER(ptr) \
  102. { Trace(-1, "%s: Invalid pointer " #ptr "\n", __szValidateInterfaceName); \
  103. _RIP_BREAK \
  104. return E_POINTER; }
  105. #define RIP_E_INVALIDARG(ptr) \
  106. { Trace(-1, "%s: Invalid argument " #ptr "\n", __szValidateInterfaceName); \
  107. _RIP_BREAK \
  108. return E_INVALIDARG; }
  109. #define RIP_E_HANDLE(h) \
  110. { Trace(-1, "%s: Invalid handle " #h "\n", __szValidateInterfaceName); \
  111. _RIP_BREAK \
  112. return E_HANDLE; }
  113. #define RIP_W_INVALIDSIZE(ptr) \
  114. { Trace(-1, "%s: " #ptr "->dwSize matches no known structure size. Defaulting to oldest structure.\n", \
  115. __szValidateInterfaceName); \
  116. _RIP_BREAK \
  117. }
  118. #define RIP_E_INVALIDSIZE(ptr) \
  119. { Trace(-1, "%s: " #ptr "->dwSize is too small\n", __szValidateInterfaceName); \
  120. _RIP_BREAK \
  121. return E_INVALIDARG; }
  122. #define RIP_E_BLOCKVSDWSIZE(ptr) \
  123. { Trace(-1, "%s: " #ptr " does not point to as much memory as " #ptr "->dwSize indicates\n", \
  124. __szValidateInterfaceName); \
  125. _RIP_BREAK \
  126. return E_INVALIDARG; }
  127. // NOTE: The DebugBreak() not in #ifdef is intentional - this is something that
  128. // must be fixed in our code, not an app-generated error.
  129. //
  130. #define V_ASSERT(exp) \
  131. { if (!(exp)) { \
  132. Trace(-1, "%s@%s: %s\n", __FILE__, __LINE__, #exp); \
  133. DebugBreak(); }}
  134. #else
  135. #define V_INAME(x)
  136. #define RIP_E_POINTER(ptr) { return E_POINTER; }
  137. #define RIP_E_INVALIDARG(ptr) { return E_INVALIDARG; }
  138. #define RIP_E_HANDLE(h) { return E_HANDLE; }
  139. #define RIP_E_BLOCKVSDWSIZE(ptr) { return E_INVALIDARG; }
  140. #define RIP_W_INVALIDSIZE(ptr)
  141. #define RIP_E_INVALIDSIZE(ptr) { return E_INVALIDARG; }
  142. #define V_ASSERT(exp)
  143. #endif // DBG
  144. // A passed struct we will only read from or may write to. Must be a struct
  145. // with a dwSize.
  146. //
  147. // int foo(CFoo *pFoo)
  148. // ...
  149. // V_STRUCTPTR_READ(pFoo, CFoo);
  150. // V_STRUCTPTR_WRITE(pFoo, CFoo);
  151. //
  152. // Use _PTR_ variants for structs w/o a dwSize
  153. //
  154. #define V_STRUCTPTR_READ(ptr,type) \
  155. { V_ASSERT(offsetof(type, dwSize) == 0); \
  156. if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
  157. if (ptr->dwSize < sizeof(type)) RIP_E_INVALIDSIZE(ptr); \
  158. if (IsBadReadPtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); }
  159. #define V_STRUCTPTR_WRITE(ptr,type) \
  160. { V_ASSERT(offsetof(type, dwSize) == 0); \
  161. if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
  162. if (ptr->dwSize < sizeof(type)) RIP_E_INVALIDSIZE(ptr); \
  163. if (IsBadWritePtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); }
  164. #define V_PTR_READ(ptr,type) \
  165. { if (IsBadReadPtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
  166. #define V_PTR_WRITE(ptr,type) \
  167. { if (IsBadWritePtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
  168. #define V_PTR_WRITE_OPT(ptr,type) \
  169. { if (ptr) if (IsBadWritePtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
  170. // A buffer pointer with separate length (not defined by the pointer type) we will only
  171. // read from or may write to.
  172. //
  173. // int foo(LPVOID *pBuffer, DWORD cbBuffer)
  174. // ...
  175. // V_BUFPTR_READ(pBuffer, cbBuffer);
  176. // V_BUFPTR_WRITE(pBuffer, cbBuffer);
  177. //
  178. #define V_BUFPTR_READ(ptr,len) \
  179. { if (IsBadReadPtr(ptr, len)) RIP_E_POINTER(ptr); }
  180. #define V_BUFPTR_READ_OPT(ptr,len) \
  181. { if (ptr) V_BUFPTR_READ(ptr,len); }
  182. #define V_BUFPTR_WRITE(ptr,len) \
  183. { if (IsBadWritePtr(ptr, len)) RIP_E_POINTER(ptr); }
  184. #define V_BUFPTR_WRITE_OPT(ptr,len) \
  185. { if (ptr) V_BUFPTR_WRITE(ptr,len); }
  186. // A pointer to a pointer (such as a pointer to an interface pointer) to return
  187. //
  188. // int foo(IReturnMe **ppRet)
  189. // ...
  190. // V_PTRPTR_WRITE(ppRet);
  191. // V_PTRPTR_WRITE_OPT(ppRet);
  192. //
  193. #define V_PTRPTR_WRITE(ptr) \
  194. { if (IsBadWritePtr(ptr, sizeof(void*))) RIP_E_POINTER(ptr); }
  195. #define V_PTRPTR_WRITE_OPT(ptr) \
  196. { if (ptr) if (IsBadWritePtr(ptr, sizeof(void*))) RIP_E_POINTER(ptr); }
  197. // A pointer to a controlling unknown
  198. //
  199. #define V_PUNKOUTER(punk) \
  200. { if (punk && IsBadCodePtr(punk)) RIP_E_POINTER(ptr); }
  201. // A pointer to a controlling unknown for which we don't support aggregation
  202. //
  203. #define V_PUNKOUTER_NOAGG(punk) \
  204. { if (punk && IsBadReadPtr(punk, sizeof(IUnknown))) RIP_E_POINTER(ptr); \
  205. if (punk) return CLASS_E_NOAGGREGATION; }
  206. // Validate an incoming interface pointer.
  207. //
  208. struct _V_GENERIC_INTERFACE
  209. {
  210. FARPROC *(__vptr[1]);
  211. };
  212. #define V_INTERFACE(ptr) \
  213. { if (IsBadReadPtr(ptr, sizeof(_V_GENERIC_INTERFACE))) RIP_E_POINTER(ptr); \
  214. if (IsBadReadPtr(*reinterpret_cast<_V_GENERIC_INTERFACE*>(ptr)->__vptr, sizeof(FARPROC))) \
  215. RIP_E_POINTER(ptr); \
  216. if (IsBadCodePtr(*(reinterpret_cast<_V_GENERIC_INTERFACE*>(ptr)->__vptr)[0])) RIP_E_POINTER(ptr); }
  217. #define V_INTERFACE_OPT(ptr) \
  218. { if (ptr) V_INTERFACE(ptr); }
  219. // Validation for a reference to a GUID, which we only ever read.
  220. //
  221. #define V_REFGUID(ref) \
  222. { if (IsBadReadPtr((void*)&ref, sizeof(GUID))) RIP_E_POINTER((void*)&ref); }
  223. // Validation for a window handle
  224. //
  225. #define V_HWND(h) \
  226. { if (!IsWindow(h)) RIP_E_HANDLE(h); }
  227. #define V_HWND_OPT(h) \
  228. { if (h) if (!IsWindow(h)) RIP_E_HANDLE(h); }
  229. // Validation for multiple sized structs based on version
  230. //
  231. #define V_STRUCTPTR_READ_VER(ptr,ver) \
  232. { ver = 7; DWORD *pdw = &ver; \
  233. if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
  234. if (IsBadReadPtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); \
  235. switch ((ptr)->dwSize) {
  236. #define V_STRUCTPTR_READ_VER_CASE(basetype,ver) \
  237. case sizeof(basetype##ver) : \
  238. V_ASSERT(offsetof(basetype##ver, dwSize) == 0); \
  239. *pdw = ver; break;
  240. #define V_STRUCTPTR_READ_VER_END(basetype,ptr) \
  241. default : if ((ptr)->dwSize > sizeof(basetype##7)) \
  242. { RIP_W_INVALIDSIZE(ptr); } else \
  243. RIP_E_INVALIDSIZE(ptr); }}
  244. #define V_STRUCTPTR_WRITE_VER(ptr,ver) \
  245. { ver = 7; DWORD *pdw = &ver; \
  246. if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
  247. if (IsBadWritePtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); \
  248. switch ((ptr)->dwSize) {
  249. #define V_STRUCTPTR_WRITE_VER_CASE(basetype,ver) \
  250. case sizeof(basetype##ver) : \
  251. V_ASSERT(offsetof(basetype##ver, dwSize) == 0); \
  252. *pdw = ver; break;
  253. #define V_STRUCTPTR_WRITE_VER_END(basetype,ptr) \
  254. default : if ((ptr)->dwSize > sizeof(basetype##7)) \
  255. { RIP_W_INVALIDSIZE(ptr); } else \
  256. RIP_E_INVALIDSIZE(ptr); }}
  257. #endif // _VALIDATE_H_