mirror of https://github.com/tongzx/nt5src
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
302 lines
11 KiB
//
|
|
// validate.h
|
|
//
|
|
// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Parameter validation macros
|
|
//
|
|
// Summary:
|
|
//
|
|
// V_INAME(interfacename) - Set the interface name for error display
|
|
// V_STRUCTPTR_READ(ptr,type) - A dwSize struct which we will read
|
|
// V_STRUCTPTR_WRITE(ptr,type) - A dwSize struct which we will read/write
|
|
// V_PTR_READ(ptr,type) - A typed ptr w/o a dwSize which we will read
|
|
// V_PTR_WRITE(ptr,type) - A typed ptr w/o a dwSize which we will read/write
|
|
// V_PTR_WRITE_OPT(ptr,type) - An optional typed ptr w/o a dwSize which we will read/write
|
|
// V_BUFPTR_READ(ptr,size) - A variable-size buffer that we will read
|
|
// V_BUFPTR_READ_OPT(ptr,size) - An optional variable-size buffer that we will read
|
|
// V_BUFPTR_WRITE(ptr,size) - A variable-size buffer that we will read/write
|
|
// V_BUFPTR_WRITE_OPT(ptr,size) - An optional variable-size buffer that we will read/write
|
|
// V_PTRPTR_WRITE(ptrptr) - A pointer to a pointer to write to
|
|
// V_PTRPTR_WRITE_OPT(ptrptr) - A pointer to a pointer to write to that is optional
|
|
// V_PUNKOUTER(punk) - A pointer to a controlling unknown, aggregation supported
|
|
// V_PUNKOUTER_NOADD(punk) - A pointer to a controlling unknown, aggregation not supported
|
|
// V_INTERFACE(ptr) - A pointer to a COM interface
|
|
// V_INTERFACE_OPT(ptr) - An optional pointer to a COM interface
|
|
// V_REFGUID(ref) - A reference to a GUID (type REFGUID)
|
|
// V_HWND(hwnd) - A window handle
|
|
// V_HWNDOPT(hwnd) - An optional window handle
|
|
//
|
|
// For handling different versions of structures:
|
|
//
|
|
// V_STRUCTPTR_READ_VER(ptr,ver) - Begin a struct version block for read access
|
|
// At the end, 'ver' will contain the
|
|
// discovered version of the struct
|
|
// V_STRUCTPTR_READ_VER_CASE(base,ver) - Test struct against version ver of
|
|
// type 'base'.
|
|
// V_STRUCTPTR_READ_VER_END(base,ptr) - End a struct version block
|
|
//
|
|
// V_STRUCTPTR_WRITE_VER(ptr,ver) - Struct version block for write access
|
|
// V_STRUCTPTR_WRITE_VER_CASE(base,ver)
|
|
// V_STRUCTPTR_WRITE_VER_END(base,ptr)
|
|
//
|
|
// The struct version block expects type names of a base type followed by a
|
|
// numeric version, such as
|
|
//
|
|
// typedef struct { } FOO7;
|
|
// typedef struct { } FOO8;
|
|
//
|
|
// In the header FOO and LPFOO are conditionally typedef'd based on a version
|
|
// #define. The DLL will be compiled with the latest version number and hence
|
|
// the largest version of the struct.
|
|
//
|
|
// Since Windows headers are compiled by default with 8-byte alignment, adding
|
|
// one DWORD may not cause the size of the structure to change. If this happens
|
|
// you will get a 'case label already used' error on one of the VER_CASE macros.
|
|
// If this happens, you can get around it by adding a dwReserved field to the
|
|
// end of the struct to force the padding.
|
|
//
|
|
// 'optional' means the pointer is allowed to be NULL by the interface specification.
|
|
//
|
|
// Sample usage:
|
|
//
|
|
// int IDirectMusic::SetFooBarInterface(
|
|
// LPDMUS_REQUESTED_CAPS pCaps, // Caps w/ dwSize (read-only)
|
|
// LPVOID pBuffer, // Buffer we will fill in
|
|
// DWORD cbSize, // Size of the buffer
|
|
// PDIRECTMUSICBAR pBar) // Callback interface for bar on this buffer
|
|
// {
|
|
// V_INTERFACE(IDirectMusic::SetFooBarInterface);
|
|
// V_BUFPTR_WRITE(pBuffer, cbSize);
|
|
// V_INTERFACE(pBar);
|
|
// DWORD dwCapsVer; // Must be a DWORD!!!
|
|
//
|
|
// V_STRUCTPTR_READ_VER(pCaps, dwCapsVer);
|
|
// V_STRUCTPTR_READ_VER_CASE(DMUS_REQUESTED_CAPS, 7);
|
|
// V_STRUCTPTR_READ_VER_CASE(DMUS_REQUESTED_CAPS, 8);
|
|
// V_STRUCTPTR_READ_VER_END_(DMUS_REQUESTED_CAPS, pCaps);
|
|
//
|
|
// // At this point, if we are still in the function we have a valid pCaps
|
|
// // pointer and dwCapsVer is either 7 or 8, indicating the version of
|
|
// // the struct passed in.
|
|
//
|
|
// ...
|
|
// }
|
|
//
|
|
#ifndef _VALIDATE_H_
|
|
#define _VALIDATE_H_
|
|
|
|
|
|
#ifdef DBG
|
|
#include <stddef.h>
|
|
|
|
#include "debug.h"
|
|
|
|
// To turn on DebugBreak on parameter error, use the following or -DRIP_BREAK in the build:
|
|
//
|
|
//#define RIP_BREAK 1
|
|
|
|
#ifdef RIP_BREAK
|
|
#define _RIP_BREAK DebugBreak();
|
|
#else
|
|
#define _RIP_BREAK
|
|
#endif
|
|
|
|
#define V_INAME(x) \
|
|
static const char __szValidateInterfaceName[] = #x;
|
|
|
|
#define RIP_E_POINTER(ptr) \
|
|
{ Trace(-1, "%s: Invalid pointer " #ptr "\n", __szValidateInterfaceName); \
|
|
_RIP_BREAK \
|
|
return E_POINTER; }
|
|
|
|
#define RIP_E_INVALIDARG(ptr) \
|
|
{ Trace(-1, "%s: Invalid argument " #ptr "\n", __szValidateInterfaceName); \
|
|
_RIP_BREAK \
|
|
return E_INVALIDARG; }
|
|
|
|
#define RIP_E_HANDLE(h) \
|
|
{ Trace(-1, "%s: Invalid handle " #h "\n", __szValidateInterfaceName); \
|
|
_RIP_BREAK \
|
|
return E_HANDLE; }
|
|
|
|
#define RIP_W_INVALIDSIZE(ptr) \
|
|
{ Trace(-1, "%s: " #ptr "->dwSize matches no known structure size. Defaulting to oldest structure.\n", \
|
|
__szValidateInterfaceName); \
|
|
_RIP_BREAK \
|
|
}
|
|
|
|
#define RIP_E_INVALIDSIZE(ptr) \
|
|
{ Trace(-1, "%s: " #ptr "->dwSize is too small\n", __szValidateInterfaceName); \
|
|
_RIP_BREAK \
|
|
return E_INVALIDARG; }
|
|
|
|
#define RIP_E_BLOCKVSDWSIZE(ptr) \
|
|
{ Trace(-1, "%s: " #ptr " does not point to as much memory as " #ptr "->dwSize indicates\n", \
|
|
__szValidateInterfaceName); \
|
|
_RIP_BREAK \
|
|
return E_INVALIDARG; }
|
|
|
|
// NOTE: The DebugBreak() not in #ifdef is intentional - this is something that
|
|
// must be fixed in our code, not an app-generated error.
|
|
//
|
|
#define V_ASSERT(exp) \
|
|
{ if (!(exp)) { \
|
|
Trace(-1, "%s@%s: %s\n", __FILE__, __LINE__, #exp); \
|
|
DebugBreak(); }}
|
|
|
|
#else
|
|
|
|
#define V_INAME(x)
|
|
#define RIP_E_POINTER(ptr) { return E_POINTER; }
|
|
#define RIP_E_INVALIDARG(ptr) { return E_INVALIDARG; }
|
|
#define RIP_E_HANDLE(h) { return E_HANDLE; }
|
|
#define RIP_E_BLOCKVSDWSIZE(ptr) { return E_INVALIDARG; }
|
|
#define RIP_W_INVALIDSIZE(ptr)
|
|
#define RIP_E_INVALIDSIZE(ptr) { return E_INVALIDARG; }
|
|
#define V_ASSERT(exp)
|
|
|
|
#endif // DBG
|
|
|
|
// A passed struct we will only read from or may write to. Must be a struct
|
|
// with a dwSize.
|
|
//
|
|
// int foo(CFoo *pFoo)
|
|
// ...
|
|
// V_STRUCTPTR_READ(pFoo, CFoo);
|
|
// V_STRUCTPTR_WRITE(pFoo, CFoo);
|
|
//
|
|
// Use _PTR_ variants for structs w/o a dwSize
|
|
//
|
|
#define V_STRUCTPTR_READ(ptr,type) \
|
|
{ V_ASSERT(offsetof(type, dwSize) == 0); \
|
|
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
|
if (ptr->dwSize < sizeof(type)) RIP_E_INVALIDSIZE(ptr); \
|
|
if (IsBadReadPtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); }
|
|
|
|
#define V_STRUCTPTR_WRITE(ptr,type) \
|
|
{ V_ASSERT(offsetof(type, dwSize) == 0); \
|
|
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
|
if (ptr->dwSize < sizeof(type)) RIP_E_INVALIDSIZE(ptr); \
|
|
if (IsBadWritePtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); }
|
|
|
|
#define V_PTR_READ(ptr,type) \
|
|
{ if (IsBadReadPtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
|
|
|
|
#define V_PTR_WRITE(ptr,type) \
|
|
{ if (IsBadWritePtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
|
|
|
|
#define V_PTR_WRITE_OPT(ptr,type) \
|
|
{ if (ptr) if (IsBadWritePtr(ptr, sizeof(type))) RIP_E_POINTER(ptr); }
|
|
|
|
// A buffer pointer with separate length (not defined by the pointer type) we will only
|
|
// read from or may write to.
|
|
//
|
|
// int foo(LPVOID *pBuffer, DWORD cbBuffer)
|
|
// ...
|
|
// V_BUFPTR_READ(pBuffer, cbBuffer);
|
|
// V_BUFPTR_WRITE(pBuffer, cbBuffer);
|
|
//
|
|
#define V_BUFPTR_READ(ptr,len) \
|
|
{ if (IsBadReadPtr(ptr, len)) RIP_E_POINTER(ptr); }
|
|
|
|
#define V_BUFPTR_READ_OPT(ptr,len) \
|
|
{ if (ptr) V_BUFPTR_READ(ptr,len); }
|
|
|
|
#define V_BUFPTR_WRITE(ptr,len) \
|
|
{ if (IsBadWritePtr(ptr, len)) RIP_E_POINTER(ptr); }
|
|
|
|
#define V_BUFPTR_WRITE_OPT(ptr,len) \
|
|
{ if (ptr) V_BUFPTR_WRITE(ptr,len); }
|
|
|
|
// A pointer to a pointer (such as a pointer to an interface pointer) to return
|
|
//
|
|
// int foo(IReturnMe **ppRet)
|
|
// ...
|
|
// V_PTRPTR_WRITE(ppRet);
|
|
// V_PTRPTR_WRITE_OPT(ppRet);
|
|
//
|
|
#define V_PTRPTR_WRITE(ptr) \
|
|
{ if (IsBadWritePtr(ptr, sizeof(void*))) RIP_E_POINTER(ptr); }
|
|
|
|
#define V_PTRPTR_WRITE_OPT(ptr) \
|
|
{ if (ptr) if (IsBadWritePtr(ptr, sizeof(void*))) RIP_E_POINTER(ptr); }
|
|
|
|
// A pointer to a controlling unknown
|
|
//
|
|
#define V_PUNKOUTER(punk) \
|
|
{ if (punk && IsBadCodePtr(punk)) RIP_E_POINTER(ptr); }
|
|
|
|
// A pointer to a controlling unknown for which we don't support aggregation
|
|
//
|
|
#define V_PUNKOUTER_NOAGG(punk) \
|
|
{ if (punk && IsBadReadPtr(punk, sizeof(IUnknown))) RIP_E_POINTER(ptr); \
|
|
if (punk) return CLASS_E_NOAGGREGATION; }
|
|
|
|
// Validate an incoming interface pointer.
|
|
//
|
|
struct _V_GENERIC_INTERFACE
|
|
{
|
|
FARPROC *(__vptr[1]);
|
|
};
|
|
|
|
#define V_INTERFACE(ptr) \
|
|
{ if (IsBadReadPtr(ptr, sizeof(_V_GENERIC_INTERFACE))) RIP_E_POINTER(ptr); \
|
|
if (IsBadReadPtr(*reinterpret_cast<_V_GENERIC_INTERFACE*>(ptr)->__vptr, sizeof(FARPROC))) \
|
|
RIP_E_POINTER(ptr); \
|
|
if (IsBadCodePtr(*(reinterpret_cast<_V_GENERIC_INTERFACE*>(ptr)->__vptr)[0])) RIP_E_POINTER(ptr); }
|
|
|
|
#define V_INTERFACE_OPT(ptr) \
|
|
{ if (ptr) V_INTERFACE(ptr); }
|
|
|
|
// Validation for a reference to a GUID, which we only ever read.
|
|
//
|
|
#define V_REFGUID(ref) \
|
|
{ if (IsBadReadPtr((void*)&ref, sizeof(GUID))) RIP_E_POINTER((void*)&ref); }
|
|
|
|
// Validation for a window handle
|
|
//
|
|
#define V_HWND(h) \
|
|
{ if (!IsWindow(h)) RIP_E_HANDLE(h); }
|
|
|
|
#define V_HWND_OPT(h) \
|
|
{ if (h) if (!IsWindow(h)) RIP_E_HANDLE(h); }
|
|
|
|
// Validation for multiple sized structs based on version
|
|
//
|
|
#define V_STRUCTPTR_READ_VER(ptr,ver) \
|
|
{ ver = 7; DWORD *pdw = &ver; \
|
|
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
|
if (IsBadReadPtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); \
|
|
switch ((ptr)->dwSize) {
|
|
|
|
#define V_STRUCTPTR_READ_VER_CASE(basetype,ver) \
|
|
case sizeof(basetype##ver) : \
|
|
V_ASSERT(offsetof(basetype##ver, dwSize) == 0); \
|
|
*pdw = ver; break;
|
|
|
|
#define V_STRUCTPTR_READ_VER_END(basetype,ptr) \
|
|
default : if ((ptr)->dwSize > sizeof(basetype##7)) \
|
|
{ RIP_W_INVALIDSIZE(ptr); } else \
|
|
RIP_E_INVALIDSIZE(ptr); }}
|
|
|
|
|
|
#define V_STRUCTPTR_WRITE_VER(ptr,ver) \
|
|
{ ver = 7; DWORD *pdw = &ver; \
|
|
if (IsBadReadPtr(ptr, sizeof(DWORD))) RIP_E_BLOCKVSDWSIZE(ptr); \
|
|
if (IsBadWritePtr(ptr, (ptr)->dwSize)) RIP_E_BLOCKVSDWSIZE(ptr); \
|
|
switch ((ptr)->dwSize) {
|
|
|
|
#define V_STRUCTPTR_WRITE_VER_CASE(basetype,ver) \
|
|
case sizeof(basetype##ver) : \
|
|
V_ASSERT(offsetof(basetype##ver, dwSize) == 0); \
|
|
*pdw = ver; break;
|
|
|
|
#define V_STRUCTPTR_WRITE_VER_END(basetype,ptr) \
|
|
default : if ((ptr)->dwSize > sizeof(basetype##7)) \
|
|
{ RIP_W_INVALIDSIZE(ptr); } else \
|
|
RIP_E_INVALIDSIZE(ptr); }}
|
|
|
|
|
|
|
|
#endif // _VALIDATE_H_
|