From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/vccorlib.c | 8 ++--- dlls/vccorlib140/vccorlib.c | 51 ++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index 8a4904e4141..2af3ff38608 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -579,8 +579,7 @@ static void test_Allocate(void) /* AllocateException allocates additional space for two pointer-width fields, with the second field used as the * back-pointer to the exception data. */ addr = pAllocateException(0); - todo_wine ok(!!addr, "got addr %p\n", addr); - if (!addr) return; + ok(!!addr, "got addr %p\n", addr); ptr = (void **)((ULONG_PTR)addr - sizeof(void *)); *ptr = NULL; /* The write should succeed. */ base = (void **)((ULONG_PTR)addr - 2 * sizeof(void *)); @@ -757,7 +756,7 @@ static void test_AllocateWithWeakRef_inline(void) ok(object->weakref->ref_strong == 1, "got ref_strong %lu\n", object->weakref->ref_strong); ok(object->weakref->object == &object->IUnknown_iface, "got object %p != %p\n", object->weakref->object, &object->IUnknown_iface); - todo_wine ok(object->weakref->unknown == 0, "got unknown %d\n", object->weakref->unknown); + ok(object->weakref->unknown == 0, "got unknown %d\n", object->weakref->unknown); ok(!object->weakref->is_exception, "got is_exception %d\n", object->weakref->is_exception); /* The object is allocate within the weakref. */ ok((char *)object->weakref == ((char *)object - sizeof(struct control_block)), "got %p != %p\n", object->weakref, @@ -844,8 +843,7 @@ static void test_AllocateWithWeakRef(void)
/* AllocateExceptionWithWeakRef will not store the control block inline, regardless of the size. */ object = pAllocateExceptionWithWeakRef(offsetof(struct unknown_impl, weakref), sizeof(struct unknown_impl)); - todo_wine ok(object != NULL, "got object %p\n", object); - if (!object) return; + ok(object != NULL, "got object %p\n", object);
object->strong_ref_free_val = -100; ok(object->weakref != NULL, "got weakref %p\n", object->weakref); diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 36fc1333718..b472a26177e 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -101,10 +101,21 @@ void *__cdecl Allocate(size_t size) return addr; }
+struct exception_alloc +{ + void *unknown; + void *exception_inner; + char data[0]; +}; + void *__cdecl AllocateException(size_t size) { - FIXME("(%Iu): stub!\n", size); - return NULL; + struct exception_alloc *base; + + TRACE("(%Iu)\n", size); + + base = Allocate(offsetof(struct exception_alloc, data[size])); + return &base->data; }
void __cdecl Free(void *addr) @@ -116,7 +127,11 @@ void __cdecl Free(void *addr)
void __cdecl FreeException(void *addr) { - FIXME("(%p): stub!\n", addr); + struct exception_alloc *base = CONTAINING_RECORD(addr, struct exception_alloc, data); + + TRACE("(%p)\n", addr); + + free(base); }
struct control_block @@ -126,7 +141,8 @@ struct control_block LONG ref_strong; IUnknown *object; bool is_inline; - UINT16 unknown; + UINT8 unknown; + bool is_exception; #ifdef _WIN32 char _padding[4]; #endif @@ -228,14 +244,30 @@ void *__cdecl AllocateWithWeakRef(ptrdiff_t offset, size_t size) weakref->object = object; weakref->ref_strong = weakref->ref_weak = 1; weakref->unknown = 0; + weakref->is_exception = FALSE;
return weakref->object; }
void *__cdecl AllocateExceptionWithWeakRef(ptrdiff_t offset, size_t size) { - FIXME("(%Iu, %Iu): stub!\n", offset, size); - return NULL; + struct control_block *weakref; + void *excp; + + TRACE("(%Iu, %Iu)\n", offset, size); + + /* AllocateExceptionWithWeakRef does not store the control block inline, regardless of size. */ + weakref = Allocate(sizeof(*weakref)); + excp = AllocateException(size); + *(struct control_block **)((char *)excp + offset) = weakref; + weakref->IWeakReference_iface.lpVtbl = &control_block_vtbl; + weakref->object = excp; + weakref->ref_strong = weakref->ref_weak = 1; + weakref->is_inline = FALSE; + weakref->unknown = 0; + weakref->is_exception = TRUE; + + return excp; }
DEFINE_THISCALL_WRAPPER(control_block_ReleaseTarget, 4) @@ -247,7 +279,12 @@ void __thiscall control_block_ReleaseTarget(struct control_block *weakref)
if (weakref->is_inline || ReadNoFence(&weakref->ref_strong) >= 0) return; if ((object = InterlockedCompareExchangePointer((void *)&weakref->object, NULL, weakref->object))) - Free(object); + { + if (weakref->is_exception) + FreeException(object); + else + Free(object); + } }
struct __abi_type_descriptor