/********************************************************************** Copyright (c) 1993-2000 Microsoft Corporation Module Name : unmrshl.cxx Abstract : This file contains the unmarshalling routines called by MIDL generated stubs and the interpreter. Author : David Kays dkays September 1993. Revision History : **********************************************************************/ #include "ndrp.h" #include "hndl.h" #include "ndrole.h" #include "attack.h" #include "pointerq.h" unsigned char * RPC_ENTRY NdrUDTSimpleTypeUnmarshall1( PMIDL_STUB_MESSAGE pStubMsg, unsigned char * * ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc ); // // Function table of unmarshalling routines. // extern const PUNMARSHALL_ROUTINE UnmarshallRoutinesTable[] = { NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrUDTSimpleTypeUnmarshall1, NdrPointerUnmarshall, NdrPointerUnmarshall, NdrPointerUnmarshall, NdrPointerUnmarshall, NdrSimpleStructUnmarshall, NdrSimpleStructUnmarshall, NdrConformantStructUnmarshall, NdrConformantStructUnmarshall, NdrConformantVaryingStructUnmarshall, NdrComplexStructUnmarshall, NdrConformantArrayUnmarshall, NdrConformantVaryingArrayUnmarshall, NdrFixedArrayUnmarshall, NdrFixedArrayUnmarshall, NdrVaryingArrayUnmarshall, NdrVaryingArrayUnmarshall, NdrComplexArrayUnmarshall, NdrConformantStringUnmarshall, NdrConformantStringUnmarshall, NdrConformantStringUnmarshall, NdrConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrNonConformantStringUnmarshall, NdrEncapsulatedUnionUnmarshall, NdrNonEncapsulatedUnionUnmarshall, NdrByteCountPointerUnmarshall, NdrXmitOrRepAsUnmarshall, // transmit as NdrXmitOrRepAsUnmarshall, // represent as NdrPointerUnmarshall, NdrUnmarshallHandle, // New Post NT 3.5 tokens serviced from here on. 0, // FC_HARD_STRUCT // NdrHardStructUnmarshall, NdrXmitOrRepAsUnmarshall, // transmit as ptr NdrXmitOrRepAsUnmarshall, // represent as ptr NdrUserMarshalUnmarshall, 0, // FC_PIPE 0, // FC_BLK_HOLE NdrRangeUnmarshall, 0, // FC_INT3264 0, // FC_UINT3264 0, // NdrCsArrayUnmarshall, 0, // NdrCsTagUnmarshall }; extern const PUNMARSHALL_ROUTINE * pfnUnmarshallRoutines = UnmarshallRoutinesTable; RPCRTAPI unsigned char * RPC_ENTRY NdrTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) { return (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, ppMemory, pFormat, fMustAlloc ); } __inline unsigned char * RPC_ENTRY NdrUDTSimpleTypeUnmarshall1( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar /* fSkipRefCheck */) { NdrSimpleTypeUnmarshall(pStubMsg,*ppMemory,*pFormat); return NULL; } void NdrpInterfacePointerUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat ); void RPC_ENTRY NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, uchar FormatChar ) /*++ Routine Description : Unmarshalls a simple type. Arguments : pStubMsg - Pointer to the stub message. pMemory - Memory pointer to unmarshall into. FormatChar - Simple type format character. Return : None. --*/ { switch ( FormatChar ) { case FC_CHAR : case FC_BYTE : case FC_SMALL : case FC_USMALL : *pMemory = *(pStubMsg->Buffer)++; break; case FC_ENUM16 : *((ulong *)pMemory) &= 0x0000ffff; // fall through... case FC_WCHAR : case FC_SHORT : case FC_USHORT : ALIGN(pStubMsg->Buffer,1); *((ushort *)pMemory) = *((ushort * &)pStubMsg->Buffer)++; break; #if defined(__RPC_WIN64__) case FC_INT3264: ALIGN(pStubMsg->Buffer,3); // sign exted long to __int64 *((__int64 *)pMemory) = *((long * &)pStubMsg->Buffer)++; break; case FC_UINT3264: ALIGN(pStubMsg->Buffer,3); *((unsigned __int64 *)pMemory) = *((ulong * &)pStubMsg->Buffer)++; break; #endif case FC_LONG : case FC_ULONG : case FC_FLOAT : case FC_ENUM32 : case FC_ERROR_STATUS_T: ALIGN(pStubMsg->Buffer,3); *((ulong *)pMemory) = *((ulong * &)pStubMsg->Buffer)++; break; case FC_HYPER : case FC_DOUBLE : ALIGN(pStubMsg->Buffer,7); // // Let's stay away from casts to doubles. // *((ulong *)pMemory) = *((ulong * &)pStubMsg->Buffer)++; *((ulong *)(pMemory + 4)) = *((ulong * &)pStubMsg->Buffer)++; break; case FC_IGNORE : break; default : NDR_ASSERT(0,"NdrSimpleTypeUnmarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } } unsigned char * RPC_ENTRY NdrRangeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Unmarshals a range FC_RANGE descriptor. --*/ { FORMAT_CHARACTER FcType = (FORMAT_CHARACTER)(pFormat[1] & 0xf); NDR_DEF_FC_RANGE * pRange = (NDR_DEF_FC_RANGE *)pFormat; uchar * pMemory; long Value; unsigned long Low, High; ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( FcType ) ); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + SIMPLE_TYPE_BUFSIZE(FcType ) ); if ( fMustAlloc ) *ppMemory = (uchar*)NdrAllocate( pStubMsg, SIMPLE_TYPE_MEMSIZE(FcType) ); else { if (REUSE_BUFFER(pStubMsg) && ! *ppMemory ) *ppMemory = pStubMsg->Buffer; else if ( ppMemory == NULL ) { NDR_ASSERT(0, "invalid range memory\n"); } } pMemory= *ppMemory; switch ( FcType ) { case FC_CHAR : case FC_BYTE : case FC_USMALL : Value = *pMemory = *(pStubMsg->Buffer)++; break; case FC_SMALL : Value = *(small *)pMemory = *(small *)(pStubMsg->Buffer)++; break; case FC_ENUM16 : Value = *((ulong *)pMemory) &= 0x0000ffff; // fall through... case FC_WCHAR : case FC_USHORT : ALIGN(pStubMsg->Buffer,1); Value = *((ushort *)pMemory) = *((ushort * &)pStubMsg->Buffer)++; break; case FC_SHORT : ALIGN(pStubMsg->Buffer,1); Value = *((short *)pMemory) = *((short * &)pStubMsg->Buffer)++; break; case FC_ULONG : case FC_ENUM32 : case FC_ERROR_STATUS_T: ALIGN(pStubMsg->Buffer,3); Value = *((ulong *)pMemory) = *((ulong * &)pStubMsg->Buffer)++; break; case FC_LONG : ALIGN(pStubMsg->Buffer,3); Value = *((long *)pMemory) = *((long * &)pStubMsg->Buffer)++; break; // case FC_IGNORE : // case FC_FLOAT : // case FC_HYPER : // case FC_DOUBLE : // case FC_INT3264 : // case FC_UINT3264 : default : NDR_ASSERT(0,"NdrSimpleTypeUnmarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } Low = *(unsigned long UNALIGNED *)(pFormat + 2); High = *(unsigned long UNALIGNED *)(pFormat + 6); if ( FcType == FC_ULONG ) { if ( (ulong)Value < Low || (ulong)Value > High ) RpcRaiseException( RPC_X_INVALID_BOUND ); } else if ( Value < (long)Low || Value > (long)High ) RpcRaiseException( RPC_X_INVALID_BOUND ); return 0; } unsigned char * RPC_ENTRY NdrPointerUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar /*fSkipRefCheck*/ ) /*++ Routine Description : Unmarshalls a top level pointer to anything. Pointers embedded in structures, arrays, or unions call NdrpPointerUnmarshall directly. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where to unmarshall the pointer. pFormat - Pointer's format string description. fSkipRefCheck - This is for cases like [in,out] unique to unique to ref pointer or unique to unique to structure with embedded ref pointer. Client pass in NULL and server allocate some memory back. The flag is set when fPointerAlloc is true in NdrpPointerUnmarshall. In fact, we probably should skip the check for all the ref pointer from fPointerAlloc. So we add a new flag in pStubMsg->uFlag Return : None. --*/ { // // If the pointer is not a ref pointer then get a pointer to it's // incomming value's location in the buffer. If it's a ref then set // up some stack space to temporarily act as the buffer. // long * pBufferPointer; if ( *pFormat != FC_RP ) { ALIGN( pStubMsg->Buffer, 3 ); pBufferPointer = (long*)pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; } else { // // If we're on the client unmarshalling a top level [out] ref pointer, // we have to make sure that it is non-null. // if ( pStubMsg->IsClient && !IS_SKIP_REF_CHECK( pStubMsg->uFlags ) && ! *ppMemory ) RpcRaiseException( RPC_X_NULL_REF_POINTER ); // // Do this so unmarshalling ref pointers works the same as // unmarshalling unique and ptr pointers. // pBufferPointer = NULL; } NdrpPointerUnmarshall( pStubMsg, ppMemory, *ppMemory, pBufferPointer, pFormat ); return 0; } void NdrpFreeOlePointer( PMIDL_STUB_MESSAGE pStubMsg, uchar *pMemory, PFORMAT_STRING pFormat ) { NDR_POINTER_QUEUE *pOldQueue; if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { NdrPointerFree( pStubMsg, pMemory, pFormat ); } RpcFinally { if (pStubMsg->pPointerQueueState) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } NDR_ALLOC_ALL_NODES_CONTEXT * NdrpGetAllocateAllNodesContext( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) { uchar *pBuffer = pStubMsg->Buffer; // Clear memory size before calling mem size routine. pStubMsg->MemorySize = 0; // // Get the allocate all nodes memory size. Need to make sure // all the pointee as finished before continuing // { NDR_POINTER_QUEUE *pOldQueue; if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, pFormat ); } RpcFinally { if ( pStubMsg->pPointerQueueState ) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } pStubMsg->Buffer = pBuffer; ulong AllocSize = pStubMsg->MemorySize; pStubMsg->MemorySize = 0; LENGTH_ALIGN( AllocSize, __alignof(NDR_ALLOC_ALL_NODES_CONTEXT) - 1); uchar *pAllocMemory = (uchar*)NdrAllocate( pStubMsg, AllocSize + sizeof(NDR_ALLOC_ALL_NODES_CONTEXT) ); NDR_ALLOC_ALL_NODES_CONTEXT *pAllocContext = (NDR_ALLOC_ALL_NODES_CONTEXT*)(pAllocMemory + AllocSize); pAllocContext->AllocAllNodesMemory = pAllocMemory; pAllocContext->AllocAllNodesMemoryBegin = pAllocMemory; pAllocContext->AllocAllNodesMemoryEnd = (uchar*)pAllocContext; return pAllocContext; } __forceinline void NdrpPointerUnmarshallInternal( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, // Where allocated pointer is written uchar * pMemory, long * pBufferPointer, // Pointer to the wire rep. PFORMAT_STRING pFormat ) /*++ Routine Description : Private routine for unmarshalling a pointer to anything. This is the entry point for pointers embedded in structures, arrays, and unions. Used for FC_RP, FC_UP, FC_FP, FC_OP. Arguments : pStubMsg - Pointer to the stub message. ppBufferPointer - Address of the location in the buffer which holds the incomming pointer's value and will hold the final unmarshalled pointer's value. pMemory - Current memory pointer's value which we want to unmarshall into. If this value is valid the it will be copied to *ppBufferPointer and this is where stuff will get unmarshalled into. pFormat - Pointer's format string description. pStubMsg->Buffer - set to the pointee. Return : None. --*/ { ulong FullPtrRefId; uchar fPointeeAlloc; int fNewAllocAllNodes; int fNewDontFreeContext; uchar uFlagsSave; fNewAllocAllNodes = FALSE; fNewDontFreeContext = FALSE; // we need to have a check here for pointer embedded in a struct, // or pointer to pointer case. CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); // // Check the pointer type. // switch ( *pFormat ) { case FC_RP : break; case FC_IP : // On the client side, release the [in,out] interface pointer. if ( IS_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ) ) { NdrInterfacePointerUnmarshall( pStubMsg, ppMemory, pFormat, true ); return; } if ((pStubMsg->IsClient == TRUE) && (pMemory != 0)) { ((IUnknown*)pMemory)->Release(); *ppMemory = NULL ; } if ( !*pBufferPointer ) return; NdrpInterfacePointerUnmarshall( pStubMsg, ppMemory, pFormat ); if ( pBufferPointer ) *pBufferPointer = PTR_WIRE_REP(*ppMemory); return; case FC_OP : // // Burn some instructions for OLE unique pointer support. // if ( pStubMsg->IsClient ) { // // It's ok if this is an [out] unique pointer. It will get // zeroed before this routine is called and NdrPointerFree // will simply return. Need to finish all the pointees before // continueing. NdrpFreeOlePointer( pStubMsg, pMemory, pFormat); // Set the current memory pointer to 0 so that we'll alloc. pMemory = 0; } // Fall through. case FC_UP : // // Check for a null incomming pointer. Routines which call this // routine insure that the memory pointer gets nulled. // if ( ! *pBufferPointer ) { *ppMemory = NULL; return; } break; case FC_FP : // // We have to remember the incomming ref id because we overwrite // it during the QueryRefId call. // FullPtrRefId = *pBufferPointer; // we couldn't pass pBufferPointer to QueryRefId because it's 4bytes // on wire but 8bytes on 64bit. (and it'll have mix alignment issue) if ( 0 == FullPtrRefId ) { *ppMemory = NULL; return; } // // Lookup the ref id. // if ( NdrFullPointerQueryRefId( pStubMsg->FullPtrXlatTables, FullPtrRefId, FULL_POINTER_UNMARSHALLED, (void**)ppMemory) ) { // true means the RefId had been unmarshalled. *pBufferPointer = PTR_WIRE_REP( *ppMemory ); return; } // // If our query returned false then check if the returned pointer // is 0. If so then we have to scribble away the ref id in the // stub message FullPtrRefId field so that we can insert the // pointer translation later, after we've allocated the pointer. // If the returned pointer was non-null then we leave the stub // message FullPtrRefId field alone so that we don't try to // re-insert the pointer to ref id translation later. // // We also copy the returned pointer value into pMemory. This // will allow our allocation decision to be made correctly. // pMemory = *ppMemory; if ( !pMemory ) { // // Put the unmarshalled ref id into the stub message to // be used later in a call to NdrFullPointerInsertRefId. // pStubMsg->FullPtrRefId = FullPtrRefId; } break; default : NDR_ASSERT(0,"NdrpPointerUnmarshall : bad pointer type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } // // Make the initial "must allocate" decision. // // The fPointeeAlloc flag is set on the client side if the current memory // pointer is null, and on the server side it is set if the current memory // pointer has the allocate don't free attribute applied to it. // // On the client side we also set the pointer's value in the buffer equal // to the current memory pointer. // // On the server side we explicitly null out the pointer's value in the // buffer as long as it's not allocated on the stack, otherwise we set it // equal to the current memory pointer (stack allocated). // if ( pStubMsg->IsClient ) { *ppMemory = pMemory; fPointeeAlloc = ! pMemory; } else { if ( ! ALLOCED_ON_STACK(pFormat[1]) ) *ppMemory = 0; else *ppMemory = pMemory; // // If this is a don't free pointer or a parent pointer of this pointer // was a don't free pointer then we set the alloc flag. // if ( fPointeeAlloc = (DONT_FREE(pFormat[1]) || pStubMsg->ReuseBuffer || pStubMsg->fInDontFree) ) { // // If we encounter a don't free pointer which is not nested inside // of another don't free pointer then set the local and stub message // flags. // if ( ! pStubMsg->fInDontFree ) { fNewDontFreeContext = TRUE; pStubMsg->fInDontFree = TRUE; } } // // We also set the alloc flag for object interface pointers. // if ( *pFormat == FC_OP ) fPointeeAlloc = TRUE; } // // Pointer to complex type. // if ( ! SIMPLE_POINTER(pFormat[1]) ) { PFORMAT_STRING pFormatPointee; pFormatPointee = pFormat + 2; // Set the pointee format string. // Cast must be to a signed short since some offsets are negative. pFormatPointee += *((signed short *)pFormatPointee); // // Right now the server will always allocate for allocate all nodes // when told to. Eventually we want to use the rpc buffer when // possible. // // // Check if this is an allocate all nodes pointer AND that we're // not already in an allocate all nodes context. // if ( ALLOCATE_ALL_NODES(pFormat[1]) && ! pStubMsg->pAllocAllNodesContext ) { fNewAllocAllNodes = TRUE; pStubMsg->pAllocAllNodesContext = NdrpGetAllocateAllNodesContext( pStubMsg, pFormatPointee ); *ppMemory = 0; fPointeeAlloc = TRUE; // // I think this is what we'll have to add to support an [in,out] // allocate all nodes full pointer ([in] only and [out] only // allocate all nodes full pointer shouldn't need any special // treatment). // // if ( *pFormat == FC_FP ) // { // pStubMsg->FullPtrRefId = FullPtrRefId; // } // } if ( POINTER_DEREF(pFormat[1]) ) { // // Re-align the buffer. This is to cover embedded pointer to // pointers. // ALIGN(pStubMsg->Buffer,0x3); // // We can't re-use the buffer for a pointer to a pointer // because we can't null out the pointee before we've unmarshalled // it. We need the stubs to alloc pointers to pointers on the // stack. // if ( ! *ppMemory && ! pStubMsg->IsClient ) fPointeeAlloc = TRUE; if ( fPointeeAlloc ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, PTR_MEM_SIZE ); *((void **)*ppMemory) = 0; } if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); if ( pBufferPointer ) *pBufferPointer = PTR_WIRE_REP(*ppMemory); pBufferPointer = 0; ppMemory = (uchar**)*ppMemory; } // // Now call the proper unmarshalling routine. // uFlagsSave = pStubMsg->uFlags; RESET_CONF_FLAGS_TO_STANDALONE(pStubMsg->uFlags); if ( fPointeeAlloc ) SET_SKIP_REF_CHECK( pStubMsg->uFlags ); (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormatPointee)]) ( pStubMsg, ppMemory, pFormatPointee, fPointeeAlloc ); pStubMsg->uFlags = uFlagsSave; if ( *pFormatPointee == FC_USER_MARSHAL ) { if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } goto PointerUnmarshallEnd; } // // Else handle a pointer to a simple type, pointer, or string. // switch ( pFormat[2] ) { case FC_C_CSTRING : case FC_C_BSTRING : case FC_C_WSTRING : case FC_C_SSTRING : NdrConformantStringUnmarshall( pStubMsg, ppMemory, &pFormat[2], fPointeeAlloc ); goto PointerUnmarshallEnd; default : // Break to handle a simple type. break; } // // Handle pointers to simple types. // // // Align the buffer. // ALIGN(pStubMsg->Buffer,SIMPLE_TYPE_ALIGNMENT(pFormat[2])); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + SIMPLE_TYPE_BUFSIZE(pFormat[2]) ); // // We can't use the buffer for pointers to enum16 since these force // us to zero out the upper 16 bits of the memory pointer, and this // might overwrite data in the buffer that we still need! // Similar thing happens for int3264 values. // if ( pFormat[2] == FC_ENUM16 #if defined(__RPC_WIN64__) || pFormat[2] == FC_INT3264 || pFormat[2] == FC_UINT3264 #endif ) { if ( ! pStubMsg->IsClient && ! *ppMemory ) fPointeeAlloc = TRUE; } // // Check for allocation or buffer reuse. // if ( fPointeeAlloc ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, SIMPLE_TYPE_MEMSIZE(pFormat[2]) ); } else { if ( ! pStubMsg->IsClient && ! *ppMemory ) { // Set pointer into buffer. *ppMemory = pStubMsg->Buffer; } } if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // // We always get here for simple types. What this means is that // when we reuse the buffer on the server side we end up copying the // data with source and destination memory pointer equal. But this // way we can cover the enum and error_status_t cases without duplicating // a lot of code. // NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, pFormat[2] ); PointerUnmarshallEnd: if ( fNewDontFreeContext ) pStubMsg->fInDontFree = FALSE; if ( pBufferPointer ) *pBufferPointer = PTR_WIRE_REP(*ppMemory); if ( fNewAllocAllNodes ) pStubMsg->pAllocAllNodesContext = 0; } NDR_UNMRSHL_POINTER_QUEUE_ELEMENT::NDR_UNMRSHL_POINTER_QUEUE_ELEMENT( MIDL_STUB_MESSAGE *pStubMsg, uchar ** ppMemoryNew, uchar * pMemoryNew, long * pBufferPointerNew, PFORMAT_STRING pFormatNew ) : ppMemory(ppMemoryNew), pMemory(pMemoryNew), pBufferPointer(pBufferPointerNew), pFormat(pFormatNew), Memory(pStubMsg->Memory), uFlags(pStubMsg->uFlags), fInDontFree( pStubMsg->fInDontFree ), pAllocAllNodesContext( pStubMsg->pAllocAllNodesContext ), pCorrMemory( pStubMsg->pCorrMemory ) { } void NDR_UNMRSHL_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"); int fInDontFreeSave = pStubMsg->fInDontFree; pStubMsg->fInDontFree = fInDontFree; SAVE_CONTEXT pCorrMemorySave(pStubMsg->pCorrMemory, pCorrMemory ); SAVE_CONTEXT AllNodesContextSave(pStubMsg->pAllocAllNodesContext, pAllocAllNodesContext); NdrpPointerUnmarshallInternal( pStubMsg, ppMemory, pMemory, pBufferPointer, pFormat ); pStubMsg->fInDontFree = fInDontFreeSave; } #if defined(DBG) void NDR_UNMRSHL_POINTER_QUEUE_ELEMENT::Print() { DbgPrint("NDR_MRSHL_POINTER_QUEUE_ELEMENT\n"); DbgPrint("pNext: %p\n", pNext ); DbgPrint("pMemory: %p\n", pMemory ); DbgPrint("ppMemory: %p\n", ppMemory ); DbgPrint("pBufferPointer: %p\n", pBufferPointer ); DbgPrint("pFormat: %p\n", pFormat ); DbgPrint("Memory: %p\n", Memory ); DbgPrint("uFlags: %x\n", uFlags ); DbgPrint("fInDontFree: %u\n", fInDontFree ); DbgPrint("pAllocAllNodesContext: %p\n", pAllocAllNodesContext ); DbgPrint("pCorrMemorySave: %p\n", pCorrMemory ); } #endif void NdrpEnquePointerUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, // Where allocated pointer is written uchar * pMemory, long * pBufferPointer, // Pointer to the wire rep. PFORMAT_STRING pFormat ) { NDR32_POINTER_CONTEXT PointerContext( pStubMsg ); RpcTryFinally { NDR_UNMRSHL_POINTER_QUEUE_ELEMENT*pElement = new(PointerContext.GetActiveState()) NDR_UNMRSHL_POINTER_QUEUE_ELEMENT(pStubMsg, ppMemory, pMemory, pBufferPointer, pFormat ); PointerContext.Enque( pElement ); PointerContext.DispatchIfRequired(); } RpcFinally { PointerContext.EndContext(); } RpcEndFinally } void NdrpPointerUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, // Where allocated pointer is written uchar * pMemory, long * pBufferPointer, // Pointer to the wire rep. PFORMAT_STRING pFormat ) { if ( !NdrIsLowStack( pStubMsg ) ) { NdrpPointerUnmarshallInternal( pStubMsg, ppMemory, pMemory, pBufferPointer, pFormat ); return; } NdrpEnquePointerUnmarshall( pStubMsg, ppMemory, pMemory, pBufferPointer, pFormat ); } unsigned char * RPC_ENTRY NdrSimpleStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a simple structure. Used for FC_STRUCT and FC_PSTRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to the structure being unmarshalled. pFormat - Structure's format string description. fMustAlloc - TRUE if the structure must be allocate, FALSE otherwise. --*/ { uchar * pBufferSave; uint StructSize; CORRELATION_RESOURCE_SAVE; // Align the buffer. ALIGN(pStubMsg->Buffer,pFormat[1]); // Increment to the struct size field. pFormat += 2; // Get struct size and increment. StructSize = (ulong) *((ushort * &)pFormat)++; // Remember the current buffer position for the struct copy later. pBufferSave = pStubMsg->Buffer; // Set BufferMark to the beginning of the struct in the buffer. pStubMsg->BufferMark = pBufferSave; CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + StructSize ); // Increment Buffer past struct data. pStubMsg->Buffer += StructSize; // Initialize the memory pointer if needed. if ( fMustAlloc ) *ppMemory = (uchar *) NdrAllocate( pStubMsg, StructSize ); else // we'll get rid of pStubMsg->ReuseBuffer given it's basically !IsClient now // we might set the flag again through compiler flag later on. if ( REUSE_BUFFER(pStubMsg) && ! *ppMemory ) *ppMemory = pBufferSave; SET_CORRELATION_MEMORY( pBufferSave ); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // Unmarshall embedded pointers before copying the struct. if ( *pFormat == FC_PP ) { NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustAlloc ); } // Copy the struct if we're not using the rpc buffer. if ( *ppMemory != pBufferSave ) { RpcpMemoryCopy( *ppMemory, pBufferSave, StructSize ); } RESET_CORRELATION_MEMORY(); return 0; } unsigned char * RPC_ENTRY NdrConformantStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a conformant structure. Used for FC_CSTRUCT and FC_CPSTRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - TRUE if the structure must be allocate, FALSE otherwise. Return : None. --*/ { uchar * pBufferStart; PFORMAT_STRING pFormatArray; uint StructSize; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); CORRELATION_RESOURCE_SAVE; // Unmarshall the conformance count into the stub message. // Only a bogus struct can embed a conf struct; if so, ->BufferMark is set. if ( fIsEmbeddedStruct ) pStubMsg->MaxCount = *((ulong *)pStubMsg->BufferMark); else { // Align the buffer for unmarshalling the conformance count. ALIGN(pStubMsg->Buffer,3); pStubMsg->MaxCount = *((ulong * &)pStubMsg->Buffer)++; } // Re-align the buffer ALIGN(pStubMsg->Buffer, pFormat[1]); // Increment format string to structure size field. pFormat += 2; // Get flat struct size and increment format string. StructSize = (ulong) *((ushort * &)pFormat)++; // Get the conformant array's description. pFormatArray = pFormat + *((signed short *)pFormat); CHECK_EOB_RAISE_IB( pStubMsg->Buffer + StructSize ); if ( F_CORRELATION_CHECK ) { SET_CORRELATION_MEMORY( pStubMsg->Buffer + StructSize); NdrpCheckCorrelation( pStubMsg, pStubMsg->MaxCount, pFormatArray, NDR_CHECK_CONFORMANCE ); RESET_CORRELATION_MEMORY(); } // Add the size of the conformant array to the structure size. // check for possible mulitplication overflow attack here. StructSize += MultiplyWithOverflowCheck( (ulong)pStubMsg->MaxCount, *((ushort *)(pFormatArray + 2) ) ); // Check the size and the buffer limit. CHECK_BOUND( (ulong)pStubMsg->MaxCount, pFormatArray[4] & 0x0f ); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, StructSize ); // // Remember where we're going to copy from. // pBufferStart = pStubMsg->Buffer; // Set stub message Buffer field to the end of the structure in the buffer. pStubMsg->Buffer += StructSize; // Increment pFormat past the array description pFormat += 2; // Initialize the memory pointer if needed. if ( fMustAlloc ) { *ppMemory = (uchar *) NdrAllocate( pStubMsg, StructSize ); } else if ( REUSE_BUFFER(pStubMsg) && ! *ppMemory ) *ppMemory = pBufferStart; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); SET_CORRELATION_MEMORY( pBufferStart ); // Unmarshall embedded pointers before copying the struct. if ( *pFormat == FC_PP ) { // // Set BufferMark to the beginning of the structure in the buffer. // pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustAlloc ); } // Copy the struct if we're not using the rpc buffer. if ( *ppMemory != pBufferStart ) { RpcpMemoryCopy( *ppMemory, pBufferStart, StructSize ); } RESET_CORRELATION_MEMORY(); // Set the reverse flag to signal that the array has been unmarshaled. if ( fIsEmbeddedStruct ) SET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return 0; } unsigned char * RPC_ENTRY NdrConformantVaryingStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a structure which contains a conformant varying array. Used for FC_CVSTRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - Ignored. Return : None. --*/ { PFORMAT_STRING pFormatArray; uchar * pBufferStruct; uchar * pBufferArray; uint StructSize, ArrayCopySize, ArrayOffset; ulong AllocationSize; ulong Elements; uchar Alignment; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); CORRELATION_RESOURCE_SAVE; IGNORED(fMustAlloc); // Save structure's alignment. Alignment = pFormat[1]; // Increment format string to struct size field. pFormat += 2; // Get non-conformant struct size and increment format string. StructSize = (ulong) *((ushort * &)pFormat)++; // Get conformant varying array's description. pFormatArray = pFormat + *((signed short *)pFormat); AllocationSize = 0; // Conformant array size // Only a bogus struct can embed a conf struct; if so, ->BufferMark is set. if ( fIsEmbeddedStruct ) Elements = *((ulong *)pStubMsg->BufferMark); else { // Align the buffer for conformance count unmarshalling. ALIGN(pStubMsg->Buffer,3); Elements = *((ulong * &)pStubMsg->Buffer)++; } // Check the size. if ( *pFormatArray == FC_CVARRAY ) CHECK_BOUND( Elements, pFormatArray[4] & 0x0f ); else if ( pFormatArray[1] == FC_STRING_SIZED ) CHECK_BOUND( Elements, pFormatArray[2] & 0x0f ); CHECK_EOB_RAISE_IB( pStubMsg->Buffer + StructSize ); if ( F_CORRELATION_CHECK ) { SET_CORRELATION_MEMORY( pStubMsg->Buffer + StructSize); NdrpCheckCorrelation( pStubMsg, Elements, pFormatArray, NDR_CHECK_CONFORMANCE ); RESET_CORRELATION_MEMORY(); } // // For a conformant varying struct we ignore all allocation flags. // Memory must always be allocated on both client and server stubs // if the current memory pointer is null. // if ( ! *ppMemory ) { AllocationSize = StructSize; ULONG ElementSize; if ( *pFormatArray == FC_CVARRAY ) { // check for possible mulitplication overflow attack here. AllocationSize += MultiplyWithOverflowCheck( Elements, *((ushort *)(pFormatArray + 2)) ); } else // must be a conformant string { if ( *pFormatArray != FC_C_WSTRING ) AllocationSize += Elements; else { AllocationSize += MultiplyWithOverflowCheck( Elements, 2 ); } } // do the real allocation after correlation checks. } // Align for the struct ALIGN(pStubMsg->Buffer,Alignment); // Remember where the structure starts in the buffer. pBufferStruct = pStubMsg->Buffer; // Mark the start of the structure in the buffer. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past the non-conformant part of the structure. // pStubMsg->Buffer += StructSize; // Align again for variance unmarshalling. ALIGN(pStubMsg->Buffer,3); // // Get offset and actual count. Put the actual count into the MaxCount // field of the stub message, where it is used if the array has pointers. // pStubMsg->Offset = ArrayOffset = *((ulong * &)pStubMsg->Buffer)++; ArrayCopySize = *((ulong * &)pStubMsg->Buffer)++; pStubMsg->MaxCount = ArrayCopySize; // Check the offset and lentgth. if ( *pFormatArray == FC_CVARRAY ) { PFORMAT_STRING pFormatVar = pFormatArray + 8; CORRELATION_DESC_INCREMENT( pFormatVar ); CHECK_BOUND( ArrayOffset, FC_LONG ); CHECK_BOUND( ArrayCopySize, *pFormatVar & 0x0f ); if ( F_CORRELATION_CHECK ) { SET_CORRELATION_MEMORY( pBufferStruct + StructSize ); // at the end of the fixed part NdrpCheckCorrelation( pStubMsg, (ulong)pStubMsg->MaxCount, // yes, this is variance from above pFormatArray, NDR_CHECK_VARIANCE ); NdrpCheckCorrelation( pStubMsg, pStubMsg->Offset, pFormatArray, NDR_CHECK_OFFSET ); RESET_CORRELATION_MEMORY(); } } else // has to be strings here. check for invalid offset { if ( ArrayOffset != 0 ) RpcRaiseException( RPC_X_INVALID_BOUND ); } if ( (Elements < (ArrayOffset + ArrayCopySize)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); SET_CORRELATION_MEMORY( pBufferStruct ); // Remember where the array starts in the buffer. pBufferArray = pStubMsg->Buffer; // we don't need to check overflow for length_is and first_is: // if size_is doesn't overflow, and size_is > length_is+first_is, neither of them can overflow. if ( *pFormatArray == FC_CVARRAY ) { // Skip to array element size field. pFormatArray += 2; // // Compute the real offset (in bytes) from the beginning of the // array for the copy and the real total number of bytes to copy. // ArrayOffset = MultiplyWithOverflowCheck( ArrayOffset, *((ushort *)pFormatArray) ); ArrayCopySize = MultiplyWithOverflowCheck( ArrayCopySize, *((ushort *)pFormatArray) ); } else { ulong CharSize = 1; // Conformant string. if ( *pFormatArray == FC_C_WSTRING ) { // Double the offset and copy size for wide char string. ArrayOffset = MultiplyWithOverflowCheck( ArrayOffset, sizeof(wchar_t) ); ArrayCopySize = MultiplyWithOverflowCheck( ArrayCopySize, sizeof(wchar_t) ); CharSize = sizeof(wchar_t); } if ( ArrayCopySize ) { uchar * p; // Check if the terminator is there. for ( p = pStubMsg->Buffer + ArrayCopySize - CharSize; CharSize--; ) { if ( *p++ != 0 ) RpcRaiseException( RPC_X_INVALID_BOUND ); } } else // cannot be zero here. { RpcRaiseException( RPC_X_INVALID_BOUND ); } } // Set the stub message Buffer field to the end of the array/string. CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, ArrayCopySize ); pStubMsg->Buffer += ArrayCopySize; // Increment format string past offset to array description field. pFormat += 2; // allocate the memory after correlation checks. Should help avoid allocation in // early correlation. if ( AllocationSize != 0 ) { *ppMemory = (uchar *) NdrAllocate( pStubMsg, (uint) AllocationSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // // Unmarshall embedded pointers before copying the struct. // if ( *pFormat == FC_PP ) { pStubMsg->BufferMark = pBufferStruct; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, (uchar) (AllocationSize != 0) ); } RESET_CORRELATION_MEMORY(); // // Copy the array. Make sure the destination memory pointer is at // the proper offset from the beginning of the array in memory. // RpcpMemoryCopy( *ppMemory, pBufferStruct, StructSize ); RpcpMemoryCopy( *ppMemory + StructSize + ArrayOffset, pBufferArray, ArrayCopySize ); // Set the reverse flag to signal that the array has been unmarshaled. if ( fIsEmbeddedStruct ) SET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return 0; } #if 0 unsigned char * RPC_ENTRY NdrHardStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a hard structure. Used for FC_HARD_STRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pUnion; uchar * pEnum; BOOL fNewMemory; ushort CopySize; ALIGN(pStubMsg->Buffer,pFormat[1]); pFormat += 2; if ( fNewMemory = (! *ppMemory || fMustAlloc) ) { // // Allocate if forced to, or if we have a union. // if ( fMustAlloc || *((short *)&pFormat[12]) ) *ppMemory = (uchar *) NdrAllocate( pStubMsg, *((ushort *)pFormat) ); else // pStubMsg->ReuseBuffer assumed *ppMemory = pStubMsg->Buffer; } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); pFormat += 8; CopySize = *((ushort *)pFormat); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + CopySize ); if ( *ppMemory != pStubMsg->Buffer ) { RpcpMemoryCopy( *ppMemory, pStubMsg->Buffer, CopySize ); } // // Zero out the upper two bytes of enums! // if ( *((short *)&pFormat[-2]) != (short) -1 ) { pEnum = *ppMemory + *((ushort *)&pFormat[-2]); *((int *)(pEnum)) = *((int *)pEnum) & ((int)0x7fff) ; } pStubMsg->Buffer += *((ushort *)pFormat)++; // // See if we have a union. // if ( *((short *)&pFormat[2]) ) { pUnion = *ppMemory + *((ushort *)pFormat); if ( fNewMemory ) MIDL_memset( pUnion, 0, *((ushort *)&pFormat[-10]) - *((ushort *)pFormat) ); pFormat += 2; pFormat += *((short *)pFormat); (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)])( pStubMsg, &pUnion, pFormat, FALSE ); } return 0; } #endif // 0 unsigned char * RPC_ENTRY NdrComplexStructUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a complex structure. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the structure should be unmarshalled. pFormat - Structure's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pBuffer; uchar * pBufferMark; uchar * pMemory; PFORMAT_STRING pFormatPointers; PFORMAT_STRING pFormatArray; PFORMAT_STRING pFormatComplex; PFORMAT_STRING pFormatSave; uint StructSize; long Alignment; long Align8Mod; uchar fIsEmbeddedStruct = IS_EMBED_CONF_STRUCT( pStubMsg->uFlags ); BOOL fOldIgnore; BOOL fSetPointerBufferMark; BOOL fEmbedConfStructContext; CORRELATION_RESOURCE_SAVE; IGNORED(fMustAlloc); pFormatSave = pFormat; StructSize = 0; // Get structure's buffer alignment. Alignment = pFormat[1]; // Increment to the conformat array offset field. pFormat += 4; // Get conformant array description. if ( *((ushort *)pFormat) ) pFormatArray = pFormat + *((signed short *)pFormat); else pFormatArray = 0; pFormat += 2; // Get pointer layout description. if ( *((ushort *)pFormat) ) pFormatPointers = pFormat + *((ushort *)pFormat); else pFormatPointers = 0; pFormat += 2; // // If the stub message PointerBufferMark field is not currently set, then // set it to the end of the flat part of structure in the buffer. // // We do this to handle embedded pointers. // if ( fSetPointerBufferMark = ! pStubMsg->PointerBufferMark ) { pBuffer = pStubMsg->Buffer; // Save field. fOldIgnore = pStubMsg->IgnoreEmbeddedPointers; pStubMsg->IgnoreEmbeddedPointers = TRUE; // Clear MemorySize. pStubMsg->MemorySize = 0; // // Get a buffer pointer to where the struct's pointees will be // unmarshalled from and remember the flat struct size in case we // have to allocate. // // Note that this function will recursively do buffer overrun // checks, bound checks, and sanity checks on size, actual count, // and offset. And further checks in this function or called functions // are redundant. StructSize = NdrComplexStructMemorySize( pStubMsg, pFormatSave ); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); // This is where any pointees begin in the buffer. pStubMsg->PointerBufferMark = pStubMsg->Buffer; pStubMsg->IgnoreEmbeddedPointers = fOldIgnore; pStubMsg->Buffer = pBuffer; } if ( fMustAlloc || ! *ppMemory ) { // // We can only get here if pStubMsg->PointerBufferMark was 0 upon // entry to this proc. // NDR_ASSERT( StructSize ,"Complex struct size is 0" ); *ppMemory = (uchar*)NdrAllocate( pStubMsg, StructSize ); // // Zero out all of the allocated memory so that deeply nested pointers // getted properly zeroed out. // MIDL_memset( *ppMemory, 0, StructSize ); } // Insert the full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // // Now check if there is a conformant array and mark where the conformance // will be unmarshalled from. // fEmbedConfStructContext = fIsEmbeddedStruct; if ( pFormatArray && !fIsEmbeddedStruct ) { ALIGN(pStubMsg->Buffer,3); pStubMsg->BufferMark = pStubMsg->Buffer; // // Increment the buffer pointer 4 bytes for every dimension in the // conformant array. // pStubMsg->Buffer += NdrpArrayDimensions( pStubMsg, pFormatArray, FALSE ) * 4; if ( FixWireRepForDComVerGTE54( pStubMsg ) ) fEmbedConfStructContext = TRUE; } // BufferMark may be set up by an outer bogus struct. pBufferMark = pStubMsg->BufferMark; // conformance count mark pStubMsg->BufferMark = pBufferMark; // Align the buffer on the struct's alignment. ALIGN(pStubMsg->Buffer,Alignment); // Get the beginning memory pointer. pMemory = *ppMemory; // Set it to the beginning of the struct. SET_CORRELATION_MEMORY( pMemory ); // // This is used for support of structs with doubles passed on an // i386 stack. The alignment of such struct's is no guaranteed to be on // an 8 byte boundary. Similarly, od 16 bit platforms for 4 byte align. // // A cast to long is what we need. Align8Mod = 0x7 & PtrToLong( pMemory ); // // Unmarshall 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 : NdrSimpleTypeUnmarshall( pStubMsg, pMemory, *pFormat ); pMemory += SIMPLE_TYPE_MEMSIZE(*pFormat); break; case FC_IGNORE : ALIGN(pStubMsg->Buffer,3); pStubMsg->Buffer += 4; pMemory += PTR_MEM_SIZE; break; case FC_POINTER : { uchar * pMemorySave = NULL; ALIGN( pStubMsg->Buffer, 0x3 ); long *pPointerId = (long*)pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; // A sized pointer here would have an offset from the beginning of the struct. // for [in,out] struct containing "[size_is(num)] IFoo ** pfoo", // we need to setup the pStub->memory pointing to the beginning of the struct // such that we can get the conformance correctly during freeing pass, before // unmarshall the returning result to the same memory spot. if (FC_OP == *pFormatPointers ) { pMemorySave = pStubMsg->Memory; pStubMsg->Memory = *ppMemory; } POINTER_BUFFER_SWAP_CONTEXT SwapContext(pStubMsg); NdrpPointerUnmarshall( pStubMsg, (uchar **)pMemory, // Where the memory pointer will be written *((uchar **)pMemory), pPointerId, // Where the pointer in the buffer is. pFormatPointers ); if (FC_OP == *pFormatPointers ) pStubMsg->Memory = pMemorySave; // Increment past the memory for the pointer. pMemory += PTR_MEM_SIZE; pFormatPointers += 4; break; } // // Embedded complex things. // case FC_EMBEDDED_COMPLEX : { // Note, we opened a new block, so this is a different set of // save variables than the one on the top. CORRELATION_RESOURCE_SAVE; // Add memory padding. pMemory += pFormat[1]; pFormat += 2; // Get the type's description. pFormatComplex = pFormat + *((signed short UNALIGNED *)pFormat); if ( FC_IP == *pFormatComplex ) { // Treat like an embedded pointer except set the // mark for iid_is. SET_CORRELATION_MEMORY( pMemory ); ALIGN( pStubMsg->Buffer, 0x3 ); long *pPointerId = (long*)pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; POINTER_BUFFER_SWAP_CONTEXT SwapContext(pStubMsg); NdrpPointerUnmarshall( pStubMsg, (uchar **)pMemory, // Where the memory pointer will be written *((uchar **)pMemory), pPointerId, // Where the pointer in the buffer is. pFormatComplex ); pMemory += PTR_MEM_SIZE; pFormat++; RESET_CORRELATION_MEMORY(); break; } // A sized thingy here is relative to its position. SET_CORRELATION_MEMORY( pMemory ); // Needed for an embedded conf struct. // pStubMsg->BufferMark = pBufferMark; if ( fEmbedConfStructContext ) SET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, &pMemory, pFormatComplex, FALSE ); pMemory = NdrpMemoryIncrement( pStubMsg, pMemory, pFormatComplex ); RESET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); RESET_CORRELATION_MEMORY(); // // Increment the main format string one byte. The loop // will increment it one more byte past the offset field. // pFormat++; } break; case FC_ALIGNM2 : ALIGN( pMemory, 0x1 ); break; case FC_ALIGNM4 : ALIGN( pMemory, 0x3 ); break; case FC_ALIGNM8 : // // We have to play some tricks for the i386 to handle the case // when an 8 byte aligned structure is passed by value. The // alignment of the struct on the stack is not guaranteed to be // on an 8 byte boundary. // pMemory -= Align8Mod; ALIGN( pMemory, 0x7 ); pMemory += Align8Mod; break; case FC_STRUCTPAD1 : case FC_STRUCTPAD2 : case FC_STRUCTPAD3 : case FC_STRUCTPAD4 : case FC_STRUCTPAD5 : case FC_STRUCTPAD6 : case FC_STRUCTPAD7 : // // Increment memory pointer by amount of padding. // pMemory += (*pFormat - FC_STRUCTPAD1) + 1; break; case FC_STRUCTPADN : // FC_STRUCTPADN 0 pMemory += *(((unsigned short *)pFormat) + 1); pFormat += 3; break; case FC_PAD : break; // // Done with layout. // case FC_END : goto ComplexUnmarshallEnd; default : NDR_ASSERT(0,"NdrComplexStructUnmarshall : bad format char"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return 0; } } ComplexUnmarshallEnd: RESET_CORRELATION_MEMORY(); // // Unmarshall conformant array if the struct has one. // if ( pFormatArray && !fIsEmbeddedStruct && ! IS_CONF_ARRAY_DONE( pStubMsg->uFlags ) ) { PPRIVATE_UNMARSHALL_ROUTINE pfnPUnmarshall; switch ( *pFormatArray ) { case FC_CARRAY : pfnPUnmarshall = NdrpConformantArrayUnmarshall; break; case FC_CVARRAY : pfnPUnmarshall = NdrpConformantVaryingArrayUnmarshall; break; case FC_BOGUS_ARRAY : pfnPUnmarshall = NdrpComplexArrayUnmarshall; break; case FC_C_WSTRING : ALIGN( pMemory, 1 ); // fall through // case FC_C_CSTRING : // case FC_C_BSTRING : // case FC_C_SSTRING : default : pfnPUnmarshall = NdrpConformantStringUnmarshall; break; } // Set it to the end of the non-conformant part of the struct. SET_CORRELATION_MEMORY( pMemory ); // // Unmarshall the conformance count of the outer array dimension for // unidimensional arrays. // pStubMsg->MaxCount = *((ulong *)pBufferMark); // // Mark where conformace counts are in the buffer. // pStubMsg->BufferMark = pBufferMark; // // Unmarshall the array/string. The final flag is the fMustCopy flag, // which must be set. // (*pfnPUnmarshall)( pStubMsg, &pMemory, pFormatArray, TRUE, FALSE ); RESET_CORRELATION_MEMORY(); } // // Now fix up the stub message Buffer field if we set the PointerBufferMark // field. // if ( fSetPointerBufferMark ) { pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; } if ( fIsEmbeddedStruct ) SET_EMBED_CONF_STRUCT( pStubMsg->uFlags ); else RESET_CONF_ARRAY_DONE( pStubMsg->uFlags ); return 0; } unsigned char * RPC_ENTRY NdrNonConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls a non conformant string. Used for FC_CSTRING, FC_WSTRING, FC_SSTRING, and FC_BSTRING (NT Beta2 compatability only). Arguments : pStubMsg - Pointer to the stub message. pMemory - Double pointer to the string should be unmarshalled. pFormat - String's format string description. fMustAlloc - Ignored. Return : None. --*/ { ulong Offset, Count, AllocSize, CharSize; IGNORED(fMustAlloc); // Align the buffer. ALIGN(pStubMsg->Buffer,3); // Get the count. Offset = *((ulong * &)pStubMsg->Buffer)++; Count = *((ulong * &)pStubMsg->Buffer)++; // Get total number of elements. AllocSize = (ulong) *((ushort *)(pFormat + 2)); CharSize = 1; // Adjust count for wide char strings and stringable structs. // Adjust alloc size for wide char strings and stringable structs. switch ( *pFormat ) { case FC_WSTRING : CharSize = 2; Count *= 2; AllocSize = MultiplyWithOverflowCheck( AllocSize , 2 ); break; case FC_SSTRING : CharSize = pFormat[1]; Count *= pFormat[1]; AllocSize = MultiplyWithOverflowCheck( AllocSize, pFormat[1] ); break; default : break; } if ( Offset != 0 || AllocSize < Count ) RpcRaiseException( RPC_X_INVALID_BOUND ); if ( Count ) { uchar * p; CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, Count ); // Check if the terminator is there. for ( p = pStubMsg->Buffer + Count - CharSize; CharSize--; ) { if ( *p++ != 0 ) RpcRaiseException( RPC_X_INVALID_BOUND ); } } else { // any MS product will generate non-zero out; // what about interop? will they send zero in valid case? RpcRaiseException( RPC_X_INVALID_BOUND ); } // Allocate memory if needed. if ( ! *ppMemory ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) AllocSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); RpcpMemoryCopy( *ppMemory, pStubMsg->Buffer, (uint) Count ); // Update buffer pointer. pStubMsg->Buffer += Count; return 0; } unsigned char * RPC_ENTRY NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine description : Unmarshalls 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 the stub message. ppMemory - Double pointer to where the string should be unmarshalled. pFormat - String's format string description. fMustAlloc - TRUE if the string must be allocated, FALSE otherwise. Return : None. --*/ { uchar fMustCopy; ulong MaxCount; if ( pStubMsg->pArrayInfo == 0 ) { ulong ActualCount, Offset; ulong ElementSize; ulong ConformanceType = FC_LONG; BOOL fIsSized; // find string type if ( *pFormat != FC_C_SSTRING ) { // Typical case: char and wchar strings ElementSize = (*pFormat == FC_C_WSTRING) ? 2 : 1; fIsSized = (pFormat[1] == FC_STRING_SIZED); if ( fIsSized ) ConformanceType = (pFormat[2] & 0x0f); } else { ElementSize = pFormat[1]; fIsSized = (pFormat[2] == FC_STRING_SIZED); if ( fIsSized ) ConformanceType = (pFormat[4] & 0x0f); } // Align the buffer for conformance unmarshalling. ALIGN( pStubMsg->Buffer,3 ); MaxCount = *((ulong * &)pStubMsg->Buffer)++; Offset = ((ulong *)pStubMsg->Buffer)[0]; ActualCount = ((ulong *)pStubMsg->Buffer)[1]; CHECK_BOUND( MaxCount, ConformanceType ); if ( (Offset != 0) || (MaxCount < ActualCount) ) RpcRaiseException( RPC_X_INVALID_BOUND ); MultiplyWithOverflowCheck( MaxCount, ElementSize ); CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, (ActualCount * ElementSize) + 8); // Defer the termination check till NdrpConformantStringUnmarshall. // // Initialize the memory pointer if needed. If the string is sized // then we always malloc on the server side. // fMustAlloc = fMustAlloc || (!pStubMsg->IsClient && fIsSized); if ( fMustAlloc ) { fMustCopy = TRUE; } else { if ( REUSE_BUFFER(pStubMsg) ) *ppMemory = pStubMsg->Buffer + 8; fMustCopy = FALSE; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } } else { // // If this is part of a multidimensional array then we get the location // where the conformance is located from a special place. // When coming here, the StubMsg->Buffer is already behind conf sizes. // MaxCount = (pStubMsg->pArrayInfo-> BufferConformanceMark[pStubMsg->pArrayInfo->Dimension]); // // We must copy the string from the buffer to new memory. // fMustCopy = TRUE; // Since this case is called by NdrComplexArrayUnmarshall, the buffer will // have already been validated for buffer overruns and bound checks in // NdrComplexArrayMemorySize. // The offset and actual counts will also have been checked for sanity. } // Load up conformant size for next stage. pStubMsg->MaxCount = MaxCount; // Call the private unmarshalling routine to do the work. NdrpConformantStringUnmarshall( pStubMsg, ppMemory, pFormat, fMustCopy, fMustAlloc ); return 0; } void NdrpConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustCopy , uchar fMustAlloc ) /*++ Routine description : Private routine for unmarshalling a conformant string. This is the entry point for unmarshalling an embedded conformant strings. Used for FC_C_CSTRING, FC_C_WSTRING, FC_C_SSTRING, and FC_C_BSTRING (NT Beta2 compatability only). Note this functions is only called from NdrConformantStringUnmarshall and NdrComplexStructUnmarshall. NdrComplexStructUnmarshall calls NdrComplexStructMemSize which validates everything except correlation. This allows many validation checks to be skipped. If the call is through NdrConformantStringUnmarshall, most of the necessary checks are in NdrConformantStringUnmarshall. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to where the string should be unmarshalled. pFormat - String's format string description. fMustCopy - TRUE if the string must be copied from the buffer to memory, FALSE otherwise. Return : None. --*/ { ulong Offset, Count, CharSize; BOOL fIsSized; fIsSized = (*pFormat != FC_C_SSTRING) ? (pFormat[1] == FC_STRING_SIZED) : (pFormat[2] == FC_STRING_SIZED); if ( fIsSized && F_CORRELATION_CHECK) { NdrpCheckCorrelation( pStubMsg, (long)pStubMsg->MaxCount, pFormat, NDR_CHECK_CONFORMANCE ); } // Align for variance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall the string count. Offset = *((ulong * &)pStubMsg->Buffer)++; Count = *((ulong * &)pStubMsg->Buffer)++; // Adjust the count for a wide strings and stringable structs. // This is good enough for BSTRs as the mem pointer has already moved. switch ( *pFormat ) { case FC_C_WSTRING : CharSize = 2; Count *= 2; break; case FC_C_SSTRING : CharSize = pFormat[1]; Count *= pFormat[1]; break; default : CharSize = 1; break; } // String must have a terminator since we computed the size // in marshaling with wcslen/strlen+charsize and the app has no // method to size a string without a terminator. if ( 0 == Count ) { RpcRaiseException( RPC_X_INVALID_BOUND ); } if ( Count ) { uchar * p; ulong ElemSize = CharSize; // Check if the terminator is there. for ( p = pStubMsg->Buffer + Count - ElemSize; ElemSize--; ) { if ( *p++ != 0 ) RpcRaiseException( RPC_X_INVALID_BOUND ); } } if ( fMustAlloc ) { *ppMemory = (uchar *) NdrAllocate( pStubMsg, pStubMsg->MaxCount * CharSize ); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } // Copy the string if needed. if ( pStubMsg->IsClient || fMustCopy ) { RpcpMemoryCopy( *ppMemory, pStubMsg->Buffer, (uint) Count ); } // Update buffer pointer. pStubMsg->Buffer += Count; } unsigned char * RPC_ENTRY NdrFixedArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a fixed array of any number of dimensions. Used for FC_SMFARRAY and FC_LGFARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array to unmarshall. pFormat - Array's format string description. fMustAlloc - TRUE if the array must be allocated, FALSE otherwise. Return : None. --*/ { uchar * pBufferStart; ulong Size; ALIGN(pStubMsg->Buffer,pFormat[1]); // Get the total array size. if ( *pFormat == FC_SMFARRAY ) { pFormat += 2; Size = (ulong) *((ushort * &)pFormat)++; } else // *pFormat++ == FC_LGFARRAY { pFormat += 2; Size = *((ulong UNALIGNED * &)pFormat)++; } pBufferStart = pStubMsg->Buffer; CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + Size ); // Set stub message buffer pointer past array. pStubMsg->Buffer += Size; // Initialize the memory pointer if necessary. if ( fMustAlloc ) *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) Size ); else if (REUSE_BUFFER(pStubMsg) && ! *ppMemory ) *ppMemory = pBufferStart; // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // Unmarshall embedded pointers. if ( *pFormat == FC_PP ) { // Mark the beginning of the array in the buffer. pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustAlloc ); } // Copy the array if we're not using the rpc buffer to hold it. if ( *ppMemory != pBufferStart ) { RpcpMemoryCopy( *ppMemory, pBufferStart, (uint) Size ); } return 0; } unsigned char * RPC_ENTRY NdrConformantArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a top level one dimensional conformant array. Used for FC_CARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to array to be unmarshalled. pFormat - Array's format string description. Return : None. --*/ { ulong CopySize; // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall the conformance count. pStubMsg->MaxCount = *((ulong * &)pStubMsg->Buffer)++; CHECK_BOUND( (ulong)pStubMsg->MaxCount, pFormat[4] & 0x0f ); CopySize = MultiplyWithOverflowCheck( (ulong)pStubMsg->MaxCount , *((ushort *)(pFormat + 2)) ); // Buffer size checking will be done in NdrpConformantArrayUnmarshall after alignment. // Initialize the memory pointer if necessary. if (!fMustAlloc && REUSE_BUFFER(pStubMsg) && ! *ppMemory ) { *ppMemory = pStubMsg->Buffer; // // Align memory pointer on an 8 byte boundary if needed. // We can't align the buffer pointer because we haven't made // the check for size_is == 0 yet. // ALIGN(*ppMemory, pFormat[1]); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } NdrpConformantArrayUnmarshall( pStubMsg, ppMemory, pFormat, fMustAlloc, fMustAlloc); return 0; } void NdrpConformantArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustCopy, uchar fMustAlloc ) /*++ Routine Description : Private routine for unmarshalling a one dimensional conformant array. This is the entry point for unmarshalling an embedded conformant array. Used for FC_CARRAY. Note this functions is only called from NdrConformantArrayUnmarshall and NdrComplexStructUnmarshall. NdrComplexStructUnmarshall calls NdrComplexStructMemSize which validates everything except correlation. NdrConformantArrayUnmarshall also does buffer validation. This allows many validation checks to be skipped. Arguments : pStubMsg - Pointer to the stub message. pMemory - Array being unmarshalled. pFormat - Array's format string description. Return : None. --*/ { uchar * pBufferStart; ulong CopySize; // do correlation testing even if the array size is zero if (F_CORRELATION_CHECK ) { NdrpCheckCorrelation( pStubMsg, (long) pStubMsg->MaxCount, pFormat, NDR_CHECK_CONFORMANCE ); } // Return if array size is 0 so that we don't align the buffer. if ( ! pStubMsg->MaxCount ) { // allocate before return; shouldn't happen here. if ( fMustAlloc ) { // Compute total array size in bytes. *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) 0 ); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } return; } ALIGN(pStubMsg->Buffer,pFormat[1]); // Compute total array size in bytes. CopySize = MultiplyWithOverflowCheck( (ulong)pStubMsg->MaxCount , *((ushort *)(pFormat + 2)) ); pBufferStart = pStubMsg->Buffer; CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, CopySize); pStubMsg->Buffer += CopySize; // we need to copy the whole allocated size in conformance array if ( fMustAlloc ) { // Compute total array size in bytes. *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) CopySize ); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } // Increment the format string pointer to possible pointer layout. pFormat += 8; CORRELATION_DESC_INCREMENT( pFormat ); // Unmarshall embedded pointers. if ( *pFormat == FC_PP ) { // Mark the beginning of the array in the buffer. pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustCopy ); } // Copy the array if we're not using the rpc message buffer for it. if ( pStubMsg->IsClient || fMustCopy ) { RpcpMemoryCopy( *ppMemory, pBufferStart, (uint) CopySize ); } } unsigned char * RPC_ENTRY NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a top level one dimensional conformant varying array. Used for FC_CVARRAY. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array being unmarshalled. pFormat - Array's format string description. fMustAlloc - Ignored. Return : None. --*/ { ulong ArrayElements = 0; // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall the conformance size. ArrayElements = *((ulong * &)pStubMsg->Buffer)++; { ulong Size; ulong Offset, ActualCount; PFORMAT_STRING pFormatVar; CHECK_BOUND( ArrayElements, pFormat[4] & 0x0f ); Offset = *((ulong *)pStubMsg->Buffer); CHECK_BOUND( Offset, FC_LONG ); ActualCount = *((ulong *)(pStubMsg->Buffer + 4)); pFormatVar = pFormat + 8; CORRELATION_DESC_INCREMENT( pFormatVar ); CHECK_BOUND( ActualCount, *pFormatVar & 0x0f ); // we only need to check overflow for conformant size . we don't need // to check varying overflow after we check conformance overflow MultiplyWithOverflowCheck( ArrayElements, *((ushort *)(pFormat + 2)) ); Size = ActualCount * *((ushort *)(pFormat + 2)); if ( ((long)Offset < 0) || (ArrayElements < (Offset + ActualCount)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); if ( (pStubMsg->Buffer + 8 + Size) > pStubMsg->BufferEnd ) RpcRaiseException( RPC_X_INVALID_BOUND ); } // // For a conformant varying array, we can't reuse the buffer // because it doesn't hold the total size of the array. So // allocate if the current memory pointer is 0. // if ( ! *ppMemory ) { fMustAlloc = TRUE; } else { fMustAlloc = FALSE; // Insert full pointer to ref id translation if needed. // do this only when not allocating memory. this will be done // in p version if new memory is allocated. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } pStubMsg->MaxCount = ArrayElements; NdrpConformantVaryingArrayUnmarshall( pStubMsg, ppMemory, pFormat, fMustAlloc, fMustAlloc); return 0; } void NdrpConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustCopy, uchar fMustAlloc ) /*++ Routine Description : Private routine for unmarshalling a one dimensional conformant varying array. This is the entry point for unmarshalling an embedded conformant varying array. Used for FC_CVARRAY. Note this functions is only called from NdrConformantVaryingArrayUnmarshall and NdrComplexStructUnmarshall. NdrComplexStructUnmarshall calls NdrComplexStructMemSize which validates everything except correlation. NdrConformantVaryingArrayUnmarshall also does buffer validation. This allows many validation checks to be skipped. Arguments : pStubMsg - Pointer to the stub message. pMemory - Array being unmarshalled. pFormat - Array's format string description. fMustCopy - Ignored. Return : None. --*/ { uchar * pBufferStart; ulong CopyOffset, CopySize; ushort ElemSize; IGNORED(fMustCopy); // Align the buffer for conformance unmarshalling. ALIGN(pStubMsg->Buffer,3); // Unmarshall offset and actual count. pStubMsg->Offset = *((ulong * &)pStubMsg->Buffer)++; pStubMsg->ActualCount = *((ulong * &)pStubMsg->Buffer)++; if (F_CORRELATION_CHECK ) { NdrpCheckCorrelation( pStubMsg, (long) pStubMsg->MaxCount, pFormat, NDR_CHECK_CONFORMANCE ); NdrpCheckCorrelation( pStubMsg, (long) pStubMsg->ActualCount, pFormat, NDR_CHECK_VARIANCE ); NdrpCheckCorrelation( pStubMsg, (long) pStubMsg->Offset, pFormat, NDR_CHECK_OFFSET ); } ElemSize = *((ushort *)(pFormat + 2)); // // Return if length is 0. // if ( ! pStubMsg->ActualCount ) { // needs to allocate before return. if ( fMustAlloc ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) pStubMsg->MaxCount * ElemSize ); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } return; } CopyOffset = MultiplyWithOverflowCheck(pStubMsg->Offset , ElemSize ); CopySize = MultiplyWithOverflowCheck( pStubMsg->ActualCount , ElemSize ); ALIGN(pStubMsg->Buffer, pFormat[1]); pBufferStart = pStubMsg->Buffer; // Increment buffer pointer past array. CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, CopySize ); pStubMsg->Buffer += CopySize; // Increment format string to possible pointer description. pFormat += 12; CORRELATION_DESC_INCREMENT( pFormat ); CORRELATION_DESC_INCREMENT( pFormat ); if ( fMustAlloc ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) pStubMsg->MaxCount * ElemSize ); // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); } // Unmarshall embedded pointers first. if ( *pFormat == FC_PP ) { // // Set the MaxCount field equal to the variance count. // The pointer unmarshalling routine uses the MaxCount field // to determine the number of times an FC_VARIABLE_REPEAT // pointer is unmarshalled. In the face of variance the // correct number of time is the actual count, not MaxCount. // pStubMsg->MaxCount = pStubMsg->ActualCount; // // Mark the location of the first transmitted array element in // the buffer. // pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fMustCopy ); } // Always copy. Buffer reuse is not possible. RpcpMemoryCopy( *ppMemory + CopyOffset, pBufferStart, (uint) CopySize ); } unsigned char * RPC_ENTRY NdrVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls top level or embedded a one dimensional varying array. Used for FC_SMVARRAY and FC_LGVARRAY. Arguments : pStubMsg - Pointer to the stub message. pMemory - Array being unmarshalled. pFormat - Array's format string description. fMustAlloc - Ignored. --*/ { uchar * pBufferStart; ulong TotalSize; ulong Offset, Count; ulong CopyOffset, CopySize; ushort ElemSize; uchar fNewMemory; long Elements; // Align the buffer for variance unmarshalling. ALIGN(pStubMsg->Buffer,3); Offset = *((ulong * &)pStubMsg->Buffer)++; Count = *((ulong * &)pStubMsg->Buffer)++; if ( ! Count ) return 0; // We fish out type from the (old part of the) variance descriptor. CHECK_BOUND( Offset, FC_LONG); CHECK_BOUND( Count, pFormat[(*pFormat == FC_SMVARRAY) ? 8 : 12] & 0x0f ); Elements = (*pFormat == FC_SMVARRAY) ? *((ushort *)(pFormat + 4)) : *((ulong UNALIGNED *)(pFormat + 6)); if ( ((long)Offset < 0 ) || (Elements < (long)(Count + Offset)) ) RpcRaiseException( RPC_X_INVALID_BOUND ); if (F_CORRELATION_CHECK ) { NdrpCheckCorrelation( pStubMsg, (long)Count, pFormat, NDR_CHECK_VARIANCE ); NdrpCheckCorrelation( pStubMsg, (long)Offset, pFormat, NDR_CHECK_OFFSET ); } ALIGN(pStubMsg->Buffer, pFormat[1]); // Get array's total size and increment to element size field. if ( *pFormat == FC_SMVARRAY ) { TotalSize = (ulong) *((ushort *)(pFormat + 2)); pFormat += 6; } else { TotalSize = *((ulong UNALIGNED *)(pFormat + 2)); pFormat += 10; } if ( fNewMemory = ! *ppMemory ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) TotalSize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); ElemSize = *((ushort *)pFormat); CopyOffset = MultiplyWithOverflowCheck( Offset, ElemSize ); CopySize = MultiplyWithOverflowCheck( Count, ElemSize ); if ( (long) CopyOffset < 0 || ( TotalSize < CopyOffset + CopySize ) ) RpcRaiseException( RPC_X_INVALID_BOUND ); pBufferStart = pStubMsg->Buffer; CHECK_EOB_WITH_WRAP_RAISE_IB( pStubMsg->Buffer, CopySize ); pStubMsg->Buffer += CopySize; // Increment format string to possible pointer description. pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); // Unmarshall embedded pointers. if ( *pFormat == FC_PP ) { // // Set the MaxCount field equal to the variance count. // The pointer unmarshalling routine uses the MaxCount field // to determine the number of times an FC_VARIABLE_REPEAT // pointer is unmarshalled. In the face of variance the // correct number of time is the actual count, not MaxCount. // pStubMsg->MaxCount = Count; // // Mark the location of the first transmitted array element in // the buffer // pStubMsg->BufferMark = pBufferStart; NdrpEmbeddedPointerUnmarshall( pStubMsg, *ppMemory, pFormat, fNewMemory ); } RpcpMemoryCopy( *ppMemory + CopyOffset, pBufferStart, (uint) CopySize ); return 0; } unsigned char * RPC_ENTRY NdrComplexArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a top level complex array. Used for FC_BOGUS_STRUCT. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array being unmarshalled. pFormat - Array's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pBuffer; long ArraySize; BOOL fSetPointerBufferMark; ArraySize = 0; // // Setting this flag means that the array is not embedded inside of // another complex struct or array. // fSetPointerBufferMark = ! pStubMsg->PointerBufferMark; if ( fSetPointerBufferMark ) { BOOL fOldIgnore; PFORMAT_STRING pFormatPP; pBuffer = pStubMsg->Buffer; fOldIgnore = pStubMsg->IgnoreEmbeddedPointers; pStubMsg->IgnoreEmbeddedPointers = TRUE; pStubMsg->MemorySize = 0; // // Get a buffer pointer to where the arrays's pointees will be // unmarshalled from and remember the array size in case we // have to allocate. // // Note this function will recursively check buffer overflows, // bounds, and trial sanity checks on array offsets, sizes, // and actual counts. This make additional checks in this // function redundant. ArraySize = NdrComplexArrayMemorySize( pStubMsg, pFormat ); // at least we are not out of bound in flat part. not really necessary // but good to have. CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); // // PointerBufferaMark is where the pointees begin in the buffer. // If this is an array of ref pointers then we don't want to set // this, all we wanted was the array size. // pFormatPP = pFormat + 12; CORRELATION_DESC_INCREMENT( pFormatPP ); CORRELATION_DESC_INCREMENT( pFormatPP ); if ( *pFormatPP != FC_RP ) { pStubMsg->PointerBufferMark = pStubMsg->Buffer; } else fSetPointerBufferMark = FALSE; pStubMsg->IgnoreEmbeddedPointers = fOldIgnore; pStubMsg->Buffer = pBuffer; } if ( fMustAlloc || ! *ppMemory ) { *ppMemory = (uchar*)NdrAllocate( pStubMsg, (uint) ArraySize ); // // Zero out the memory of the array if we allocated it, to insure // that all embedded pointers are zeroed out. Blech. // MIDL_memset( *ppMemory, 0, (uint) ArraySize ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); // // Check for a conformance description. // if ( ( *((long UNALIGNED *)(pFormat + 4)) != 0xffffffff ) && ( pStubMsg->pArrayInfo == 0 ) ) { // // The outer most array dimension sets the conformance marker. // ALIGN(pStubMsg->Buffer,0x3); // Mark where the conformance count(s) will be unmarshalled from. pStubMsg->BufferMark = pStubMsg->Buffer; // Increment past conformance count(s). pStubMsg->Buffer += NdrpArrayDimensions( pStubMsg, pFormat, FALSE ) * 4; } NdrpComplexArrayUnmarshall( pStubMsg, ppMemory, pFormat, TRUE, FALSE ); if ( fSetPointerBufferMark ) { // // This will set the buffer pointer to end of all of the array's // unmarshalled data in the buffer. // pStubMsg->Buffer = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; } return 0; } void NdrpComplexArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustCopy, uchar fMustAlloc ) /*++ Routine Description : Private routine for unmarshalling a complex array. This is the entry point for unmarshalling an embedded complex array. Used for FC_BOGUS_ARRAY. Note this functions is only called from NdrComplexArrayUnmarshall and NdrComplexStructUnmarshall. NdrComplexStructUnmarshall calls NdrComplexStructMemSize which validates everything except correlation. MdrComplexArrayUnmarshall has a similar check. This allows many validation checks to be skipped. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the array being unmarshalled. pFormat - Array's format string description. fMustCopy - Ignored. Return : None. --*/ { ARRAY_INFO ArrayInfo; PARRAY_INFO pArrayInfo; PUNMARSHALL_ROUTINE pfnUnmarshall; PFORMAT_STRING pFormatSave; ulong Elements; ulong Offset, Count; ulong MemoryElementSize; long Dimension; uchar Alignment; bool UseBrokenInterfacePointer = false; // this is called from ComplexStruct & ComplexArray, and in either case, we // cann't prevent allocation before correlation check. These are "can't solve" // scenarios. uchar * pMemory = *ppMemory; // // Setup if we are the outer dimension. All this is for multidimensional // array support. If we didn't have to worry about Beta2 stub // compatability we could this much better. // if ( ! pStubMsg->pArrayInfo ) { pStubMsg->pArrayInfo = &ArrayInfo; ArrayInfo.Dimension = 0; ArrayInfo.BufferConformanceMark = (unsigned long *)pStubMsg->BufferMark; ArrayInfo.BufferVarianceMark = 0; } pFormatSave = pFormat; pArrayInfo = pStubMsg->pArrayInfo; Dimension = pArrayInfo->Dimension; Alignment = pFormat[1]; pFormat += 2; // This is 0 if the array has conformance. Elements = *((ushort * &)pFormat)++; // // Check for conformance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { Elements = pArrayInfo->BufferConformanceMark[Dimension]; if ( F_CORRELATION_CHECK ) { NdrpCheckCorrelation( pStubMsg, Elements, pFormatSave, NDR_CHECK_CONFORMANCE ); } } pFormat += 4; CORRELATION_DESC_INCREMENT( pFormat ); // // Check for variance description. // if ( *((long UNALIGNED *)pFormat) != 0xffffffff ) { 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; pStubMsg->Buffer += VarianceSize; } Offset = pArrayInfo->BufferVarianceMark[Dimension * 2]; Count = pArrayInfo->BufferVarianceMark[(Dimension * 2) + 1]; if ( F_CORRELATION_CHECK ) { NdrpCheckCorrelation( pStubMsg, Offset, pFormatSave, NDR_CHECK_OFFSET ); NdrpCheckCorrelation( pStubMsg, Count, pFormatSave, NDR_CHECK_VARIANCE ); } } else { Offset = 0; Count = Elements; } pFormat += 4; CORRELATION_DESC_INCREMENT( pFormat ); if ( ! Count ) goto ComplexArrayUnmarshallEnd; ALIGN(pStubMsg->Buffer,Alignment); switch ( *pFormat ) { case FC_EMBEDDED_COMPLEX : pFormat += 2; pFormat += *((signed short *)pFormat); if ( *pFormat == FC_IP ) goto HandleInterfacePointer; pfnUnmarshall = pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)]; pArrayInfo->Dimension = Dimension + 1; pArrayInfo->MaxCountArray = pArrayInfo->BufferConformanceMark; MemoryElementSize = (ulong) ( NdrpMemoryIncrement( pStubMsg, pMemory, pFormat ) - pMemory ); pArrayInfo->MaxCountArray = 0; break; // note : midl doesn't seems to generate FC_OP in here, so we don't want // to change it for now. but there is potential bug here that pStubMsg->Memory // is not set and NdrPointerFree might fail if FC_OP points to a conformance // struct/array. case FC_RP : case FC_UP : case FC_FP : case FC_OP : pfnUnmarshall = (PUNMARSHALL_ROUTINE) NdrpPointerUnmarshall; // Need this in case we have a variant offset. MemoryElementSize = PTR_MEM_SIZE; break; case FC_IP : HandleInterfacePointer: UseBrokenInterfacePointer = !FixWireRepForDComVerGTE54( pStubMsg ); // Probably this code is not used, as for arrays of IPs the compiler // (as of ver. 5.1.+) generates array of embedded complex. // pfnUnmarshall = (PUNMARSHALL_ROUTINE)NdrpPointerUnmarshall; // Need this in case we have a variant offset. MemoryElementSize = PTR_MEM_SIZE; break; case FC_ENUM16 : pfnUnmarshall = 0; MemoryElementSize = sizeof(int); break; #if defined(__RPC_WIN64__) case FC_INT3264: case FC_UINT3264: pfnUnmarshall = 0; MemoryElementSize = sizeof(__int64); break; #endif case FC_RANGE: pfnUnmarshall = NdrRangeUnmarshall; MemoryElementSize = SIMPLE_TYPE_MEMSIZE( pFormat[1] ); break; default : NDR_ASSERT( IS_SIMPLE_TYPE(*pFormat), "NdrpComplexArrayUnmarshall : bad format char" ); Count = MultiplyWithOverflowCheck( Count, SIMPLE_TYPE_BUFSIZE(*pFormat) ); pMemory += MultiplyWithOverflowCheck( Offset , SIMPLE_TYPE_MEMSIZE(*pFormat) ); RpcpMemoryCopy( pMemory, pStubMsg->Buffer, (uint) Count ); pStubMsg->Buffer += Count; goto ComplexArrayUnmarshallEnd; } // // If there is variance then increment the memory pointer to the first // element actually being marshalled. // if ( Offset ) pMemory += MultiplyWithOverflowCheck( Offset , MemoryElementSize ); // // Check for an array of enum16 or int3264. // if ( ! pfnUnmarshall ) { #if defined(__RPC_WIN64__) if ( *pFormat != FC_ENUM16 ) { // int3264 if ( *pFormat == FC_INT3264 ) { for ( ; Count--; ) *((INT64 * &)pMemory)++ = *((long * &)pStubMsg->Buffer)++; } else { for ( ; Count--; ) *((UINT64 * &)pMemory)++ = *((ulong * &)pStubMsg->Buffer)++; } } else #endif { for ( ; Count--; ) { // Cast to ushort since we don't want to sign extend. *((int * &)pMemory)++ = (int) *((ushort * &)pStubMsg->Buffer)++; } } goto ComplexArrayUnmarshallEnd; } // !pfnUnmarshall // // Array of pointers. // if ( (pfnUnmarshall == (PUNMARSHALL_ROUTINE) NdrpPointerUnmarshall) ) { // If the broken interface pointer is used, // the pointer will not show up in the flat part // but in the pointee. if ( UseBrokenInterfacePointer ) { pStubMsg->pArrayInfo = 0; SET_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ); POINTER_BUFFER_SWAP_CONTEXT SwapContext( pStubMsg ); for ( ; Count--; ) { NdrpPointerUnmarshall( pStubMsg, (uchar **)pMemory, *((uchar **)pMemory), NULL, pFormat ); pMemory += PTR_MEM_SIZE; } RESET_BROKEN_INTERFACE_POINTER( pStubMsg->uFlags ); } else { long *pBufferPtr; ulong DoPtrWireInc; if ( *pFormat != FC_RP ) { pBufferPtr = (long*)pStubMsg->Buffer; pStubMsg->Buffer += MultiplyWithOverflowCheck( PTR_WIRE_SIZE , Count ); DoPtrWireInc = 1; } else { pBufferPtr = 0; DoPtrWireInc = 0; } pStubMsg->pArrayInfo = 0; POINTER_BUFFER_SWAP_CONTEXT SwapContext( pStubMsg ); for ( ; Count--; ) { NdrpPointerUnmarshall( pStubMsg, (uchar **)pMemory, *((uchar **)pMemory), pBufferPtr, pFormat ); pBufferPtr += DoPtrWireInc; pMemory += PTR_MEM_SIZE; } } goto ComplexArrayUnmarshallEnd; } // // Unmarshall the complex array elements. // if ( ! IS_ARRAY_OR_STRING(*pFormat) ) pStubMsg->pArrayInfo = 0; for ( ; Count--; ) { // Keep track of multidimensional array dimension. if ( IS_ARRAY_OR_STRING(*pFormat) ) pArrayInfo->Dimension = Dimension + 1; (*pfnUnmarshall)( pStubMsg, &pMemory, pFormat, FALSE ); // Increment the memory pointer by the element size. pMemory += MemoryElementSize; } ComplexArrayUnmarshallEnd: // pArrayInfo must be zero when not valid. pStubMsg->pArrayInfo = (Dimension == 0) ? 0 : pArrayInfo; } unsigned char * RPC_ENTRY NdrEncapsulatedUnionUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls an encapsulated array. Used for FC_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the union should be unmarshalled. pFormat - Union's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar * pBuffer; uchar * pUnion; uchar SwitchType; IGNORED(fMustAlloc); NO_CORRELATION; // // Since we can never use the buffer to hold a union we simply have // to check the current memory pointer to see if memory must be allocated. // // The memory size of an encapsulated union is the union size plus // the memory needed for the switch_is member (including any padding // for alignment). // if ( ! *ppMemory ) { uint Size; Size = *((ushort *)(pFormat + 2)) + HIGH_NIBBLE(pFormat[1]); *ppMemory = (uchar*)NdrAllocate( pStubMsg, Size ); // // We must zero out all of the new memory in case there are pointers // in any of the arms. // MIDL_memset( *ppMemory, 0, Size ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); SwitchType = LOW_NIBBLE(pFormat[1]); pBuffer = pStubMsg->Buffer; // // Unmarshall the switch_is field into memory. // NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, SwitchType ); // // The above call incremented the buffer pointer. Set it back to before // the switch is value in the buffer. // pStubMsg->Buffer = pBuffer; // Get a memory pointer to the union. pUnion = *ppMemory + HIGH_NIBBLE(pFormat[1]); NdrpUnionUnmarshall( pStubMsg, &pUnion, pFormat + 2, SwitchType, 0 ); // Encapsulated union return 0; } unsigned char * RPC_ENTRY NdrNonEncapsulatedUnionUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a non encapsulated array. Used for FC_NON_ENCAPSULATED_UNION. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the union should be unmarshalled. pFormat - Union's format string description. fMustAlloc - Ignored. Return : None. --*/ { uchar SwitchType; PFORMAT_STRING pFormatSave = pFormat; IGNORED(fMustAlloc); SwitchType = pFormat[1]; // // Get the memory size and arm description part of the format string // description. // pFormat += 6; CORRELATION_DESC_INCREMENT( pFormat ); pFormat += *((signed short *)pFormat); // // Since we can never use the buffer to hold a union we simply have // to check the current memory pointer to see if memory must be allocated. // if ( fMustAlloc || ! *ppMemory ) { uint Size; Size = *((ushort *)pFormat); *ppMemory = (uchar*)NdrAllocate( pStubMsg, Size ); // // We must zero out all of the new memory in case there are pointers // in any of the arms. // MIDL_memset( *ppMemory, 0, Size ); } // Insert full pointer to ref id translation if needed. if ( pStubMsg->FullPtrRefId ) FULL_POINTER_INSERT( pStubMsg, *ppMemory ); NdrpUnionUnmarshall( pStubMsg, ppMemory, pFormat, SwitchType, pFormatSave ); return 0; } void NdrpUnionUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar SwitchType, PFORMAT_STRING pFormatNonEncUnion ) /*++ Routine description : Private routine for unmarshalling a union. This routine is shared for both encapsulated and non-encapsulated unions and handles the actual unmarshalling of the proper union arm. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the union should be unmarshalled. pFormat - Union's format string description. SwitchType - Union's switch type. Return : None. --*/ { long SwitchIs; long Arms; uchar Alignment; // // Unmarshall the switch is. We have to do it inline here so that a // switch_is which is negative will be properly sign extended. // 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,1); SwitchIs = (long) *((short * &)pStubMsg->Buffer)++; break; case FC_USHORT : case FC_WCHAR : ALIGN(pStubMsg->Buffer,1); 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,3); SwitchIs = *((long * &)pStubMsg->Buffer)++; break; default : NDR_ASSERT(0,"NdrpUnionUnmarshall : Illegal union switch_type"); RpcRaiseException( RPC_S_INTERNAL_ERROR ); return; } if ( pFormatNonEncUnion ) { if ( F_CORRELATION_CHECK ) { // Unions offset in the switch_is correlation descriptor is relative // to the union position itself, not to the beginning of the struct. // This is set properly at the complex struct level. NdrpCheckCorrelation( pStubMsg, SwitchIs, pFormatNonEncUnion, NDR_CHECK_CONFORMANCE ); } } // Skip the memory size field. pFormat += 2; // // 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). Get your gun. // Alignment = (uchar) ( *((ushort *)pFormat) >> 12 ); ALIGN(pStubMsg->Buffer,Alignment); // // Number of arms is the lower 12 bits. Ok shoot me. // Arms = (long) ( *((ushort * &)pFormat)++ & 0x0fff); // // Search for union 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) ) { RpcRaiseException( RPC_S_INVALID_TAG ); } // // Return if the arm is empty. // if ( ! *((ushort *)pFormat) ) return; // check we aren't EOB after unmarshalling arm selector // not really necessary ( we shouldn't overwrite buffer in union) but we shouldn't // go further if it failes here. CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); // // 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) ) { // we could read pass the end of buffer, but won't corrupt memory // here. We always allocate memory for union in the server side. NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, pFormat[0] ); return; } pFormat += *((signed short *)pFormat); // // Determine the double memory pointer that we pass to the arm's // unmarshalling routine. // If the union arm we take is a pointer, we have to dereference the // current memory pointer since we're passed the pointer to a pointer // to the union (regardless of whether the actual parameter was a by-value // union or a pointer to a union). // // We also have to do a bunch of other special stuff to handle unions // embedded inside of strutures. // if ( IS_POINTER_TYPE(*pFormat) ) { ppMemory = (uchar **) *ppMemory; // // If we're embedded in a struct or array we have do some extra stuff. // if ( pStubMsg->PointerBufferMark ) { ALIGN(pStubMsg->Buffer,3); long *pPointerId = (long*)pStubMsg->Buffer; pStubMsg->Buffer += PTR_WIRE_SIZE; POINTER_BUFFER_SWAP_CONTEXT SwapContext( pStubMsg ); NdrpPointerUnmarshall( pStubMsg, ppMemory, *((uchar **)ppMemory), pPointerId, pFormat ); return; } } // // Union arm of a non-simple type. // (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormat)]) ( pStubMsg, ppMemory, pFormat, FALSE ); } unsigned char * RPC_ENTRY NdrByteCountPointerUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a pointer with the byte count attribute applied to it. Used for FC_BYTE_COUNT_POINTER. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Double pointer to where the byte count pointer should be unmarshalled. pFormat - Byte count pointer's format string description. fMustAlloc - Ignored. Return : None. --*/ { PFORMAT_STRING pFormatComplex; long ByteCount; long DataSize; ByteCount = (ulong) NdrpComputeConformance( pStubMsg, NULL, pFormat ); pFormatComplex = pFormat + 6; CORRELATION_DESC_INCREMENT( pFormatComplex ); pFormatComplex += *((signed short *)pFormatComplex); // // Determine incoming data size. // if ( pFormat[1] != FC_PAD ) { DataSize = SIMPLE_TYPE_MEMSIZE(pFormat[1]); } else { uchar * pBuffer; pBuffer = pStubMsg->Buffer; pStubMsg->MemorySize = 0; // // This will give us the allocate(all_nodes) size of the data. // DataSize = (*pfnMemSizeRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, pFormatComplex ); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer ); pStubMsg->Buffer = pBuffer; } if ( DataSize > ByteCount ) RpcRaiseException( RPC_X_BYTE_COUNT_TOO_SMALL ); // // Now make things look like we're handling an allocate all nodes. // NDR_ALLOC_ALL_NODES_CONTEXT AllocContext; AllocContext.AllocAllNodesMemory = *ppMemory; AllocContext.AllocAllNodesMemoryBegin = *ppMemory; AllocContext.AllocAllNodesMemoryEnd = *ppMemory + ByteCount; pStubMsg->pAllocAllNodesContext = &AllocContext; // // Now unmarshall. // if ( pFormat[1] != FC_PAD ) { ALIGN(pStubMsg->Buffer,SIMPLE_TYPE_ALIGNMENT(pFormat[1])); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + SIMPLE_TYPE_BUFSIZE(pFormat[1]) ); NdrSimpleTypeUnmarshall( pStubMsg, *ppMemory, pFormat[1] ); } else { (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pFormatComplex)]) ( pStubMsg, ppMemory, pFormatComplex, TRUE ); } pStubMsg->pAllocAllNodesContext = 0; return 0; } unsigned char * RPC_ENTRY NdrpXmitOrRepAsPtrUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a transmit as (or represent as) object given by pointers. (FC_TRANSMIT_AS_PTR or FC_REPRESENT_AS_PTR) See NdrXmitOrRepAsUnmarshall for more detals. Arguments : pStubMsg - a pointer to the stub message ppMemory - pointer to the presented type where to put data pFormat - format string description fMustAlloc - allocate flag Note. fMustAlloc is ignored as we always allocate outside of the buffer. --*/ { unsigned char * pTransmittedType; unsigned char * pPresentedType = *ppMemory; BOOL fMustFreeXmit = FALSE; const XMIT_ROUTINE_QUINTUPLE * pQuintuple = pStubMsg->StubDesc->aXmitQuintuple; unsigned short QIndex; unsigned long PresentedTypeSize; uchar * PointerBufferMarkSave; void * XmitTypePtr = 0; void * pMemoryListSave; (void) fMustAlloc; // Fetch the QuintupleIndex. QIndex = *(unsigned short *)(pFormat + 2); PresentedTypeSize = *(unsigned short *)(pFormat + 4); if ( ! pPresentedType ) { //Allocate a presented type object first. pPresentedType = (uchar*)NdrAllocate( pStubMsg, (uint) PresentedTypeSize ); MIDL_memset( pPresentedType, 0, (uint) PresentedTypeSize ); } // Allocate the transmitted object outside of the buffer // and unmarshall into it pFormat += 8; pFormat = pFormat + *(short *)pFormat; // Save the current state of the memory list so that the temporary // memory allocated for the transmitted type can be easily removed // from the list. This assumes that the memory allocated here // will not have any pointers to other blocks of memory. This is true // as long as full pointers are not used. The current compiler does // not support full pointers, so this in not a problem. pMemoryListSave = pStubMsg->pMemoryList; pTransmittedType = NULL; // asking the engine to allocate // only when ptr is ref: make it look like UP. if ( *pFormat == FC_RP ) pTransmittedType = (uchar *)& XmitTypePtr; { uchar *PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NDR_POINTER_QUEUE *pOldQueue = NULL; // Set the current queue to NULL so that all pointees will be // queued and unmarshalled together if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { (*pfnUnmarshallRoutines[ ROUTINE_INDEX( *pFormat )]) ( pStubMsg, & pTransmittedType, pFormat, TRUE ); } RpcFinally { pStubMsg->PointerBufferMark = PointerBufferMarkSave; if ( pStubMsg->pPointerQueueState ) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } // Translate from the transmitted type into the presented type. pStubMsg->pTransmitType = (uchar *)& pTransmittedType; pStubMsg->pPresentedType = pPresentedType; pQuintuple[ QIndex ].pfnTranslateFromXmit( pStubMsg ); *ppMemory = pStubMsg->pPresentedType; // Free the transmitted object (it was allocated by the engine) // and its pointees. The call through the table frees the pointees // plus it frees the object itself as it is a pointer. // Remove the memory that will be freed from the allocated memory // list by restoring the memory list pointer. // If an exception occures during one of these free routines, we // are in trouble anyway. pStubMsg->pMemoryList = pMemoryListSave; { uchar *PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NDR_POINTER_QUEUE *pOldQueue = NULL; // Set the current queue to NULL so that all pointees will be // queued and freed together if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { (*pfnFreeRoutines[ ROUTINE_INDEX( *pFormat )])( pStubMsg, pTransmittedType, pFormat ); } RpcFinally { pStubMsg->PointerBufferMark = PointerBufferMarkSave; if ( pStubMsg->pPointerQueueState ) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } return 0; } unsigned char * RPC_ENTRY NdrXmitOrRepAsUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a transmit as (or represent as)object. Means: allocate the transmitted object, unmarshall transmitted object, translate the transmitted into presented free the transmitted. See mrshl.c for the description of the FC layout. Arguments : pStubMsg - a pointer to the stub message ppMemory - pointer to the presented type where to put data pFormat - format string description fMustAlloc - allocate flag Note. fMustAlloc is ignored as we always allocate outside of the buffer. --*/ { unsigned char * pTransmittedType; unsigned char * pPresentedType = *ppMemory; __int64 SimpleTypeValueBuffer[2]; const XMIT_ROUTINE_QUINTUPLE * pQuintuple = pStubMsg->StubDesc->aXmitQuintuple; unsigned short QIndex; unsigned long PresentedTypeSize; uchar * PointerBufferMarkSave; BOOL fXmitByPtr = *pFormat == FC_TRANSMIT_AS_PTR || *pFormat == FC_REPRESENT_AS_PTR; (void) fMustAlloc; if ( fXmitByPtr ) { NdrpXmitOrRepAsPtrUnmarshall( pStubMsg, ppMemory, pFormat, fMustAlloc ); return 0; } // Fetch the QuintupleIndex. QIndex = *(unsigned short *)(pFormat + 2); PresentedTypeSize = *(unsigned short *)(pFormat + 4); if ( ! pPresentedType ) { //Allocate a presented type object first. pPresentedType = (uchar*)NdrAllocate( pStubMsg, (uint) PresentedTypeSize ); MIDL_memset( pPresentedType, 0, (uint) PresentedTypeSize ); } // Allocate the transmitted object outside of the buffer // and unmarshall into it pFormat += 8; pFormat = pFormat + *(short *)pFormat; if ( IS_SIMPLE_TYPE( *pFormat )) { pTransmittedType = (unsigned char *)SimpleTypeValueBuffer; NdrSimpleTypeUnmarshall( pStubMsg, pTransmittedType, *pFormat ); // Translate from the transmitted type into the presented type. pStubMsg->pTransmitType = pTransmittedType; pStubMsg->pPresentedType = pPresentedType; pQuintuple[ QIndex ].pfnTranslateFromXmit( pStubMsg ); *ppMemory = pStubMsg->pPresentedType; } else { // Save the current state of the memory list so that the temporary // memory allocated for the transmitted type can be easily removed // from the list. This assumes that the memory allocated here // will not have any linkes to other blocks of memory. This is true // as long as full pointers are not used. Fortunatly, full pointers // do not work correctly in the current code. void *pMemoryListSave = pStubMsg->pMemoryList; { uchar *PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NDR_POINTER_QUEUE *pOldQueue = NULL; // Set the current queue to NULL so that all pointees will be // queued and unmarshalled together if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } pTransmittedType = NULL; //asking the engine to allocate RpcTryFinally { (*pfnUnmarshallRoutines[ ROUTINE_INDEX( *pFormat )]) ( pStubMsg, & pTransmittedType, pFormat, TRUE ); } RpcFinally { pStubMsg->PointerBufferMark = PointerBufferMarkSave; if ( pStubMsg->pPointerQueueState ) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } // Translate from the transmitted type into the presented type. pStubMsg->pTransmitType = pTransmittedType; pStubMsg->pPresentedType = pPresentedType; pQuintuple[ QIndex ].pfnTranslateFromXmit( pStubMsg ); *ppMemory = pStubMsg->pPresentedType; // Free the transmitted object (it was allocated by the engine) // and its pointees. The call through the table frees the pointees // only (plus it'd free the object itself if it were a pointer). // As the transmitted type is not a pointer here, we need to free it // explicitely later. // Remove the memory that will be freed from the allocated memory // list by restoring the memory list pointer. // If an exception occures during one of these free routines, we // are in trouble anyway. pStubMsg->pMemoryList = pMemoryListSave; { uchar *PointerBufferMarkSave = pStubMsg->PointerBufferMark; pStubMsg->PointerBufferMark = 0; NDR_POINTER_QUEUE *pOldQueue = NULL; // Set the current queue to NULL so that all pointees will be // queued and freed together if ( pStubMsg->pPointerQueueState ) { pOldQueue = pStubMsg->pPointerQueueState->GetActiveQueue(); pStubMsg->pPointerQueueState->SetActiveQueue(NULL); } RpcTryFinally { (*pfnFreeRoutines[ ROUTINE_INDEX( *pFormat )])( pStubMsg, pTransmittedType, pFormat ); } RpcFinally { pStubMsg->PointerBufferMark = PointerBufferMarkSave; if ( pStubMsg->pPointerQueueState ) { pStubMsg->pPointerQueueState->SetActiveQueue( pOldQueue ); } } RpcEndFinally } // The buffer reusage check. if ( pTransmittedType < pStubMsg->BufferStart || pTransmittedType > pStubMsg->BufferEnd ) (*pStubMsg->pfnFree)( pTransmittedType ); } return 0; } void NdrpUserMarshalUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar * pMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Unmarshals a user_marshal object. The layout is described in marshalling. Arguments : pStubMsg - Pointer to the stub message. pMemory - Pointer to the memory where the object should be unmarshalled to. pFormat - Object's format string description. Return : None. --*/ { unsigned char *pUserBuffer = pStubMsg->Buffer; unsigned char *pUserBufferSaved = pUserBuffer; USER_MARSHAL_CB UserMarshalCB; NdrpInitUserMarshalCB( pStubMsg, pFormat, USER_MARSHAL_CB_UNMARSHALL, & UserMarshalCB ); unsigned short QIndex = *(unsigned short *)(pFormat + 2); const USER_MARSHAL_ROUTINE_QUADRUPLE *pQuadruple = pStubMsg->StubDesc->aUserMarshalQuadruple; if ((pUserBufferSaved < (uchar *) pStubMsg->RpcMsg->Buffer) || ((unsigned long) (pUserBufferSaved - (uchar *) pStubMsg->RpcMsg->Buffer) > pStubMsg->RpcMsg->BufferLength)) { RpcRaiseException( RPC_X_INVALID_BUFFER ); } pUserBuffer = pQuadruple[ QIndex ].pfnUnmarshall( (ulong*) &UserMarshalCB, pUserBuffer, pMemory ); if ((pUserBufferSaved > pUserBuffer) || ((unsigned long) (pUserBuffer - (uchar *) pStubMsg->RpcMsg->Buffer) > pStubMsg->RpcMsg->BufferLength )) { RpcRaiseException( RPC_X_INVALID_BUFFER ); } pStubMsg->Buffer = pUserBuffer; return; } void NDR_USR_MRSHL_UNMRSHL_POINTER_QUEUE_ELEMENT::Dispatch(MIDL_STUB_MESSAGE *pStubMsg) { NdrpUserMarshalUnmarshall( pStubMsg, pMemory, pFormat ); } #if defined(DBG) void NDR_USR_MRSHL_UNMRSHL_POINTER_QUEUE_ELEMENT::Print() { DbgPrint("NDR_USR_MRSHL_BUFSIZE_POINTER_QUEUE_ELEMENT\n"); DbgPrint("pMemory: %p\n", pMemory ); DbgPrint("pFormat: %p\n", pFormat ); } #endif unsigned char * NdrUserMarshalUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) { // Align for the object or a pointer to it. unsigned long PointerMarker = 0; ALIGN( pStubMsg->Buffer, LOW_NIBBLE(pFormat[1]) ); // Take care of the pointer, if any. if ( (pFormat[1] & USER_MARSHAL_UNIQUE) || ((pFormat[1] & USER_MARSHAL_REF) && pStubMsg->PointerBufferMark) ) { PointerMarker = *((unsigned long * &)pStubMsg->Buffer)++; } // We always call user's routine to unmarshall the user object. // However, the top level object is allocated by the engine. // Thus, the behavior is exactly the same as for represent_as(), // with regard to the top level presented type. if ( *ppMemory == NULL ) { // Allocate a presented type object first. uint MemSize = *(ushort *)(pFormat + 4); *ppMemory = (uchar *) NdrAllocate( pStubMsg, MemSize ); MIDL_memset( *ppMemory, 0, MemSize ); } if ( pFormat[1] & USER_MARSHAL_POINTER ) { if ((pFormat[1] & USER_MARSHAL_UNIQUE) && !PointerMarker ) return 0; if ( !pStubMsg->pPointerQueueState || !pStubMsg->pPointerQueueState->GetActiveQueue()) { POINTER_BUFFER_SWAP_CONTEXT NewContext(pStubMsg); NdrpUserMarshalUnmarshall( pStubMsg, *ppMemory, pFormat ); } else { NDR_USR_MRSHL_UNMRSHL_POINTER_QUEUE_ELEMENT*pElement = new(pStubMsg->pPointerQueueState) NDR_USR_MRSHL_UNMRSHL_POINTER_QUEUE_ELEMENT(*ppMemory, pFormat ); pStubMsg->pPointerQueueState->GetActiveQueue()->Enque( pElement ); } return 0; } NdrpUserMarshalUnmarshall( pStubMsg, *ppMemory, pFormat ); return 0; } void NdrpInterfacePointerUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat ) /*++ Routine Description : Unmarshalls an interface pointer. Arguments : pStubMsg - Pointer to the stub message. ppMemory - Pointer to the interface pointer being unmarshalled. pFormat - Interface pointer's format string description. Return : None. Notes : There are two data representation formats for a marshalled interface pointer. The NDR engine examines the format string to determine the appropriate data format. The format string contains FC_IP followed by either FC_CONSTANT_IID or FC_PAD. Here is the data representation for the FC_CONSTANT_IID case. typedef struct { unsigned long size; [size_is(size)] byte data[]; }MarshalledInterface; Here is the data representation for the FC_PAD case. This format is used when [iid_is] is specified in the IDL file. typedef struct { uuid_t iid; unsigned long size; [size_is(size)] byte data[]; }MarshalledInterfaceWithIid; --*/ { HRESULT hr; unsigned long MaxCount, Size; IStream * pStream; ALIGN(pStubMsg->Buffer,0x3); // Unmarshal the conformant size and the count field. MaxCount = *((unsigned long * &) pStubMsg->Buffer)++; Size = *((unsigned long * &) pStubMsg->Buffer)++; //Check the array bounds if ( Size != MaxCount ) RpcRaiseException( RPC_X_BAD_STUB_DATA ); if( MaxCount > 0) { CHECK_EOB_WITH_WRAP_RAISE_BSD( pStubMsg->Buffer, MaxCount ); if ( F_CORRELATION_CHECK ) { IID *piid, *piidValue; BOOL fDoCheck = FALSE; // Get a pointer to the IID hidden in the interface pointer // representation in the buffer with Rick's IRpcHelper. // NdrpGetIIDFromBuffer( pStubMsg, & piidValue ); // // Get an IID pointer to compare. // if ( pFormat[1] == FC_CONSTANT_IID ) { // // The IID may not be aligned properly in the format string, // so we copy it to a local variable. // piid = (IID*) (pFormat + 2); fDoCheck = TRUE; } else { ULONG_PTR MaxCountSave = pStubMsg->MaxCount; uchar * pMemorySave = pStubMsg->Memory; pStubMsg->MaxCount = 0; pStubMsg->Memory = pStubMsg->pCorrMemory; piid = (IID *) NdrpComputeIIDPointer( pStubMsg, *ppMemory, // should not be used pFormat ); if (piid != 0) { PNDR_FCDEF_CORRELATION pFormatCorr = (PNDR_FCDEF_CORRELATION)(pFormat+2); if ( pFormatCorr->CorrFlags.Early ) fDoCheck = TRUE; else { // save ptr as a value to check NdrpAddCorrelationData( pStubMsg, pStubMsg->pCorrMemory, pFormat + 2, (LONG_PTR) piid, // "value" NDR_CHECK_CONFORMANCE ); } } // else could not check for -Os etc. pStubMsg->MaxCount = MaxCountSave; pStubMsg->Memory = pMemorySave; } if ( fDoCheck && 0 != memcmp( piidValue, piid, sizeof(IID) ) ) RpcRaiseException( RPC_X_BAD_STUB_DATA ); } pStream = (*NdrpCreateStreamOnMemory)(pStubMsg->Buffer, MaxCount); if(pStream == 0) RpcRaiseException(RPC_S_OUT_OF_MEMORY); hr = (*pfnCoUnmarshalInterface)(pStream, IID_NULL, (void**)ppMemory); pStream->Release(); pStream = 0; if(FAILED(hr)) RpcRaiseException(hr); } //Advance the stub message pointer. pStubMsg->Buffer += MaxCount; } unsigned char * RPC_ENTRY NdrInterfacePointerUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar /*fMustAlloc*/ ) { // This is only called for toplevel interface pointers // in Os mode stubs. IUnknown ** ppunk = (IUnknown **)ppMemory; // On the client side, release the [in,out] interface pointer. if ((pStubMsg->IsClient == TRUE) && (*ppunk != 0)) (*ppunk)->Release(); *ppunk = 0; // // We always have to pickup the pointer itself from the wire // as it behaves like a unique pointer. ALIGN(pStubMsg->Buffer,0x3); long PtrValue = *((long * &)pStubMsg->Buffer)++; // If the pointer is null, we are done. if ( 0 == PtrValue ) return 0; NdrpInterfacePointerUnmarshall( pStubMsg, ppMemory, pFormat ); return 0; } void RPC_ENTRY NdrClientContextUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, NDR_CCONTEXT * pContextHandle, RPC_BINDING_HANDLE BindHandle ) /*++ Routine Description : Unmarshalls a context handle on the client side. Arguments : pStubMsg - Pointer to stub message. pContextHandle - Pointer to context handle to unmarshall. BindHandle - The handle value used by the client for binding. Return : None. --*/ { // Note, this is a routine called directly from -Os stubs. // The routine called by interpreter is called NdrUnmarshallHandle // and can be found in hndl.c ALIGN(pStubMsg->Buffer,3); CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + CONTEXT_HANDLE_WIRE_SIZE ); // All 20 bytes of the buffer are touched so a check is not needed here. NDRCContextUnmarshall( pContextHandle, BindHandle, pStubMsg->Buffer, pStubMsg->RpcMsg->DataRepresentation ); pStubMsg->Buffer += CONTEXT_HANDLE_WIRE_SIZE; } NDR_SCONTEXT RPC_ENTRY NdrServerContextUnmarshall( PMIDL_STUB_MESSAGE pStubMsg ) /*++ Routine Description : Unmarshalls a context handle on the server side. Arguments : pStubMsg - Pointer to stub message. Return : The unmarshalled context handle. --*/ { // Note, this is a routine called directly from -Os stubs. // The routine called by interpreter is called NdrUnmarshallHandle // and can be found in hndl.c NDR_SCONTEXT Context; ALIGN(pStubMsg->Buffer,3); // we might corrupt the memory during the byte swap CHECK_EOB_RAISE_BSD( pStubMsg->Buffer + CONTEXT_HANDLE_WIRE_SIZE ); // All 20 bytes of the buffer are touched so a check is not needed here. Context = NDRSContextUnmarshall2(pStubMsg->RpcMsg->Handle, pStubMsg->Buffer, pStubMsg->RpcMsg->DataRepresentation, RPC_CONTEXT_HANDLE_DEFAULT_GUARD, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS ); if ( ! Context ) RpcRaiseException( RPC_X_SS_CONTEXT_MISMATCH ); pStubMsg->Buffer += CONTEXT_HANDLE_WIRE_SIZE; return Context; } NDR_SCONTEXT RPC_ENTRY NdrContextHandleInitialize ( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /* This routine is to initialize a context handle with a new NT5 flavor. It is used in conjunction with NdrContextHandleUnmarshal. */ { NDR_SCONTEXT SContext; void * pGuard = RPC_CONTEXT_HANDLE_DEFAULT_GUARD; DWORD Flags = RPC_CONTEXT_HANDLE_DEFAULT_FLAGS; // NT5 beta2 features: strict context handle, serialize and noserialize. if ( pFormat[1] & NDR_STRICT_CONTEXT_HANDLE ) { // The guard is defined as the interface ID. // If you change it, modify hndlsvr.cxx in the same way. pGuard = pStubMsg->StubDesc->RpcInterfaceInformation; pGuard = & ((PRPC_SERVER_INTERFACE)pGuard)->InterfaceId; } if ( pFormat[1] & NDR_CONTEXT_HANDLE_NOSERIALIZE ) { Flags = RPC_CONTEXT_HANDLE_DONT_SERIALIZE; } else if ( pFormat[1] & NDR_CONTEXT_HANDLE_SERIALIZE ) { Flags = RPC_CONTEXT_HANDLE_SERIALIZE; } SContext = NDRSContextUnmarshall2( pStubMsg->RpcMsg->Handle, (void *)0, // buffer pStubMsg->RpcMsg->DataRepresentation, pGuard, Flags ); return SContext; } NDR_SCONTEXT RPC_ENTRY NdrServerContextNewUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /* This routine to unmarshal a context handle with a new NT5 flavor. For the old style handles, we call an optimized routine NdrServerContextUnmarshall below. Interpreter calls NdrUnmarshallHandle from hndl.c ppMemory - note, this is not a pointer to user's context handle but a pointer to NDR_SCONTEXT pointer to the runtime internal object. User's handle is a field of that object. */ { NDR_SCONTEXT SContext; void * pGuard = RPC_CONTEXT_HANDLE_DEFAULT_GUARD; DWORD Flags = RPC_CONTEXT_HANDLE_DEFAULT_FLAGS; // Anti-attack defense for servers, NT5 beta3 feature. if ( pFormat[1] & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL ) { // Check the incoming context handle on the server. // Context handle wire layout: ulong with version (always 0), then a uuid. // if ( !pStubMsg->IsClient && 0 == memcmp( pStubMsg->Buffer + 4, &GUID_NULL, sizeof(GUID) ) ) RpcRaiseException( RPC_X_BAD_STUB_DATA ); } // NT5 beta2 features: strict context handle, serialize and noserialize. if ( pFormat[1] & NDR_STRICT_CONTEXT_HANDLE ) { pGuard = pStubMsg->StubDesc->RpcInterfaceInformation; pGuard = & ((PRPC_SERVER_INTERFACE)pGuard)->InterfaceId; } if ( pFormat[1] & NDR_CONTEXT_HANDLE_NOSERIALIZE ) { Flags = RPC_CONTEXT_HANDLE_DONT_SERIALIZE; } else if ( pFormat[1] & NDR_CONTEXT_HANDLE_SERIALIZE ) { Flags = RPC_CONTEXT_HANDLE_SERIALIZE; } ALIGN( pStubMsg->Buffer, 0x3 ); // All 20 bytes of the buffer are touched so a check is not needed here. SContext = NDRSContextUnmarshall2( pStubMsg->RpcMsg->Handle, pStubMsg->Buffer, pStubMsg->RpcMsg->DataRepresentation, pGuard, Flags ); if ( ! SContext ) RpcRaiseException( RPC_X_SS_CONTEXT_MISMATCH ); pStubMsg->Buffer += CONTEXT_HANDLE_WIRE_SIZE; return SContext; } #ifdef _CS_CHAR_ unsigned char * RPC_ENTRY NdrCsTagUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a cs tag. Arguments : pStubMsg - Pointer to stub message. ppMemory - Double pointer to where to unmarshall to pFormat - The format string entry fMustAlloc - TRUE if we can't reuse the buffer (not relevant in this case) --*/ { NDR_CS_TAG_FORMAT *pTagFormat = (NDR_CS_TAG_FORMAT *) pFormat; ulong Codeset = NdrpGetSetCSTagUnmarshall( pStubMsg, (NDR_CS_TAG_FORMAT *) pFormat); // If there is a tag routine, then this parameter is not on the stack if ( NDR_INVALID_TAG_ROUTINE_INDEX == pTagFormat->TagRoutineIndex ) ** (ulong **) ppMemory = Codeset; pStubMsg->Buffer += sizeof(ulong); return 0; } unsigned char * RPC_ENTRY NdrCsArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, uchar ** ppMemory, PFORMAT_STRING pFormat, uchar fMustAlloc ) /*++ Routine Description : Unmarshalls a international character (cs) array tag. Arguments : pStubMsg - Pointer to stub message. ppMemory - Double pointer to where to unmarshall to pFormat - The format string entry fMustAlloc - TRUE if we can't reuse the buffer --*/ { ulong LocalCodeset; error_status_t status; uchar *ConvertedData; uchar *UnconvertedData; ulong ArraySize; ulong WireLength; uchar *OldBuffer; uchar fMustAllocOriginal; BOOL IsClient; NDR_CS_ARRAY_FORMAT *pCSFormat; NDR_CS_SIZE_CONVERT_ROUTINES *CSRoutines; CS_TYPE_LOCAL_SIZE_ROUTINE LocalSizeRoutine; CS_TYPE_FROM_NETCS_ROUTINE FromNetCSRoutine; IDL_CS_CONVERT ConversionType; pCSFormat = (NDR_CS_ARRAY_FORMAT *) pFormat; NDR_ASSERT( NULL != pStubMsg->pCSInfo, "cs 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; FromNetCSRoutine = CSRoutines[ pCSFormat->CSRoutineIndex].pfnFromNetCs; pFormat += pCSFormat->DescriptionOffset; // REVIEW: A lot of this code can be eleminted by calling memsize on the // cs_char array instead of the underlying one. // Get the size of the data on the wire OldBuffer = pStubMsg->Buffer; WireLength = PtrToUlong( NdrpMemoryIncrement( pStubMsg, 0, pFormat ) ); // Figure out whether we need to convert and how much we need to allocate // if we do LocalSizeRoutine( pStubMsg->RpcMsg->Handle, pStubMsg->pCSInfo->WireCodeset, WireLength, &ConversionType, &ArraySize, &status); if ( RPC_S_OK != status ) RpcRaiseException( status ); // If we need to convert we just want the unmarshalling routine to give us // back a pointer and not do any allocations. We'll do the allocation // later if need be. IsClient = pStubMsg->IsClient; if ( IDL_CS_NO_CONVERT != ConversionType ) { fMustAllocOriginal = fMustAlloc; OldBuffer = *ppMemory; *ppMemory = NULL; fMustAlloc = FALSE; // Slimy hack to enable buffer reuse on the client side pStubMsg->IsClient = FALSE; } // Unmarshall the base array pfnUnmarshallRoutines[ ROUTINE_INDEX( *pFormat ) ] ( pStubMsg, ppMemory, pFormat, fMustAlloc ); pStubMsg->IsClient = IsClient; // If we don't need to convert, we're done if ( IDL_CS_NO_CONVERT == ConversionType ) return 0; // Make sure we've got a buffer to convert into NDR_ASSERT( NULL != *ppMemory, "Invalid memory pointer" ); UnconvertedData = *ppMemory; *ppMemory = OldBuffer; if ( fMustAllocOriginal || NULL == *ppMemory ) { *ppMemory = (uchar *) NdrAllocate( pStubMsg, ArraySize * pCSFormat->UserTypeSize ); } else if ( pStubMsg->IsClient ) { // Make sure we don't overflow the client's buffer long ClientArraySize; long ClientArrayLength; long ClientWireSize; NdrpGetArraySizeLength( pStubMsg, *ppMemory, pFormat, pCSFormat->UserTypeSize, &ClientArraySize, &ClientArrayLength, &ClientWireSize ); ArraySize = min( ArraySize, (ulong)ClientArraySize ); } // Reset the conformance variable to the new array size if ( NdrpArrayMarshallFlags[ *pFormat - FC_CARRAY ] & MARSHALL_CONFORMANCE ) { uchar *pOldCorrMemory = pStubMsg->pCorrMemory; if ( !pStubMsg->pCorrMemory ) pStubMsg->pCorrMemory = pStubMsg->StackTop; NdrpCheckCorrelation( pStubMsg, ArraySize, pFormat, NDR_CHECK_CONFORMANCE | NDR_RESET_VALUE ); pStubMsg->pCorrMemory = pOldCorrMemory; } // Do the conversion FromNetCSRoutine( pStubMsg->RpcMsg->Handle, pStubMsg->pCSInfo->WireCodeset, UnconvertedData, WireLength, ArraySize, *ppMemory, &ArraySize, // Actually it returns the length not the size &status); if ( RPC_S_OK != status ) RpcRaiseException( status ); // Reset the variance variable to the new array length if ( NdrpArrayMarshallFlags[ *pFormat - FC_CARRAY ] & MARSHALL_VARIANCE ) { NdrpCheckCorrelation( pStubMsg, ArraySize, pFormat, NDR_CHECK_VARIANCE | NDR_RESET_VALUE ); } return 0; } #endif // _CS_CHAR_ void NdrPartialIgnoreServerUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, void ** ppMemory ) { ALIGN( pStubMsg->Buffer, 0x3 ); *ppMemory = UlongToPtr( *(ulong*)pStubMsg->Buffer ); pStubMsg->Buffer += PTR_WIRE_SIZE; }