windowsrustperformancecounter

Memory Leak in a Rust Program


I wrote a Rust program using windows-sys crate and collecting the performance counter values for query that is being supplied. I use the sample program provided by Microsoft team (here).

The program is able to retrieve the performance counter value. However when I checked process explorer to monitor the footprint, I noticed the below chart for private bytes. Since the private bytes is linearly increasing it points to memory leak.

enter image description here

I couldn't use windbg because windbg is not able to connect to microsoft symbol server. Hence I decided to manually identify the source of the problem by commenting out code and checking the private bytes. The relevant code is below -

fn execute_perf_query(input_query: &String,perf_query: &mut Vec<PerfEntryForMongo>)->f64{
    log::info!("Performing counter for  {:?}", input_query);

    let hostname = gethostname().into_string();
    
    unsafe {
        let mut query = 0;
        let p: *const u16 = std::ptr::null();
        
        PdhOpenQueryW(p, 0 as usize, &mut query);

    }

    return -1.0;
    //println!("Returning Now");
}

Please note, currently I have commented out code related to PdhAddCounterW, PdhCollectQueryData, and PdhGetFormattedCounterValue to understand impact of each windows call on private bytes.

Vec<PerfEntryForMongo> is being cleared after each iteration, and hence is not causing memory leak. hostname is a string and would be allocated on heap, however once the scope is ending, the memory would be freed.

I am using raw pointer, however it is a NULL pointer and shouldn't be allocating any memory in heap. What I need to understand, what is causing memory leak. I have covered the chapters related to reference, borrowing and unsafe Rust, yet I am not able to identify the cause of memory leak.


Solution

  • The PdhOpenQueryW() call will create a resource and update the query handle. You need to release the resource associated to this handle with PdhCloseQuery().

    Because all of this happens in an unsafe block, Rust trusts you and cannot decide on its own whether this resource should be released.

    Each time this function is called, the created resource is leaked.