EX_FAST_REF Pointers


EX_FAST_REF pointers are built around that fact that that data structures allocated from the pool are always aligned on a 16 byte boundary on 64-bit systems and 8 byte boundary on 32-bit systems. As a result of this alignment, a few spare bits in the pointer are available to be used for reference counting purposes. This mechanism is for internal use in the kernel and not exposed to driver developers.

EX_FAST_REF structure definition on X64

kd> dt nt!_EX_FAST_REF
    +0x000 Object           : Ptr64 Void
    +0x000 RefCnt           : Pos 0, 4 Bits
    +0x000 Value            : Uint8B

EX_FAST_REF structure definition on X86

kd> dt nt!_EX_FAST_REF
    +0x000 Object           : Ptr32 Void
    +0x000 RefCnt           : Pos 0, 3 Bits
    +0x000 Value            : Uint4B

As seen in the above structure definitions EX_FAST_REF is pointer sized structure. The maximum number of references that can be taken (EX_FAST_REF.RefCount) is 15 on X64 and 7 on X86.

EX_FAST_REF pointers are initialized using ObInitializeFastReference() which sets up EX_FAST_REF.Value to point to the pool allocated structure and initializes the EX_FAST_REF.RefCnt to the maximum number of references. Fast references are taken and dropped using the multiprocessor safe lock free operation InterlockedCompareExchangePointer().

When a fast reference is taken on a EX_FAST_REF pointer the RefCount is decremented. When there are no more fast references available ( EX_FAST_REF.RefCnt == 1 ) the fast reference function ObFastReferenceObject() takes the slow path i.e. ObReferenceObject() and replenishes the reference count to the maximum value.

The high level code construct for taking fast references on an EX_FAST_REF pointer FastRefPointer is as follows :

EX_FAST_REF New, Old;

for ( New = Old = FastRefPointer ; Old.RefCount ; Old = New ) 
{ 
    // set New to the desired value
    New.RefCnt = Old.RefCnt -1;

    // attempt to set it atomically
    New.Object = InterlockedCompareExchangePointer ( 
        &FastRefPointer, 
        New.Object, 
        Old.Object );

    // check if the existing value was what we expected
    if ( Old.Object == New.Object ) {
        break; // done
    } 
}

Similarly when a fast reference on an EX_FAST_REF pointer is dropped the RefCount is incremented and when it reaches the maximum, the slow dereference path i.e. ObfDereferenceObject() is taken.

Examples of EX_FAST_REF pointers in the system are OBJECT_HEADER.SecurityDescriptor, SHARED_CACHE_MAP.FileObjectFastRef, EPROCESS.Token and EPROCESS.PrefetchTrace.