WDF object lifetime: WDFLOOKASIDE child vs WDFMEMORY (siblings under same parent)

I’m trying to clarify WDF object-lifetime ordering when WDFLOOKASIDE, its child object, and WDFMEMORY allocations are involved.

In my driver, I create a WDFLOOKASIDE where both LookasideAttributes.ParentObject and MemoryAttributes.ParentObject point to the same parent WDFOBJECT. This means:

  • The WDFLOOKASIDE is a child of the parent object.

  • Any WDFMEMORY allocated via WdfMemoryCreateFromLookaside is also a child of that same parent (i.e., sibling to the lookaside).

  • Separately, I create another child WDFOBJECT whose parent is the lookaside itself (so the lookaside is its parent).

So the hierarchy is roughly:

ParentObject
 ├── WDFLOOKASIDE
 │    └── ChildWdfObject
 └── WDFMEMORY (multiple instances)

I’m trying to understand what happens when the parent object is deleted (either explicitly with WdfObjectDelete, or implicitly at driver unload).


:one: Ordering question #1

Is there a framework guarantee that the ChildWdfObject’s EvtDestroyCallback (the one parented to the lookaside) will be invoked before the destruction of the sibling WDFMEMORY objects that were allocated from the lookaside?


:two: Ordering question #2

Does WDF perform deletion in distinct phases over the object tree:

  • Phase 1: invoke EvtCleanupCallback bottom-up across the tree

  • Phase 2: after the root cleanup completes, invoke EvtDestroyCallback bottom-up

In other words, is it guaranteed that the ChildWdfObject’s EvtCleanupCallback will run before any EvtDestroyCallback for the sibling WDFMEMORY objects?

The documentation here is a bit ambiguous:

“…the framework calls the child object's EvtCleanupCallback callback functions before calling the parent object's EvtCleanupCallback callback function. Next, if the child's reference count is zero, the framework calls the child object's EvtDestroyCallback callback function…”

What’s unclear is whether “next” means:

  • the child’s EvtDestroyCallback runs immediately after the child’s EvtCleanupCallback,
    or

  • the child’s EvtDestroyCallback runs only after all of its parent objects’ EvtCleanupCallback up to the root, have completed.

I’m trying to determine whether relying on this ordering is documented and safe, or whether the behavior should be considered undefined.

Thanks for any insight.