mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5266 lines
151 KiB
5266 lines
151 KiB
/**********************************************************************
|
|
|
|
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<uchar*> MemorySave( pStubMsg->Memory, Memory );
|
|
SAVE_CONTEXT<uchar> uFlagsSave( pStubMsg->uFlags, uFlags );
|
|
NDR_ASSERT( !pStubMsg->PointerBufferMark, "PointerBufferMark is not 0\n");
|
|
int fInDontFreeSave = pStubMsg->fInDontFree;
|
|
pStubMsg->fInDontFree = fInDontFree;
|
|
SAVE_CONTEXT<uchar*> pCorrMemorySave(pStubMsg->pCorrMemory, pCorrMemory );
|
|
SAVE_CONTEXT<NDR_ALLOC_ALL_NODES_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 <unsigned short>
|
|
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;
|
|
}
|
|
|