Repository: tikv/tikv
File: components/resolved_ts/src/endpoint.rs (Rust)

Code before:
        fail_point!("resolved_ts_after_handle_change_log");
    }

    fn handle_scan_locks(
        &mut self,
        region_id: u64,
        observe_id: ObserveId,
        entries: ScanEntries,
        apply_index: u64,
    ) {
        let mut memory_quota_exceeded = None;
        if let Some(observe_region) = self.regions.get_mut(&region_id) {
            if observe_region.handle.id == observe_id {
                if let Err(Error::MemoryQuotaExceeded(e)) =
                    observe_region.track_scan_locks(entries, apply_index)
                {
                    memory_quota_exceeded = Some(Error::MemoryQuotaExceeded(e));
                }
            }
        } else {
            debug!("scan locks region not exist";
                "region_id" => region_id,
                "observe_id" => ?observe_id);
        }
        if let Some(e) = memory_quota_exceeded {
            self.re_register_all_regions(Some(e.to_string().as_str()));
        }
    }

    fn handle_advance_resolved_ts(&self, leader_resolver: LeadershipResolver) {
        let regions = self.regions.keys().copied().collect();
        self.advance_worker.advance_ts_for_regions(
            regions,
            leader_resolver,
            self.cfg.advance_ts_interval.0,
            self.advance_notify.clone(),
        );
    }

    fn handle_change_config(&mut self, change: ConfigChange) {
        let prev = format!("{:?}", self.cfg);
        if let Err(e) = self.cfg.update(change) {
            warn!("resolved-ts config fails"; "error" => ?e);
        } else {
            self.advance_notify.notify_waiters();
            self.memory_quota
                .set_capacity(self.cfg.memory_quota.0 as usize);
            self.scan_concurrency_semaphore =
                Arc::new(Semaphore::new(self.cfg.incremental_scan_concurrency));
            info!(
                "resolved-ts config changed";

Review comment (bug):
Converting `e.to_string().as_str()` creates a temporary String that is immediately converted to a string slice. The temporary String is dropped at the end of the statement, making the string slice invalid. This is a use-after-free bug. Instead, pass `&e.to_string()` or use a temporary variable to store the String.

Code after:
        fail_point!("resolved_ts_after_handle_change_log");
    }

    fn handle_scan_locks(
        &mut self,
        region_id: u64,
        observe_id: ObserveId,
        entries: ScanEntries,
        apply_index: u64,
    ) {
        let mut memory_quota_exceeded = None;
        if let Some(observe_region) = self.regions.get_mut(&region_id) {
            if observe_region.handle.id == observe_id {
                if let Err(Error::MemoryQuotaExceeded(e)) =
                    observe_region.track_scan_locks(entries, apply_index)
                {
                    memory_quota_exceeded = Some(Error::MemoryQuotaExceeded(e));
                }
            }
        } else {
            debug!("scan locks region not exist";
                "region_id" => region_id,
                "observe_id" => ?observe_id);
        }
        if let Some(e) = memory_quota_exceeded {
            self.re_register_all_regions(Some(&e.to_string()));
        }
    }

    fn handle_advance_resolved_ts(&self, leader_resolver: LeadershipResolver) {
        let regions = self.regions.keys().copied().collect();
        self.advance_worker.advance_ts_for_regions(
            regions,
            leader_resolver,
            self.cfg.advance_ts_interval.0,
            self.advance_notify.clone(),
        );
    }

    fn handle_change_config(&mut self, change: ConfigChange) {
        let prev = format!("{:?}", self.cfg);
        if let Err(e) = self.cfg.update(change) {
            warn!("resolved-ts config fails"; "error" => ?e);
        } else {
            self.advance_notify.notify_waiters();
            self.memory_quota
                .set_capacity(self.cfg.memory_quota.0 as usize);
            self.scan_concurrency_semaphore =
                Arc::new(Semaphore::new(self.cfg.incremental_scan_concurrency));
            info!(
                "resolved-ts config changed";