Repository: microsoft/onefuzz
File: src/agent/coverage/src/record/windows.rs (Rust)

Code before:
        dbg.quit_debugging();
    }

    fn insert_module(&mut self, dbg: &mut Debugger, module: &ModuleLoadInfo) -> Result<()> {
        let path = FilePath::new(module.path().to_string_lossy())?;

        if !self.allowlist.modules.is_allowed(&path) {
            debug!("not inserting denylisted module: {path}");
            return Ok(());
        }

        let module = if let Ok(m) = WindowsModule::load(self.loader, path.clone()) {
            m
        } else {
            debug!("skipping undebuggable module: {path}");
            return Ok(());
        };

        let debuginfo = module.debuginfo()?;
        self.modules.insert(path.clone(), (module, debuginfo));

        self.set_or_defer_module_breakpoints(dbg, path)?;

        Ok(())
    }

    fn set_or_defer_module_breakpoints(
        &mut self,
        dbg: &mut Debugger,
        path: FilePath,
    ) -> Result<()> {
        let (_module, debuginfo) = &self.modules[&path];

        // For borrowck.
        let mut trigger = None;

        for function in debuginfo.functions() {
            // Called on process startup.
            if function.name.contains("__asan::AsanInitInternal") {
                trigger = Some(function.clone());
                break;
            }

            // Called on shared library load.
            if function.name.contains("DllMain(") {
                trigger = Some(function.clone());
                break;
            }
        }

        if let Some(trigger) = trigger {

Review comment (bug):
Fixed bug: this check ignored modules. So if we had a breakpoint set in `foo+123`, this would return `true` for `bar+123`, even if no breakpoint was set.

Code after:

        let breakpoint = self.breakpoints.remove(id);

        let Some(breakpoint) = breakpoint else {
            let stack = dbg.get_current_stack()?;
            bail!("stopped on dangling breakpoint, debuggee stack:\n{}", stack);
        };

        let coverage = self
            .coverage
            .modules
            .get_mut(&breakpoint.module)
            .ok_or_else(|| anyhow!("coverage not initialized for module: {}", breakpoint.module))?;

        coverage.increment(breakpoint.offset);

        Ok(())
    }

    fn stop(&mut self, dbg: &mut Debugger, stop_error: impl Into<Option<Error>>) {
        self.stop_error = stop_error.into();
        dbg.quit_debugging();
    }

    fn insert_module(&mut self, dbg: &mut Debugger, module: &ModuleLoadInfo) -> Result<()> {
        let path = FilePath::new(module.path().to_string_lossy())?;

        if self.modules.contains_key(&path) {
            warn!("module coverage already initialized, skipping");
            return Ok(());
        }

        if !self.allowlist.modules.is_allowed(&path) {
            debug!("not inserting denylisted module: {path}");
            return Ok(());
        }

        let module = if let Ok(m) = WindowsModule::load(self.loader, path.clone()) {
            m
        } else {
            debug!("skipping undebuggable module: {path}");
            return Ok(());
        };

        let debuginfo = module.debuginfo()?;
        self.modules.insert(path.clone(), (module, debuginfo));

        self.set_or_defer_module_breakpoints(dbg, path)?;

        Ok(())
    }