From 9116d73c63256e7318e0a74bb80f7ecdf0c7f2f5 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Sun, 10 Aug 2008 11:14:07 +0100 Subject: [PATCH] rpcrt4: Factorise conformant array NDR functions and use them to fix the wire-representation of complex structures with conformant arrays. Factorise each conformant array function into the part that deals with reading, writing or sizing the conformance and another part that deals with reading, writing or sizing the variance and the element data. This allows complex structures to use the right wire format where the conformance appears before the structure data starts. --- dlls/rpcrt4/ndr_marshall.c | 425 ++++++++++++++++++++++++++++++------- 1 file changed, 346 insertions(+), 79 deletions(-) diff --git a/dlls/rpcrt4/ndr_marshall.c b/dlls/rpcrt4/ndr_marshall.c index 836410b5816..13d3b9f175d 100644 --- a/dlls/rpcrt4/ndr_marshall.c +++ b/dlls/rpcrt4/ndr_marshall.c @@ -626,6 +626,19 @@ finish_conf: return pFormat+4; } +static inline PFORMAT_STRING SkipConformance(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + if (IsConformanceOrVariancePresent(pFormat)) + { + if (pStubMsg->fHasNewCorrDesc) + pFormat += 6; + else + pFormat += 4; + } + return pFormat; +} + /* multiply two numbers together, raising an RPC_S_INVALID_BOUND exception if * the result overflows 32-bits */ static inline ULONG safe_multiply(ULONG a, ULONG b) @@ -2113,6 +2126,213 @@ void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg, EmbeddedPointerFree(pStubMsg, pMemory, pFormat+4); } +/* Array helpers */ + +static inline void array_compute_and_size_conformance( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + switch (fc) + { + case RPC_FC_CARRAY: + ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + SizeConformance(pStubMsg); + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline void array_buffer_size( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size; + DWORD esize; + unsigned char alignment; + + switch (fc) + { + case RPC_FC_CARRAY: + esize = *(const WORD*)(pFormat+2); + alignment = pFormat[1] + 1; + + pFormat = SkipConformance(pStubMsg, pFormat + 4); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + size = safe_multiply(esize, pStubMsg->MaxCount); + /* conformance value plus array */ + safe_buffer_length_increment(pStubMsg, size); + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline void array_compute_and_write_conformance( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + switch (fc) + { + case RPC_FC_CARRAY: + ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + WriteConformance(pStubMsg); + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline void array_write_variance_and_marshall( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size; + DWORD esize; + unsigned char alignment; + + switch (fc) + { + case RPC_FC_CARRAY: + esize = *(const WORD*)(pFormat+2); + alignment = pFormat[1] + 1; + + pFormat = SkipConformance(pStubMsg, pFormat + 4); + + ALIGN_POINTER_CLEAR(pStubMsg->Buffer, alignment); + + size = safe_multiply(esize, pStubMsg->MaxCount); + pStubMsg->BufferMark = pStubMsg->Buffer; + safe_copy_to_buffer(pStubMsg, pMemory, size); + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline ULONG array_read_conformance( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) +{ + DWORD esize; + + switch (fc) + { + case RPC_FC_CARRAY: + esize = *(const WORD*)(pFormat+2); + pFormat = ReadConformance(pStubMsg, pFormat+4); + return safe_multiply(esize, pStubMsg->MaxCount); + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline void array_read_variance_and_unmarshall( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory, + PFORMAT_STRING pFormat, unsigned char fMustAlloc, + unsigned char fUseBufferMemoryServer) +{ + ULONG bufsize, memsize; + DWORD esize; + unsigned char alignment; + unsigned char *saved_buffer; + + switch (fc) + { + case RPC_FC_CARRAY: + esize = *(const WORD*)(pFormat+2); + alignment = pFormat[1] + 1; + + bufsize = memsize = safe_multiply(esize, pStubMsg->MaxCount); + + pFormat = SkipConformance(pStubMsg, pFormat + 4); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + if (fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, memsize); + else + { + if (fUseBufferMemoryServer && !pStubMsg->IsClient && !*ppMemory) + /* for servers, we just point straight into the RPC buffer */ + *ppMemory = pStubMsg->Buffer; + } + + saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer; + safe_buffer_increment(pStubMsg, bufsize); + EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat, fMustAlloc); + + TRACE("copying %p to %p\n", saved_buffer, *ppMemory); + if (*ppMemory != saved_buffer) + memcpy(*ppMemory, saved_buffer, bufsize); + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline void array_memory_size( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) +{ + DWORD size; + DWORD esize; + unsigned char alignment; + + switch (fc) + { + case RPC_FC_CARRAY: + esize = *(const WORD*)(pFormat+2); + alignment = pFormat[1] + 1; + + pFormat = SkipConformance(pStubMsg, pFormat + 4); + + size = safe_multiply(esize, pStubMsg->MaxCount); + pStubMsg->MemorySize += size; + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + pStubMsg->BufferMark = pStubMsg->Buffer; + safe_buffer_increment(pStubMsg, size); + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline void array_free( + unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + switch (fc) + { + case RPC_FC_CARRAY: + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); + break; + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + /* No embedded pointers so nothing to do */ + break; + default: + ERR("unknown array format 0x%x\n", fc); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +/* Complex types */ #include "pshpack1.h" typedef struct @@ -2823,6 +3043,9 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pointer_desc = NULL; unsigned char *OldMemory = pStubMsg->Memory; int pointer_buffer_mark_set = 0; + ULONG count = 0; + ULONG max_count = 0; + ULONG offset = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2858,10 +3081,27 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->Memory = pMemory; + if (conf_array) + { + unsigned long struct_size = ComplexStructSize(pStubMsg, pFormat); + array_compute_and_write_conformance(conf_array[0], pStubMsg, + pMemory + struct_size, conf_array); + /* these could be changed in ComplexMarshall so save them for later */ + max_count = pStubMsg->MaxCount; + count = pStubMsg->ActualCount; + offset = pStubMsg->Offset; + } + pMemory = ComplexMarshall(pStubMsg, pMemory, pFormat, pointer_desc); if (conf_array) - NdrConformantArrayMarshall(pStubMsg, pMemory, conf_array); + { + pStubMsg->MaxCount = max_count; + pStubMsg->ActualCount = count; + pStubMsg->Offset = offset; + array_write_variance_and_marshall(conf_array[0], pStubMsg, pMemory, + conf_array); + } pStubMsg->Memory = OldMemory; @@ -2889,6 +3129,10 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pointer_desc = NULL; unsigned char *pMemory; int pointer_buffer_mark_set = 0; + ULONG count = 0; + ULONG max_count = 0; + ULONG offset = 0; + ULONG array_size = 0; TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -2915,19 +3159,39 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); - if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, size); - pFormat += 4; if (*(const SHORT*)pFormat) conf_array = pFormat + *(const SHORT*)pFormat; pFormat += 2; if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; pFormat += 2; + if (conf_array) + { + array_size = array_read_conformance(conf_array[0], pStubMsg, conf_array); + size += array_size; + + /* these could be changed in ComplexMarshall so save them for later */ + max_count = pStubMsg->MaxCount; + count = pStubMsg->ActualCount; + offset = pStubMsg->Offset; + } + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, size); + pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc, fMustAlloc); if (conf_array) - NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); + { + pStubMsg->MaxCount = max_count; + pStubMsg->ActualCount = count; + pStubMsg->Offset = offset; + if (fMustAlloc) + memset(pMemory, 0, array_size); + array_read_variance_and_unmarshall(conf_array[0], pStubMsg, &pMemory, + conf_array, FALSE, + FALSE /* fUseBufferMemoryServer */); + } if (pointer_buffer_mark_set) { @@ -2949,6 +3213,9 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pointer_desc = NULL; unsigned char *OldMemory = pStubMsg->Memory; int pointer_length_set = 0; + ULONG count = 0; + ULONG max_count = 0; + ULONG offset = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2982,10 +3249,27 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->Memory = pMemory; + if (conf_array) + { + unsigned long struct_size = ComplexStructSize(pStubMsg, pFormat); + array_compute_and_size_conformance(conf_array[0], pStubMsg, pMemory + struct_size, + conf_array); + + /* these could be changed in ComplexMarshall so save them for later */ + max_count = pStubMsg->MaxCount; + count = pStubMsg->ActualCount; + offset = pStubMsg->Offset; + } + pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, pointer_desc); if (conf_array) - NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array); + { + pStubMsg->MaxCount = max_count; + pStubMsg->ActualCount = count; + pStubMsg->Offset = offset; + array_buffer_size(conf_array[0], pStubMsg, pMemory, conf_array); + } pStubMsg->Memory = OldMemory; @@ -3006,6 +3290,9 @@ ULONG WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, unsigned size = *(const WORD*)(pFormat+2); PFORMAT_STRING conf_array = NULL; PFORMAT_STRING pointer_desc = NULL; + ULONG count = 0; + ULONG max_count = 0; + ULONG offset = 0; TRACE("(%p,%p)\n", pStubMsg, pFormat); @@ -3017,10 +3304,26 @@ ULONG WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; pFormat += 2; + if (conf_array) + { + array_read_conformance(conf_array[0], pStubMsg, conf_array); + + /* these could be changed in ComplexStructMemorySize so save them for + * later */ + max_count = pStubMsg->MaxCount; + count = pStubMsg->ActualCount; + offset = pStubMsg->Offset; + } + ComplexStructMemorySize(pStubMsg, pFormat, pointer_desc); if (conf_array) - NdrConformantArrayMemorySize(pStubMsg, conf_array); + { + pStubMsg->MaxCount = max_count; + pStubMsg->ActualCount = count; + pStubMsg->Offset = offset; + array_memory_size(conf_array[0], pStubMsg, conf_array); + } return size; } @@ -3049,7 +3352,7 @@ void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg, pMemory = ComplexFree(pStubMsg, pMemory, pFormat, pointer_desc); if (conf_array) - NdrConformantArrayFree(pStubMsg, pMemory, conf_array); + array_free(conf_array[0], pStubMsg, pMemory, conf_array); pStubMsg->Memory = OldMemory; } @@ -3061,23 +3364,16 @@ unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - DWORD size = 0, esize = *(const WORD*)(pFormat+2); - unsigned char alignment = pFormat[1] + 1; - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + if (pFormat[0] != RPC_FC_CARRAY) + { + ERR("invalid format = 0x%x\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - - WriteConformance(pStubMsg); - - ALIGN_POINTER_CLEAR(pStubMsg->Buffer, alignment); - - size = safe_multiply(esize, pStubMsg->MaxCount); - pStubMsg->BufferMark = pStubMsg->Buffer; - safe_copy_to_buffer(pStubMsg, pMemory, size); - - EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + array_compute_and_write_conformance(RPC_FC_CARRAY, pStubMsg, pMemory, + pFormat); + array_write_variance_and_marshall(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat); return NULL; } @@ -3090,34 +3386,17 @@ unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - DWORD size, esize = *(const WORD*)(pFormat+2); - unsigned char alignment = pFormat[1] + 1; - unsigned char *saved_buffer; - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - - pFormat = ReadConformance(pStubMsg, pFormat+4); - - size = safe_multiply(esize, pStubMsg->MaxCount); - ALIGN_POINTER(pStubMsg->Buffer, alignment); - - if (fMustAlloc) - *ppMemory = NdrAllocate(pStubMsg, size); - else + if (pFormat[0] != RPC_FC_CARRAY) { - if (!pStubMsg->IsClient && !*ppMemory) - /* for servers, we just point straight into the RPC buffer */ - *ppMemory = pStubMsg->Buffer; + ERR("invalid format = 0x%x\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); } - saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer; - safe_buffer_increment(pStubMsg, size); - EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat, fMustAlloc); - - TRACE("copying %p to %p\n", saved_buffer, *ppMemory); - if (*ppMemory != saved_buffer) - memcpy(*ppMemory, saved_buffer, size); + array_read_conformance(RPC_FC_CARRAY, pStubMsg, pFormat); + array_read_variance_and_unmarshall(RPC_FC_CARRAY, pStubMsg, ppMemory, pFormat, + fMustAlloc, + TRUE /* fUseBufferMemoryServer */); return NULL; } @@ -3129,23 +3408,15 @@ void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - DWORD size, esize = *(const WORD*)(pFormat+2); - unsigned char alignment = pFormat[1] + 1; - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + if (pFormat[0] != RPC_FC_CARRAY) + { + ERR("invalid format = 0x%x\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - - SizeConformance(pStubMsg); - - ALIGN_LENGTH(pStubMsg->BufferLength, alignment); - - size = safe_multiply(esize, pStubMsg->MaxCount); - /* conformance value plus array */ - safe_buffer_length_increment(pStubMsg, size); - - EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); + array_compute_and_size_conformance(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat); + array_buffer_size(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat); } /*********************************************************************** @@ -3154,21 +3425,15 @@ void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, ULONG WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { - DWORD size = 0, esize = *(const WORD*)(pFormat+2); - unsigned char alignment = pFormat[1] + 1; - TRACE("(%p,%p)\n", pStubMsg, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + if (pFormat[0] != RPC_FC_CARRAY) + { + ERR("invalid format = 0x%x\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } - pFormat = ReadConformance(pStubMsg, pFormat+4); - size = safe_multiply(esize, pStubMsg->MaxCount); - pStubMsg->MemorySize += size; - - ALIGN_POINTER(pStubMsg->Buffer, alignment); - pStubMsg->BufferMark = pStubMsg->Buffer; - safe_buffer_increment(pStubMsg, size); - - EmbeddedPointerMemorySize(pStubMsg, pFormat); + array_read_conformance(RPC_FC_CARRAY, pStubMsg, pFormat); + array_memory_size(RPC_FC_CARRAY, pStubMsg, pFormat); return pStubMsg->MemorySize; } @@ -3181,11 +3446,13 @@ void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + if (pFormat[0] != RPC_FC_CARRAY) + { + ERR("invalid format = 0x%x\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - - EmbeddedPointerFree(pStubMsg, pMemory, pFormat); + array_free(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat); }