/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1993-2000 Microsoft Corporation Module Name : memsize.c Abstract : This file contains the routines called by MIDL 2.0 stubs and the intepreter for computing the memory size needed to hold a parameter being unmarshalled. Author : David Kays dkays November 1993. Revision History : Note: Simple types are not checked for buffer over-run since we are only reading from the buffer and not writing from it. So if a buffer overun actually occures, no real damage is done. ---------------------------------------------------------------------*/ #include "ndrp.h" #include "interp2.h" #include "attack.h" #include "pointerq.h" unsigned long NdrUDTSimpleTypeMemsize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ); extern const PMEM_SIZE_ROUTINE MemSizeRoutinesTable[] = { // dummies for 64b C compiler workaround // NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, // FC_ZERO - FC_USHORT NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, NdrUDTSimpleTypeMemsize, // FC_LONG - FC_IGNORE NdrUDTSimpleTypeMemsize, // FC_ERROR_STATUS_T NdrPointerMemorySize, NdrPointerMemorySize, NdrPointerMemorySize, NdrPointerMemorySize, NdrSimpleStructMemorySize, NdrSimpleStructMemorySize, NdrConformantStructMemorySize, NdrConformantStructMemorySize, NdrConformantVaryingStructMemorySize, NdrComplexStructMemorySize, NdrConformantArrayMemorySize, NdrConformantVaryingArrayMemorySize, NdrFixedArrayMemorySize, NdrFixedArrayMemorySize, NdrVaryingArrayMemorySize, NdrVaryingArrayMemorySize, NdrComplexArrayMemorySize, NdrConformantStringMemorySize, NdrConformantStringMemorySize, NdrConformantStringMemorySize, NdrConformantStringMemorySize, NdrNonConformantStringMemorySize, NdrNonConformantStringMemorySize, NdrNonConformantStringMemorySize, NdrNonConformantStringMemorySize, NdrEncapsulatedUnionMemorySize, NdrNonEncapsulatedUnionMemorySize, 0, // byte count NdrXmitOrRepAsMemorySize, // transmit as NdrXmitOrRepAsMemorySize, // represent as NdrPointerMemorySize, 0, // New Post NT 3.5 token serviced from here on. 0, // NdrHardStructMemorySize, NdrXmitOrRepAsMemorySize, // transmit as ptr NdrXmitOrRepAsMemorySize, // represent as ptr NdrUserMarshalMemorySize, 0, // FC_PIPE 0, // FC_BLK_HOLE NdrpRangeMemorySize, 0, // FC_INT3264 0, // FC_UINT3264 0, // NdrCsArrayMemorySize, 0, // NdrCsTagMemorySize }; extern const PMEM_SIZE_ROUTINE * pfnMemSizeRoutines = MemSizeRoutinesTable; void NdrpInterfacePointerMemorySize ( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ); unsigned long NdrUDTSimpleTypeMemsize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) { ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT(*pFormat) ); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE(*pFormat); pStubMsg->MemorySize += SIMPLE_TYPE_MEMSIZE(*pFormat); return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrpRangeMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ --*/ { FORMAT_CHARACTER FcType = (FORMAT_CHARACTER)(pFormat[1] & 0x0f); ALIGN(pStubMsg->Buffer,SIMPLE_TYPE_ALIGNMENT(FcType)); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE(FcType); switch ( pFormat[2] ) { case FC_ENUM16 : // // We can't use the simple type tables for enum16. // LENGTH_ALIGN( pStubMsg->MemorySize, sizeof(int) - 1 ); pStubMsg->MemorySize += sizeof(int); break; default : LENGTH_ALIGN( pStubMsg->MemorySize, SIMPLE_TYPE_ALIGNMENT(FcType) ); pStubMsg->MemorySize += SIMPLE_TYPE_MEMSIZE(FcType); break; } return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrPointerMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a top level pointer to anything. Pointers embedded in structures, arrays, or unions call NdrpPointerMemorySize directly. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { uchar * pBufferMark; // // If this is not a ref pointer then mark where the pointer's id is in // the buffer and increment the stub message buffer pointer. // if ( *pFormat != FC_RP ) { ALIGN(pStubMsg->Buffer,0x3); pBufferMark = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; } else pBufferMark = 0; // Else we can leave pBufferMark unitialized. return NdrpPointerMemorySize( pStubMsg, pBufferMark, pFormat ); } __forceinline unsigned long NdrpPointerMemorySizeInternal( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferMark, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for computing the memory size required for a pointer to anything. This is the entry point for pointers embedded in structures arrays, or unions. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to stub message. pBufferMark - Location in the buffer where a unique or full pointer's id is. Unused for ref pointers. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { uchar uFlagsSave; ulong MemSize; switch ( *pFormat ) { case FC_RP : break; case FC_UP : case FC_OP : if ( ! *((long *)pBufferMark) ) return pStubMsg->MemorySize; break; case FC_IP: if ( IS_BROKEN_INTERFACE_POINTER(pStubMsg->uFlags) ) { // In this case, the whole pointer and pointee are // where the pointee should have been. // (Treat like toplevel at this point ) NdrInterfacePointerMemorySize( pStubMsg, pFormat ); } else { if ( ! *((long *)pBufferMark) ) return pStubMsg->MemorySize; NdrpInterfacePointerMemorySize( pStubMsg, pFormat ); } return pStubMsg->MemorySize; case FC_FP : // // Check if we've already mem sized this full pointer. // if ( NdrFullPointerQueryRefId( pStubMsg->FullPtrXlatTables, *((ulong *)pBufferMark), FULL_POINTER_MEM_SIZED, 0 ) ) return pStubMsg->MemorySize; break; default : NDR_ASSERT(0,"NdrpPointerMemorySize : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } // // We align all memory pointers on at least a void * boundary. // LENGTH_ALIGN( pStubMsg->MemorySize, PTR_MEM_ALIGN ); if ( ! SIMPLE_POINTER(pFormat[1]) ) { // Pointer to complex type. if ( POINTER_DEREF(pFormat[1]) ) pStubMsg->MemorySize += PTR_MEM_SIZE; pFormat += 2; pFormat += *((signed short *)pFormat); } else { switch ( pFormat[2] ) { case FC_C_CSTRING : case FC_C_BSTRING : case FC_C_WSTRING : case FC_C_SSTRING : // Increment to string's description. pFormat += 2; break; default : // Simple type. ALIGN(pStubMsg->Buffer,SIMPLE_TYPE_ALIGNMENT(pFormat[2])); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( pFormat[2] ); switch ( pFormat[2] ) { case FC_ENUM16 : // // We can't use the simple type tables for enum16. // LENGTH_ALIGN( pStubMsg->MemorySize, sizeof(int) - 1 ); pStubMsg->MemorySize += sizeof(int); break; default : LENGTH_ALIGN( pStubMsg->MemorySize, SIMPLE_TYPE_ALIGNMENT(pFormat[2]) ); pStubMsg->MemorySize += SIMPLE_TYPE_MEMSIZE(pFormat[2]); break; } return pStubMsg->MemorySize; } } uFlagsSave = pStubMsg->uFlags; RESET_CONF_FLAGS_TO_STANDALONE(pStubMsg->uFlags); MemSize = (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, pFormat ); pStubMsg->uFlags = uFlagsSave; return MemSize; } NDR_MEMSIZE_POINTER_QUEUE_ELEMENT::NDR_MEMSIZE_POINTER_QUEUE_ELEMENT( MIDL_STUB_MESSAGE *pStubMsg, uchar *pBufferMarkNew, PFORMAT_STRING pFormatNew ) : pFormat(pFormatNew), pBufferMark(pBufferMarkNew), Memory(pStubMsg->Memory), uFlags(pStubMsg->uFlags) { } void NDR_MEMSIZE_POINTER_QUEUE_ELEMENT::Dispatch( MIDL_STUB_MESSAGE *pStubMsg) { SAVE_CONTEXT MemorySave( pStubMsg->Memory, Memory ); SAVE_CONTEXT uFlagsSave( pStubMsg->uFlags, uFlags ); NDR_ASSERT( !pStubMsg->PointerBufferMark, "PointerBufferMark is not 0!\n"); NDR_ASSERT( !pStubMsg->PointerLength, "PointerLength is not 0!\n"); NdrpPointerMemorySizeInternal( pStubMsg, pBufferMark, pFormat ); } #if defined(DBG) void NDR_MEMSIZE_POINTER_QUEUE_ELEMENT::Print() { DbgPrint("NDR_MRSHL_POINTER_QUEUE_ELEMENT\n"); DbgPrint("pNext: %p\n", pNext ); DbgPrint("pFormat: %p\n", pFormat ); DbgPrint("pBufferMark: %p\n", pBufferMark ); DbgPrint("Memory: %p\n", Memory ); DbgPrint("uFlags: %x\n", uFlags ); } #endif void NdrpEnquePointerMemorySize( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferMark, PFORMAT_STRING pFormat ) { NDR32_POINTER_CONTEXT PointerContext( pStubMsg ); RpcTryFinally { NDR_MEMSIZE_POINTER_QUEUE_ELEMENT*pElement = new(PointerContext.GetActiveState()) NDR_MEMSIZE_POINTER_QUEUE_ELEMENT(pStubMsg, pBufferMark, pFormat ); PointerContext.Enque( pElement ); PointerContext.DispatchIfRequired(); } RpcFinally { PointerContext.EndContext(); } RpcEndFinally } unsigned long NdrpPointerMemorySize( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferMark, PFORMAT_STRING pFormat ) { if ( !NdrIsLowStack(pStubMsg) ) { return NdrpPointerMemorySizeInternal( pStubMsg, pBufferMark, pFormat ); } NdrpEnquePointerMemorySize( pStubMsg, pBufferMark, pFormat ); return 0; } unsigned long RPC_ENTRY NdrSimpleStructMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a simple structure. Used for FC_STRUCT and FC_PSTRUCT. Arguments : pStubMsg - Pointer to stub message. pFormat - Structure's format string description. Return : The computed memory size. --*/ { ulong Size; Size = *((ushort *)(pFormat + 2)); ALIGN(pStubMsg->Buffer,pFormat[1]); LENGTH_ALIGN( pStubMsg->MemorySize, pFormat[1] ); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + Size ); pStubMsg->Buffer += Size; pStubMsg->MemorySize += Size; if ( *pFormat == FC_PSTRUCT ) { // Mark where the structure starts in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer - Size; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat + 4 ); } return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrConformantStructMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a conformant structure. Used for FC_CSTRUCT and FC_CPSTRUCT. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { PFORMAT_STRING pFormatArray; ulong Size; uchar Alignment = pFormat[1]; // set by the outermost embedding complex struct uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); Size = *((ushort *)(pFormat + 2)); // Get the conformance count. if ( fIsEmbeddedStruct ) { // A bogus struct would set the mark. pStubMsg->MaxCount = *((long *)pStubMsg->BufferMark); } else { // Align for the conformance count. ALIGN(pStubMsg->Buffer,0x3); pStubMsg->MaxCount = *((long *&)pStubMsg->Buffer)++; } // Increment the format string to the offset to array description. pFormat += 4; // Get the array's description. pFormatArray = pFormat + *((signed short *)pFormat); // Check bounds. CHECK_BOUND( (ulong)pStubMsg->MaxCount, pFormatArray[4] & 0x0f ); // check for possible mulitplication overflow attack here. Size += MultiplyWithOverflowCheck( (ulong)pStubMsg->MaxCount, *((ushort *)(pFormatArray + 2) ) ); // Increment the format string past the offset to array description. pFormat += 2; // Realign for struct ALIGN(pStubMsg->Buffer, Alignment); LENGTH_ALIGN( pStubMsg->MemorySize, Alignment ); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, Size ); pStubMsg->Buffer += Size; pStubMsg->MemorySize += Size; if ( *pFormat == FC_PP ) { // Mark the beginning of the struct in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer - Size; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat ); } if ( fIsEmbeddedStruct ) SET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrConformantVaryingStructMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a conformant varying structure. Used for FC_CVSTRUCT. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { PFORMAT_STRING pFormatArray; uchar * pBufferMark; ulong Size; // set by the outermost embedding complex struct uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); Size = *((ushort *)(pFormat + 2)); // Get the conformance count. if ( fIsEmbeddedStruct ) { pStubMsg->MaxCount = *((long *&)pStubMsg->BufferMark); } else { ALIGN(pStubMsg->Buffer,0x3); pStubMsg->MaxCount = *((long *&)pStubMsg->Buffer)++; } ALIGN(pStubMsg->Buffer,pFormat[1]); LENGTH_ALIGN( pStubMsg->MemorySize, pFormat[1] ); // Remember the start of the struct in the buffer. pBufferMark = pStubMsg->Buffer; CHECK_EOB_RAISE_IB( pStubMsg->Buffer + Size ); pStubMsg->Buffer += Size; pStubMsg->MemorySize += Size; pFormat += 4; // Get array's format string description. pFormatArray = pFormat + *((signed short *)pFormat); // We always marshal the array, the outer struct will watch for the done flag. if ( *pFormatArray == FC_CVARRAY ) { NdrpConformantVaryingArrayMemorySize( pStubMsg, pFormatArray ); } else { NdrpConformantStringMemorySize( pStubMsg, pFormatArray ); } pFormat += 2; if ( *pFormat == FC_PP ) { // Mark the start of the structure in the buffer. pStubMsg->Buffer = pBufferMark; pStubMsg->MaxCount = pStubMsg->ActualCount; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat ); } if ( fIsEmbeddedStruct ) SET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return pStubMsg->MemorySize; } #if 0 unsigned long RPC_ENTRY NdrHardStructMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a hard structure. Used for FC_HARD_STRUCT. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ushort CopySize; LENGTH_ALIGN(pStubMsg->MemorySize,pFormat[1]); pStubMsg->MemorySize += *((ushort *)&pFormat[2]); ALIGN(pStubMsg->Buffer,pFormat[1]); CopySize = *((ushort *)&pFormat[10]); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + CopySize ); pStubMsg->Buffer += CopySize; if ( *((short *)&pFormat[14]) ) { pFormat += 14; pFormat += *((short *)pFormat); (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, pFormat ); } return pStubMsg->MemorySize; } #endif // 0 unsigned long RPC_ENTRY NdrComplexStructMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a complex structure. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. Notes: This routine can calculate the memory size with or without pointees. When calculating size with pointees at the top level, the routine calls itself recursively to find out where pointees would be and then remember the context using pStubMsg->MemorySize and pStubMsg->PointerBufferMark. --*/ { uchar * pBufferMark; PFORMAT_STRING pFormatPointers; PFORMAT_STRING pFormatArray; PFORMAT_STRING pFormatComplex; long Alignment; BOOL fSetPointerBufferMark; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); BOOL fEmbedConfStructContext; // // This is fun. If we're not ignoring embedded pointers and this structure // is not embedded inside of another struct or array then we make a // recursive call to get a pointer to where the flat part of the structure // ends in the buffer. Then we can properly get to any embedded pointer's // pointees. // if ( fSetPointerBufferMark = (! pStubMsg->IgnoreEmbeddedPointers && ! pStubMsg->PointerBufferMark) ) { pStubMsg->IgnoreEmbeddedPointers = TRUE; // This gets clobbered. uchar * BufferSave = pStubMsg->Buffer; ulong MemorySizeSave = pStubMsg->MemorySize; // // Get a buffer pointer to where the struct's pointees are. // (void) NdrComplexStructMemorySize( pStubMsg, pFormat ); // Mark where the pointees begin. pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->PointerLength = pStubMsg->MemorySize; pStubMsg->IgnoreEmbeddedPointers = FALSE; pStubMsg->MemorySize = MemorySizeSave; pStubMsg->Buffer = BufferSave; } Alignment = pFormat[1]; pFormat += 4; fEmbedConfStructContext = fIsEmbeddedStruct; // Get conformant array description. if ( *((ushort *)pFormat) ) { ulong ConformanceSize; pFormatArray = pFormat + *((signed short *)pFormat); if ( FixWireRepForDComVerGTE54( pStubMsg ) ) fEmbedConfStructContext = TRUE; if ( !fIsEmbeddedStruct ) { ALIGN(pStubMsg->Buffer,3); // conformance count marker pStubMsg->BufferMark = pStubMsg->Buffer; // Handle multidimensional arrays. ConformanceSize = NdrpArrayDimensions( pStubMsg, pFormatArray, FALSE ) * 4; CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + ConformanceSize ); pStubMsg->Buffer += ConformanceSize; } } else { pFormatArray = 0; } // BufferMark may be set by an outer bogus struct. pBufferMark = pStubMsg->BufferMark; RESET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); pFormat += 2; // Get pointer layout description. if ( *((ushort *)pFormat) ) pFormatPointers = pFormat + *((ushort *)pFormat); else pFormatPointers = 0; pFormat += 2; ALIGN(pStubMsg->Buffer,Alignment); // // Size the structure member by member. // for ( ; ; pFormat++ ) { switch ( *pFormat ) { // // Simple types. // case FC_CHAR : case FC_BYTE : case FC_SMALL : case FC_WCHAR : case FC_SHORT : case FC_LONG : #if defined(__RPC_WIN64__) case FC_INT3264 : case FC_UINT3264 : #endif case FC_FLOAT : case FC_HYPER : case FC_DOUBLE : case FC_ENUM16 : case FC_ENUM32 : case FC_IGNORE : ALIGN(pStubMsg->Buffer,SIMPLE_TYPE_ALIGNMENT(*pFormat)); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( *pFormat ); pStubMsg->MemorySize += SIMPLE_TYPE_MEMSIZE(*pFormat); break; case FC_POINTER : { ALIGN(pStubMsg->Buffer,0x3); uchar *pPointerId = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; if ( ! pStubMsg->IgnoreEmbeddedPointers ) { POINTER_MEMSIZE_SWAP_CONTEXT SwapContext( pStubMsg ); NdrpPointerMemorySize( pStubMsg, pPointerId, pFormatPointers ); } // // We actually do a post alignment of the memory size. // Do this to prevent some under-allocations when pointers // to strings, or char or short are involved. // LENGTH_ALIGN( pStubMsg->MemorySize, PTR_MEM_ALIGN ); pStubMsg->MemorySize += PTR_MEM_SIZE; pFormatPointers += 4; } break; // // Embedded complex types. // case FC_EMBEDDED_COMPLEX : // Add padding. pStubMsg->MemorySize += pFormat[1]; pFormat += 2; // Get the type's description. pFormatComplex = pFormat + *((signed short UNALIGNED *)pFormat); if ( FC_IP == *pFormatComplex ) { ALIGN(pStubMsg->Buffer,0x3); uchar *pPointerId = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; if ( ! pStubMsg->IgnoreEmbeddedPointers ) { POINTER_MEMSIZE_SWAP_CONTEXT SwapContext( pStubMsg ); NdrpPointerMemorySize( pStubMsg, pPointerId, pFormatComplex ); } pStubMsg->MemorySize += PTR_MEM_SIZE; pFormat++; break; } // Needed for embedded conf structs // pStubMsg->BufferMark = pBufferMark; if ( fEmbedConfStructContext ) SET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); (void) (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, pFormatComplex ); RESET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); // // Increment the main format string one byte. The loop // will increment it one more byte past the offset field. // pFormat++; break; case FC_ALIGNM2 : LENGTH_ALIGN( pStubMsg->MemorySize, 0x1 ); break; case FC_ALIGNM4 : LENGTH_ALIGN( pStubMsg->MemorySize, 0x3 ); break; case FC_ALIGNM8 : LENGTH_ALIGN( pStubMsg->MemorySize, 0x7 ); break; case FC_STRUCTPAD1 : case FC_STRUCTPAD2 : case FC_STRUCTPAD3 : case FC_STRUCTPAD4 : case FC_STRUCTPAD5 : case FC_STRUCTPAD6 : case FC_STRUCTPAD7 : pStubMsg->MemorySize += (*pFormat - FC_STRUCTPAD1) + 1; break; case FC_STRUCTPADN : // FC_STRUCTPADN 0 pStubMsg->MemorySize += *(((unsigned short *)pFormat) + 1); pFormat += 3; break; case FC_PAD : break; // // Done with layout. // case FC_END : goto ComplexMemorySizeEnd; default : NDR_ASSERT(0,"NdrComplexStructMemorySize : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } } ComplexMemorySizeEnd : if ( pFormatArray && !fIsEmbeddedStruct && ! IS_CONF_ARRAY_DONE( pStubMsg->uFlags ) ) { PPRIVATE_MEM_SIZE_ROUTINE pfnMemSize; switch ( *pFormatArray ) { case FC_CARRAY : pfnMemSize = NdrpConformantArrayMemorySize; break; case FC_CVARRAY : pfnMemSize = NdrpConformantVaryingArrayMemorySize; break; case FC_BOGUS_ARRAY : pfnMemSize = NdrpComplexArrayMemorySize; break; // case FC_C_CSTRING : // case FC_C_BSTRING : // case FC_C_WSTRING : // case FC_C_SSTRING : default : pfnMemSize = NdrpConformantStringMemorySize; break; } // Set the max count for non-complex conformant arrays. pStubMsg->MaxCount = *((ulong *)pBufferMark); // Mark where conformance count(s) are. pStubMsg->BufferMark = pBufferMark; (void) (*pfnMemSize)( pStubMsg, pFormatArray ); } if ( fSetPointerBufferMark ) { pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->MemorySize = pStubMsg->PointerLength; pStubMsg->PointerBufferMark = 0; pStubMsg->PointerLength = 0; } if ( fIsEmbeddedStruct ) SET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); else RESET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrFixedArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a fixed array of any number of dimensions. Used for FC_SMFARRAY and FC_LGFARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ulong Size; ALIGN(pStubMsg->Buffer,pFormat[1]); LENGTH_ALIGN( pStubMsg->MemorySize, pFormat[1] ); if ( *pFormat == FC_SMFARRAY ) { pFormat += 2; Size = *((ushort *&)pFormat)++; } else { pFormat += 2; Size = *((ulong UNALIGNED *&)pFormat)++; } CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + Size ); pStubMsg->Buffer += Size; pStubMsg->MemorySize += Size; if ( *pFormat == FC_PP ) { // Mark the location in the buffer where the array starts. pStubMsg->BufferMark = pStubMsg->Buffer - Size; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat ); } return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrConformantArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a top level one dimensional conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { // // Get the conformance count. // ALIGN(pStubMsg->Buffer,0x3); pStubMsg->MaxCount = *((long *&)pStubMsg->Buffer)++; return NdrpConformantArrayMemorySize( pStubMsg, pFormat ); } unsigned long NdrpConformantArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for computing the memory size of a one dimensional conformant array. This is the entry point for an embedded conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ulong Size; if ( ! pStubMsg->MaxCount ) return pStubMsg->MemorySize; // Check bounds. CHECK_BOUND( (ulong)pStubMsg->MaxCount, pFormat[4] & 0x0f ); ALIGN(pStubMsg->Buffer, pFormat[1]); LENGTH_ALIGN( pStubMsg->MemorySize, pFormat[1] ); // Increment to element size. pFormat += 2; // Compute array size. // check for possible mulitplication overflow attack here. Size = MultiplyWithOverflowCheck( (ulong)pStubMsg->MaxCount, *((ushort *)pFormat) ); pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, Size ); pStubMsg->Buffer += Size; pStubMsg->MemorySize += Size; if ( *pFormat == FC_PP ) { // Mark the location in the buffer where the array starts. pStubMsg->BufferMark = pStubMsg->Buffer - Size; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat ); } return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a one dimensional top level conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { // // Get the conformance count. // ALIGN(pStubMsg->Buffer,0x3); pStubMsg->MaxCount = *((long *&)pStubMsg->Buffer)++; return NdrpConformantVaryingArrayMemorySize( pStubMsg, pFormat ); } unsigned long NdrpConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for computing the memory size of a one dimensional conformant varying array. This is the entry point for memory sizing an embedded conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ulong BufferSize; PFORMAT_STRING pFormatVar; // // Get the offset and actual count in case needed for pointer sizing. // ALIGN(pStubMsg->Buffer,0x3); pStubMsg->Offset = *((long *&)pStubMsg->Buffer)++; pStubMsg->ActualCount = *((long *&)pStubMsg->Buffer)++; // Check bounds. CHECK_BOUND( (ulong)pStubMsg->MaxCount, pFormat[4] & 0x0f ); pFormatVar = pFormat + 8; CORRELATION_DESC_INCREMENT( pFormatVar ); CHECK_BOUND( pStubMsg->ActualCount, *pFormatVar & 0x0f ); if ( (pStubMsg->MaxCount < (pStubMsg->Offset + pStubMsg->ActualCount)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); // // Do the memory size increment now in case the actual count is 0. // LENGTH_ALIGN( pStubMsg->MemorySize, pFormat[1] ); // check for possible mulitplication overflow attack here. pStubMsg->MemorySize += MultiplyWithOverflowCheck( (ulong)pStubMsg->MaxCount, *((ushort *)(pFormat + 2)) ); if ( ! pStubMsg->ActualCount ) return pStubMsg->MemorySize; ALIGN(pStubMsg->Buffer, pFormat[1]); // Increment to element size. pFormat += 2; BufferSize = pStubMsg->ActualCount * *((ushort *)pFormat); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, BufferSize ); pStubMsg->Buffer += BufferSize; pFormat += 10; CORRELATION_DESC_INCREMENT( pFormat ); CORRELATION_DESC_INCREMENT( pFormat ); if ( *pFormat == FC_PP ) { // Mark the location in the buffer where the array starts. pStubMsg->BufferMark = pStubMsg->Buffer - BufferSize; pStubMsg->MaxCount = pStubMsg->ActualCount; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat ); } return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a top level or embedded varying array. Used for FC_SMVARRAY and FC_LGVARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ulong MemorySize; ulong BufferSize; uchar Alignment; long Elements; // // Get the offset and actual count. // ALIGN(pStubMsg->Buffer,0x3); pStubMsg->Offset = *((long *&)pStubMsg->Buffer)++; pStubMsg->ActualCount = *((long *&)pStubMsg->Buffer)++; // Check bounds using the old part of correlation descr. CHECK_BOUND( pStubMsg->ActualCount, pFormat[(*pFormat == FC_SMVARRAY) ? 8 : 12] & 0x0f ); Elements = (*pFormat == FC_SMVARRAY) ? *((ushort *)(pFormat + 4)) : *((ulong UNALIGNED *)(pFormat + 6)); if ( (((long)pStubMsg->Offset) < 0) || (Elements < (long)(pStubMsg->ActualCount + pStubMsg->Offset)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); Alignment = pFormat[1]; if ( *pFormat == FC_SMVARRAY ) { pFormat += 2; MemorySize = (ulong) *((ushort *)pFormat); pFormat += 4; } else { pFormat += 2; MemorySize = *((ulong UNALIGNED *)pFormat); pFormat += 8; } // // Do the memory size increment now in case the actual count is 0 and // we have return. // LENGTH_ALIGN( pStubMsg->MemorySize, Alignment ); pStubMsg->MemorySize += MemorySize; if ( ! pStubMsg->ActualCount ) return pStubMsg->MemorySize; ALIGN(pStubMsg->Buffer, Alignment); // check for possible mulitplication overflow attack here. BufferSize = MultiplyWithOverflowCheck( pStubMsg->ActualCount , *((ushort *)pFormat) ); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, BufferSize ); pStubMsg->Buffer += BufferSize; pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); if ( *pFormat == FC_PP ) { // Mark the start of the array in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer - BufferSize; pStubMsg->MaxCount = pStubMsg->ActualCount; NdrpEmbeddedPointerMemorySize( pStubMsg, pFormat ); } return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrComplexArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a top level complex array. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { BOOL fSetPointerBufferMark; PFORMAT_STRING pFormatPP; // // We set this if we're doing a real 'all nodes' sizing, this array // is not embedded in another structure or array, and this is not an // array of ref pointers. // pFormatPP = pFormat + 12; CORRELATION_DESC_INCREMENT( pFormatPP ); CORRELATION_DESC_INCREMENT( pFormatPP ); fSetPointerBufferMark = ! pStubMsg->IgnoreEmbeddedPointers && ! pStubMsg->PointerBufferMark && *pFormatPP != FC_RP; // // More fun. Make a recursive call so that we have a pointer to the end // of the array's flat stuff in the buffer. Then we can properly get to // any embedded pointer members. We have no way of knowing if there are // any embedded pointers so we're stuck doing this all the time. // if ( fSetPointerBufferMark ) { pStubMsg->IgnoreEmbeddedPointers = TRUE; // Save this since it gets clobbered. ulong MemorySizeSave = pStubMsg->MemorySize; uchar* pBufferSave = pStubMsg->Buffer; // // Get a buffer pointer to where the array's pointees are. // (void) NdrComplexArrayMemorySize( pStubMsg, pFormat ); // This is where the array pointees start. pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->PointerLength = pStubMsg->MemorySize; pStubMsg->IgnoreEmbeddedPointers = FALSE; pStubMsg->MemorySize = MemorySizeSave; pStubMsg->Buffer = pBufferSave; } if ( ( *((long UNALIGNED *)(pFormat + 4)) != 0xffffffff ) && ( pStubMsg->pArrayInfo == 0 ) ) { // // The outer most array dimension sets the conformance marker. // ALIGN(pStubMsg->Buffer,0x3); pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past conformance count(s). pStubMsg->Buffer += NdrpArrayDimensions( pStubMsg, pFormat, FALSE ) * 4; CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); } (void) NdrpComplexArrayMemorySize( pStubMsg, pFormat ); if ( fSetPointerBufferMark ) { pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->MemorySize = pStubMsg->PointerLength; pStubMsg->PointerLength = 0; pStubMsg->PointerBufferMark = 0; } return pStubMsg->MemorySize; } unsigned long NdrpComplexArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for computing the memory size of a complex array. This is the entry point for memory sizing an embedded complex array. Used for FC_BOGUS_ARRAY. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ARRAY_INFO ArrayInfo; PARRAY_INFO pArrayInfo; PMEM_SIZE_ROUTINE pfnMemSize; uchar * pBufferSave; PFORMAT_STRING pFormatSave; ulong Elements; ulong Count, CountSave; long Dimension; uchar Alignment; uchar * pPointerIdMark; bool IsBrokenInterfacePointerFormat = false; // // Setup if we are the outer dimension. // if ( ! pStubMsg->pArrayInfo ) { pStubMsg->pArrayInfo = &ArrayInfo; ArrayInfo.Dimension = 0; ArrayInfo.BufferConformanceMark = (unsigned long *)pStubMsg->BufferMark; ArrayInfo.BufferVarianceMark = 0; } // Used for array of ref pointers only. pBufferSave = 0; pFormatSave = pFormat; pArrayInfo = pStubMsg->pArrayInfo; Dimension = pArrayInfo->Dimension; // Get the array alignment. Alignment = pFormat[1]; pFormat += 2; // Get number of elements (0 if conformance present). Elements = *((ushort *&)pFormat)++; // // Check for conformance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { Elements = pArrayInfo->BufferConformanceMark[Dimension]; // Check bounds CHECK_BOUND( Elements, *pFormat & 0x0f ); } pFormat += 4; CORRELATION_DESC_INCREMENT( pFormat ); // // Check for variance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { long Offset; if ( Dimension == 0 ) { ulong VarianceSize; ALIGN(pStubMsg->Buffer,0x3); // Mark where the variance counts are. pArrayInfo->BufferVarianceMark = (unsigned long *)pStubMsg->Buffer; // Handle multidimensional arrays. VarianceSize = NdrpArrayDimensions( pStubMsg, pFormatSave, TRUE ) * 8; CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + VarianceSize ); pStubMsg->Buffer += VarianceSize; } Count = pArrayInfo->BufferVarianceMark[(Dimension * 2) + 1]; // Check bounds CHECK_BOUND( Count, *pFormat & 0x0f ); Offset = pArrayInfo->BufferVarianceMark[(Dimension * 2)]; if ( (Offset < 0) || (Elements < (Offset + Count)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); } else { Count = Elements; } CountSave = Count; pFormat += 4; CORRELATION_DESC_INCREMENT( pFormat ); // // Only align the buffer if at least one element was shipped. // if ( Count ) ALIGN(pStubMsg->Buffer,Alignment); pPointerIdMark = 0; switch ( *pFormat ) { case FC_EMBEDDED_COMPLEX : pFormat += 2; pFormat += *((signed short *)pFormat); pfnMemSize = pfnMemSizeRoutines[ROUTINE_INDEX(*pFormat)]; if ( FC_IP == *pFormat ) goto HandleInterfacePointer; break; case FC_IP : HandleInterfacePointer: IsBrokenInterfacePointerFormat = !FixWireRepForDComVerGTE54( pStubMsg ); pPointerIdMark = pStubMsg->Buffer; // Do not leave any space for the pointer if this is // the broken format. But do position the pointee as if the // pointer was transmitted. if ( pStubMsg->IgnoreEmbeddedPointers || !IsBrokenInterfacePointerFormat ) { CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, Count * PTR_WIRE_SIZE ); pStubMsg->Buffer += MultiplyWithOverflowCheck( Count , PTR_WIRE_SIZE ); } goto HandleRefPointer; case FC_UP : case FC_FP : case FC_OP : pPointerIdMark = pStubMsg->Buffer; CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, Count * PTR_WIRE_SIZE ); pStubMsg->Buffer += MultiplyWithOverflowCheck( Count , PTR_WIRE_SIZE ); // Fall through case FC_RP : HandleRefPointer: // // Add in the size of the array explicitly. // LENGTH_ALIGN( pStubMsg->MemorySize, PTR_MEM_ALIGN ); pStubMsg->MemorySize += MultiplyWithOverflowCheck( Elements, PTR_MEM_SIZE ); if ( pStubMsg->IgnoreEmbeddedPointers ) goto ComplexArrayMemSizeEnd; pfnMemSize = (PMEM_SIZE_ROUTINE) NdrpPointerMemorySize; break; case FC_RANGE: { LENGTH_ALIGN( pStubMsg->MemorySize, SIMPLE_TYPE_ALIGNMENT( pFormat[1] ) ); ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( pFormat[1] ) ); pStubMsg->Buffer += MultiplyWithOverflowCheck( Count, SIMPLE_TYPE_BUFSIZE( pFormat[1] ) ); pStubMsg->MemorySize += MultiplyWithOverflowCheck( Elements, SIMPLE_TYPE_MEMSIZE( pFormat[1] ) ); // not really needed as it's checked after memsize is done CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); goto ComplexArrayMemSizeEnd; break; } default : { ulong ByteCount; NDR_ASSERT( IS_SIMPLE_TYPE(*pFormat), "NdrpComplexArrayMemorySize : bad format char" ); ByteCount = MultiplyWithOverflowCheck( Count , SIMPLE_TYPE_BUFSIZE(*pFormat) ); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, ByteCount ); pStubMsg->Buffer += ByteCount; if ( *pFormat == FC_ENUM16 ) LENGTH_ALIGN( pStubMsg->MemorySize, sizeof(int) - 1 ); else LENGTH_ALIGN( pStubMsg->MemorySize, SIMPLE_TYPE_ALIGNMENT(*pFormat) ); pStubMsg->MemorySize += MultiplyWithOverflowCheck( Elements, SIMPLE_TYPE_MEMSIZE( * pFormat ) ); goto ComplexArrayMemSizeEnd; } } if ( ! IS_ARRAY_OR_STRING(*pFormat) ) pStubMsg->pArrayInfo = 0; if ( pfnMemSize == (PMEM_SIZE_ROUTINE) NdrpPointerMemorySize ) { // If the broken format is used, the pointer and pointee // are where the pointee should have been. if (IsBrokenInterfacePointerFormat) SET_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ); POINTER_MEMSIZE_SWAP_CONTEXT SwapContext( pStubMsg ); for ( ; Count--; pPointerIdMark += PTR_WIRE_SIZE ) { NdrpPointerMemorySize( pStubMsg, pPointerIdMark, pFormat ); } if (IsBrokenInterfacePointerFormat) RESET_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ); } else { for ( ; Count--; ) { // Keep track of multidimensional array dimension. if ( IS_ARRAY_OR_STRING(*pFormat) ) pArrayInfo->Dimension = Dimension + 1; (*pfnMemSize)( pStubMsg, pFormat ); } } if ( pBufferSave ) { pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->Buffer = pBufferSave; } // // If we had variance then we have to make sure and add in the node size // of any members that were not shipped. // if ( (CountSave < Elements) && (*pFormat != FC_RP) ) { long ElementSize; pArrayInfo->Dimension = Dimension + 1; pArrayInfo->MaxCountArray = pArrayInfo->BufferConformanceMark; pStubMsg->pArrayInfo = pArrayInfo; ElementSize = (long)( NdrpMemoryIncrement( pStubMsg, 0, pFormat ) - (uchar*)0 ); pArrayInfo->MaxCountArray = 0; // // We don't have the memory alignment anywhere, so align the memory // size to 8. At worse we'll allocate a few extra bytes. // LENGTH_ALIGN(pStubMsg->MemorySize,0x7); pStubMsg->MemorySize += MultiplyWithOverflowCheck( (Elements - CountSave) , ElementSize ); } ComplexArrayMemSizeEnd: // pArrayInfo must be zero when not valid. pStubMsg->pArrayInfo = (Dimension == 0) ? 0 : pArrayInfo; return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrNonConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a non conformant string. Used for FC_CSTRING, FC_WSTRING, FC_SSTRING, and FC_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ulong BufferSize; ulong MemorySize; ALIGN(pStubMsg->Buffer,0x3); // Skip the offset. pStubMsg->Buffer += 4; BufferSize = *((long *&)pStubMsg->Buffer)++; MemorySize = *((ushort *)(pFormat + 2)); if ( MemorySize < BufferSize ) RpcRaiseException( RPC_X_INVALID_BOUND ); switch ( *pFormat ) { case FC_WSTRING : // Buffer is already aligned on a 4 byte boundary. // Align memory just in case. LENGTH_ALIGN( pStubMsg->MemorySize, 0x1 ); MemorySize = MultiplyWithOverflowCheck( MemorySize, sizeof(wchar_t) ); BufferSize = MultiplyWithOverflowCheck( BufferSize, sizeof(wchar_t) ); break; case FC_SSTRING : MemorySize = MultiplyWithOverflowCheck( MemorySize, pFormat[1] ); BufferSize = MultiplyWithOverflowCheck ( BufferSize, pFormat[1] ); break; default : break; } CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, BufferSize ); pStubMsg->Buffer += BufferSize; pStubMsg->MemorySize += MemorySize; return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a top level conformant string. Used for FC_C_CSTRING, FC_C_WSTRING, FC_C_SSTRING, and FC_C_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { // // Get string size. // if ( pStubMsg->pArrayInfo != 0 ) { // // If this is part of a multidimensional array then we get the location // where the conformance is from a special place. // pStubMsg->MaxCount = pStubMsg->pArrayInfo-> BufferConformanceMark[pStubMsg->pArrayInfo->Dimension]; } else { ALIGN(pStubMsg->Buffer,0x3); pStubMsg->MaxCount = *((long *&)pStubMsg->Buffer)++; } return NdrpConformantStringMemorySize( pStubMsg, pFormat ); } unsigned long NdrpConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for determing the memory size of a conformant string. This is the entry point for an embedded conformant string. Used for FC_C_CSTRING, FC_C_WSTRING, FC_C_SSTRING, and FC_C_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { ulong MemorySize; ulong BufferSize; ALIGN(pStubMsg->Buffer,3); // Skip the offset. pStubMsg->Buffer += 4; BufferSize = *((long *&)pStubMsg->Buffer)++; MemorySize = (ulong)pStubMsg->MaxCount; // Check bounds. if ( (*pFormat != FC_C_SSTRING) && (pFormat[1] == FC_STRING_SIZED) ) CHECK_BOUND( MemorySize, pFormat[2] & 0xf); // // Make sure the offset is 0 and the memory size is at least as // large as the buffer size. // if ( *((long *)(pStubMsg->Buffer - 8)) != 0 || (MemorySize < BufferSize) ) RpcRaiseException( RPC_X_INVALID_BOUND ); switch ( *pFormat ) { case FC_C_WSTRING : // Buffer is already aligned on a 4 byte boundary. // Align memory just in case. LENGTH_ALIGN( pStubMsg->MemorySize, 0x1 ); MemorySize = MultiplyWithOverflowCheck( MemorySize, sizeof(wchar_t) ); BufferSize = MultiplyWithOverflowCheck( BufferSize, sizeof(wchar_t) ); break; case FC_C_SSTRING : MemorySize = MultiplyWithOverflowCheck( MemorySize, pFormat[1] ); BufferSize = MultiplyWithOverflowCheck( BufferSize, pFormat[1] ); break; default : break; } CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, BufferSize ); pStubMsg->Buffer += BufferSize; pStubMsg->MemorySize += MemorySize; return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrEncapsulatedUnionMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of an encapsulated union. Used for FC_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { uchar SwitchType; SwitchType = LOW_NIBBLE(pFormat[1]); // // No alignment needed. Add number of bytes to the union. // pStubMsg->MemorySize += HIGH_NIBBLE(pFormat[1]); NO_CORRELATION; return NdrpUnionMemorySize( pStubMsg, pFormat + 2, SwitchType ); } unsigned long RPC_ENTRY NdrNonEncapsulatedUnionMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size of a non-encapsulated union. Used for FC_NON_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { uchar SwitchType; SwitchType = pFormat[1]; // // Set the format string to the memory size and arm description. // pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); pFormat += *((signed short *)pFormat); return NdrpUnionMemorySize( pStubMsg, pFormat, SwitchType ); } unsigned long NdrpUnionMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, uchar SwitchType ) /*++ Routine Description : Private routine for computing the memory size needed for a union. This routine is used for sizing both encapsulated and non-encapsulated unions. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. SwitchType - Union's switch type. Return : The computed memory size. --*/ { long UnionSize; long SwitchIs; long Arms; uchar Alignment; switch ( SwitchType ) { case FC_SMALL : case FC_CHAR : SwitchIs = (long) *((char *&)pStubMsg->Buffer)++; break; case FC_USMALL : SwitchIs = (long) *((uchar *&)pStubMsg->Buffer)++; break; case FC_SHORT : case FC_ENUM16 : ALIGN(pStubMsg->Buffer,0x1); SwitchIs = (long) *((short *&)pStubMsg->Buffer)++; break; case FC_USHORT : case FC_WCHAR : ALIGN(pStubMsg->Buffer,0x1); SwitchIs = (long) *((ushort *&)pStubMsg->Buffer)++; break; case FC_LONG : case FC_ULONG : case FC_ENUM32 : // FC_INT3264 gets mapped to FC_LONG ALIGN(pStubMsg->Buffer,0x3); SwitchIs = *((long *&)pStubMsg->Buffer)++; break; default : NDR_ASSERT(0,"NdrpUnionMemorySize : bad switch type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } // // Get the max flat union memory size. // UnionSize = *((ushort *&)pFormat)++; // // We're at the union_arms<2> field now, which contains both the // Microsoft union aligment value and the number of union arms. // // // Get the union alignment (0 if this is a DCE union). // Alignment = (uchar) ( *((ushort *)pFormat) >> 12 ); ALIGN(pStubMsg->Buffer,Alignment); pStubMsg->MemorySize += UnionSize; // // Get number of union arms. // Arms = (long) ( *((ushort *&)pFormat)++ & 0x0fff ); // // Search for the correct arm. // for ( ; Arms; Arms-- ) { if ( *((long UNALIGNED *&)pFormat)++ == SwitchIs ) { // // Found the right arm, break out. // break; } // Else increment format string. pFormat += 2; } // // Check if we took the default arm and no default arm is specified. // if ( ! Arms && (*((ushort *)pFormat) == (ushort) 0xffff) ) { // // Raise an exception here. // RpcRaiseException( RPC_S_INVALID_TAG ); } // // Return if the arm is emtpy. // if ( ! *((ushort *)pFormat) ) return pStubMsg->MemorySize; // // Ok we've got the correct arm now. The only goal now is to increment // the buffer pointer by the correct amount, and possibly add the size // of embedded pointers in the chosen union arm to the memory size. // // // Get the arm's description. // // We need a real solution after beta for simple type arms. This could // break if we have a format string larger than about 32K. // if ( IS_MAGIC_UNION_BYTE(pFormat) ) { unsigned char FcType = pFormat[0]; ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( FcType )); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( FcType ); return pStubMsg->MemorySize; } pFormat += *((signed short *)pFormat); if ( IS_POINTER_TYPE(*pFormat) ) { if ( pStubMsg->IgnoreEmbeddedPointers ) { ALIGN(pStubMsg->Buffer,0x3); pStubMsg->Buffer += PTR_WIRE_SIZE; return pStubMsg->MemorySize; } if ( pStubMsg->PointerBufferMark ) { ALIGN(pStubMsg->Buffer,0x3); uchar *pPointerId = pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; if ( !pStubMsg->IgnoreEmbeddedPointers ) { POINTER_MEMSIZE_SWAP_CONTEXT SwapContext(pStubMsg); (void) NdrpPointerMemorySize( pStubMsg, pPointerId, pFormat ); } return pStubMsg->MemorySize; } } // // Add in the size of arm. We end up adding the size of the flat part // of the arm a second time here. // We do have to call this however, so that the buffer pointer is properly // updated. // return (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, pFormat ); } unsigned long RPC_ENTRY NdrXmitOrRepAsMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for the presented type of a transmit as or represent as. See mrshl.c for the description of the FC layout. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size of the presented type object. --*/ { unsigned long MemorySize; unsigned short QIndex; // Fetch the QuintupleIndex. QIndex = *(unsigned short *)(pFormat + 2); // Memsize the presented object. MemorySize = *(unsigned short *)(pFormat + 4); // Update our current count in the stub message. pStubMsg->MemorySize += MemorySize; // Move the pointer in the buffer behind the transmitted object // for the next field to be memsized correctly. pFormat += 8; pFormat = pFormat + *(short *)pFormat; if ( IS_SIMPLE_TYPE( *pFormat )) { // Simple type. ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( *pFormat) ); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( *pFormat ); } else { uchar *PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NDR_POINTER_QUEUE *pOldQueue = NULL; if ( pStubMsg->pPointerQueueState) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { (*pfnMemSizeRoutines[ ROUTINE_INDEX( *pFormat) ])( pStubMsg, pFormat ); } RpcFinally { pStubMsg->PointerBufferMark = PointerBufferMarkSave; if ( pStubMsg->pPointerQueueState) { pStubMsg->pPointerQueueState->SetActiveQueue(pOldQueue); } } RpcEndFinally } return( MemorySize ); } void NdrpUserMarshalMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) { unsigned long MemorySizeSave; // Flat type. // Optimization: if we know the wire size, don't walk to size it. if ( *(unsigned short *)(pFormat + 6) != 0 ) { CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + *(unsigned short *)(pFormat + 6)); pStubMsg->Buffer += *(unsigned short *)(pFormat + 6); return; } // Unknown wire size: we need to step through the buffer. // However, the memory size may have nothing to do with // the wire type description.. // so, we need to remember what the current memory size is. MemorySizeSave = pStubMsg->MemorySize; pFormat += 8; pFormat = pFormat + *(short *)pFormat; if ( IS_SIMPLE_TYPE( *pFormat )) { // Simple type. pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( *pFormat ); } else { (*pfnMemSizeRoutines[ ROUTINE_INDEX( *pFormat) ])( pStubMsg, pFormat ); } pStubMsg->MemorySize = MemorySizeSave; } void NDR_USR_MRSHL_MEMSIZE_POINTER_QUEUE_ELEMENT::Dispatch(MIDL_STUB_MESSAGE *pStubMsg) { NdrpUserMarshalMemorySize( pStubMsg, pFormat ); } #if defined(DBG) void NDR_USR_MRSHL_MEMSIZE_POINTER_QUEUE_ELEMENT::Print() { DbgPrint("NDR_USR_MRSHL_MEMSIZE_POINTER_QUEUE_ELEMENT\n"); DbgPrint("pFormat: %p\n", pFormat ); } #endif unsigned long RPC_ENTRY NdrUserMarshalMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a usr_marshal type. See mrshl.c for the description of the layouts. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The memory size of the usr_marshall object. --*/ { unsigned long MemorySize; // The memory sizing routine can be called only when sizing a complex // struct for memory allocation. // Hence, IgnoreEmbeddedPointer in this case has to be on. // Memsize the presented object. MemorySize = *(unsigned short *)(pFormat + 4); // Update our current count in the stub message. pStubMsg->MemorySize += MemorySize; // Move the pointer in the buffer behind the transmitted object // for the next field to be memsized correctly. ALIGN( pStubMsg->Buffer, LOW_NIBBLE( pFormat[1] ) ); if ( pFormat[1] & USER_MARSHAL_POINTER ) { ulong PointerMarker = 0; if ( (pFormat[1] & USER_MARSHAL_UNIQUE) || ((pFormat[1] & USER_MARSHAL_REF) && pStubMsg->PointerBufferMark) ) { PointerMarker = *((unsigned long * &)pStubMsg->Buffer)++; } if ( pStubMsg->IgnoreEmbeddedPointers ) return pStubMsg->MemorySize; if ( (pFormat[1] & USER_MARSHAL_UNIQUE) && !PointerMarker) return pStubMsg->MemorySize; if ( !pStubMsg->pPointerQueueState || !pStubMsg->pPointerQueueState->GetActiveQueue() ) { // If we are embedded, switch to the pointee buffer. POINTER_MEMSIZE_SWAP_CONTEXT NewContext(pStubMsg); NdrpUserMarshalMemorySize( pStubMsg, pFormat ); } else { NDR_USR_MRSHL_MEMSIZE_POINTER_QUEUE_ELEMENT*pElement = new(pStubMsg->pPointerQueueState) NDR_USR_MRSHL_MEMSIZE_POINTER_QUEUE_ELEMENT(pFormat ); pStubMsg->pPointerQueueState->GetActiveQueue()->Enque( pElement ); } return pStubMsg->MemorySize; } NdrpUserMarshalMemorySize( pStubMsg, pFormat ); return pStubMsg->MemorySize; } void NdrpInterfacePointerMemorySize ( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size needed for an interface pointer. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The current memory size. --*/ { ALIGN( pStubMsg->Buffer, 3 ); // Pick up the conformant size and the count field. ulong MaxCount = *((unsigned long *&) pStubMsg->Buffer)++; ulong Size = *((unsigned long *&) pStubMsg->Buffer)++; //Check the array bounds if ( Size != MaxCount ) RpcRaiseException( RPC_X_BAD_STUB_DATA ); IStream* pStream = 0; RpcTryFinally { if (MaxCount > 0) { CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, MaxCount ); if ( IS_WALKIP( pStubMsg->uFlags) ) { #if defined(DEBUG_WALKIP) CHAR AppName[MAX_PATH]; memset(AppName, 0, sizeof(AppName ) ); GetModuleFileNameA( NULL, AppName, sizeof(AppName ) ); DbgPrint("WALKIP32 %s %p\n", AppName, pStubMsg->Buffer ); #else pStream = (*NdrpCreateStreamOnMemory)(pStubMsg->Buffer, MaxCount); if(pStream == 0) RpcRaiseException(RPC_S_OUT_OF_MEMORY); HRESULT hr = (*pfnCoReleaseMarshalData)(pStream); if(FAILED(hr)) RpcRaiseException(hr); #endif } } } RpcFinally { if ( pStream ) pStream->Release(); pStubMsg->Buffer += MaxCount; } RpcEndFinally } unsigned long RPC_ENTRY NdrInterfacePointerMemorySize ( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) { ALIGN(pStubMsg->Buffer,0x3); ulong PtrValue = *((long *&)pStubMsg->Buffer)++; LENGTH_ALIGN( pStubMsg->MemorySize, PTR_MEM_ALIGN ); pStubMsg->MemorySize += PTR_MEM_SIZE; if ( !PtrValue || pStubMsg->IgnoreEmbeddedPointers ) return pStubMsg->MemorySize; NdrpInterfacePointerMemorySize( pStubMsg, pFormat ); return pStubMsg->MemorySize; } void NdrpEmbeddedPointerMemorySize ( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for all embedded pointers in an array or a structure. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { if ( pStubMsg->IgnoreEmbeddedPointers ) return; POINTER_MEMSIZE_SWAP_CONTEXT SwapContext( pStubMsg ); uchar * pBufPtr; uchar * pBufferMark; uchar * pBufferSave; ULONG_PTR MaxCountSave; MaxCountSave = pStubMsg->MaxCount; pBufferMark = pStubMsg->BufferMark; // Increment past the FC_PP and pad. pFormat += 2; for (;;) { if ( *pFormat == FC_END ) { return; } // // Check for FC_FIXED_REPEAT or FC_VARIABLE_REPEAT. // if ( *pFormat != FC_NO_REPEAT ) { pStubMsg->MaxCount = MaxCountSave; pStubMsg->BufferMark = pBufferMark; NdrpEmbeddedRepeatPointerMemorySize( pStubMsg, &pFormat ); // Continue to the next pointer. continue; } // Compute the pointer to the pointer id in the buffer to size. pBufPtr = (pBufferMark + *((signed short *)(pFormat + 4))); // Increment to the pointer description. pFormat += 6; NdrpPointerMemorySize( pStubMsg, pBufPtr, pFormat ); // Increment to next pointer description. pFormat += 4; } // for } void NdrpEmbeddedRepeatPointerMemorySize ( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING * ppFormat ) /*++ Routine Description : Computes the memory size required for all embedded pointers in an array. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer's format string description. Return : The computed memory size. --*/ { uchar * pBufPtr; uchar * pBufferMark; PFORMAT_STRING pFormat; PFORMAT_STRING pFormatSave; ulong RepeatCount, RepeatIncrement, Pointers, PointersSave; pBufferMark = pStubMsg->BufferMark; pFormat = *ppFormat; switch ( *pFormat ) { case FC_FIXED_REPEAT : // Increment past the FC_FIXED_REPEAT and FC_PAD. pFormat += 2; // Get the total number of times to repeat the pointer marshall. RepeatCount = *((ushort *&)pFormat)++; break; case FC_VARIABLE_REPEAT : // Get the total number of times to repeat the pointer marshall. RepeatCount = (ulong)pStubMsg->MaxCount; pFormat += 2; break; default : NDR_ASSERT(0,"NdrpEmbeddedRepeatPointerMemorySize : bad format"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } // Get the increment amount between successive pointers. RepeatIncrement = *((ushort *&)pFormat)++; // Offset to array is ignored. pFormat += 2; // Get number of pointers. PointersSave = Pointers = *((ushort *&)pFormat)++; pFormatSave = pFormat; // // Loop for the number of shipped array elements. // for ( ; RepeatCount--; pBufferMark += RepeatIncrement ) { pFormat = pFormatSave; Pointers = PointersSave; // // Loop for the number of pointer in each array element (which could // be greater than 0 for an array of structures). // for ( ; Pointers--; ) { pFormat += 2; // Get the buffer pointer where the pointer id is. pBufPtr = pBufferMark + *((signed short *&)pFormat)++; NdrpPointerMemorySize( pStubMsg, pBufPtr, pFormat ); // Increment to the next the pointer description. pFormat += 4; } } // Get the format string pointer past this repeat pointer description. *ppFormat = pFormatSave + PointersSave * 8; } #ifdef _CS_CHAR unsigned long RPC_ENTRY NdrCsTagMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a cs tag. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer to FC_CS_TAG in the format string. Return : The computed memory size. --*/ { // We need to set the tag in the stub message so that it can be used // later for sizing/unmarshalling arrays NdrpGetSetCSTagUnmarshall( pStubMsg, (NDR_CS_TAG_FORMAT *) pFormat); pStubMsg->Buffer += sizeof( ulong ); pStubMsg->MemorySize += sizeof( ulong ); return pStubMsg->MemorySize; } unsigned long RPC_ENTRY NdrCsArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*++ Routine Description : Computes the memory size required for a cs_char array. Arguments : pStubMsg - Pointer to stub message. pFormat - Pointer to FC_CS_TAG in the format string. Return : The computed memory size. --*/ { NDR_CS_ARRAY_FORMAT *pCSFormat; NDR_CS_SIZE_CONVERT_ROUTINES *CSRoutines; CS_TYPE_LOCAL_SIZE_ROUTINE LocalSizeRoutine; IDL_CS_CONVERT ConversionType; ulong ArraySize; ulong WireLength; error_status_t status; pCSFormat = (NDR_CS_ARRAY_FORMAT *) pFormat; NDR_ASSERT( NULL != pStubMsg->pCSInfo, "cs_char stub info not set up"); // Get all the info out of the FC_CS_ARRAY structure and bump pFormat // to point to the underlying data descriptor CSRoutines = pStubMsg->StubDesc->CsRoutineTables->pSizeConvertRoutines; LocalSizeRoutine = CSRoutines[ pCSFormat->CSRoutineIndex].pfnLocalSize; pFormat += pCSFormat->DescriptionOffset; // Get the size of the data on the wire WireLength = PtrToUlong( NdrpMemoryIncrement( pStubMsg, 0, pFormat ) ); LocalSizeRoutine( pStubMsg->RpcMsg->Handle, pStubMsg->pCSInfo->WireCodeset, WireLength, &ConversionType, &ArraySize, &status); if ( RPC_S_OK != status ) RpcRaiseException( status ); pStubMsg->MemorySize += ArraySize * pCSFormat->UserTypeSize; return pStubMsg->MemorySize; } #endif