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

Code before:
    // observe id is valid.
    #[allow(dropping_references)]
    fn handle_change_log(&mut self, cmd_batch: Vec<CmdBatch>) {
        let size = cmd_batch.iter().map(|b| b.size()).sum::<usize>();
        self.memory_quota.free(size);
        RTS_CHANNEL_PENDING_CMD_BYTES.sub(size as i64);
        for batch in cmd_batch {
            if batch.is_empty() {
                continue;
            }
            if let Some(observe_region) = self.regions.get_mut(&batch.region_id) {
                let observe_id = batch.rts_id;
                let region_id = observe_region.meta.id;
                if observe_region.handle.id == observe_id {
                    let logs = ChangeLog::encode_change_log(region_id, batch);
                    if let Err(e) = observe_region.track_change_log(&logs) {
                        drop(observe_region);
                        match e {
                            cause @ Error::MemoryQuotaExceeded(_) => {
                                self.re_register_all_regions(Some(cause.to_string().as_str()));
                            }
                            cause @ Error::Other(_) => {
                                self.re_register_region(
                                    region_id,
                                    observe_id,
                                    Some(cause.to_string().as_str()),
                                    None,
                                );
                            }
                        };
                    }
                } else {
                    debug!("resolved ts CmdBatch discarded";
                        "region_id" => batch.region_id,
                        "observe_id" => ?batch.rts_id,
                        "current" => ?observe_region.handle.id,
                    );
                }
            }
        }
        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;

Review comment (bug):
Converting `cause.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 `&cause.to_string()` or use a temporary variable to store the String.
```suggestion
                                let msg = cause.to_string();
                                self.re_register_all_regions(Some(&msg));
                            }
                            cause @ Error::Other(_) => {
                                let msg = cause.to_string();
                                self.re_register_region(
                                    region_id,
                                    observe_id,
                                    Some(&msg),
```

Code after:
    // observe id is valid.
    #[allow(dropping_references)]
    fn handle_change_log(&mut self, cmd_batch: Vec<CmdBatch>) {
        let size = cmd_batch.iter().map(|b| b.size()).sum::<usize>();
        self.memory_quota.free(size);
        RTS_CHANNEL_PENDING_CMD_BYTES.sub(size as i64);
        for batch in cmd_batch {
            if batch.is_empty() {
                continue;
            }
            if let Some(observe_region) = self.regions.get_mut(&batch.region_id) {
                let observe_id = batch.rts_id;
                let region_id = observe_region.meta.id;
                if observe_region.handle.id == observe_id {
                    let logs = ChangeLog::encode_change_log(region_id, batch);
                    if let Err(e) = observe_region.track_change_log(&logs) {
                        drop(observe_region);
                        match e {
                            cause @ Error::MemoryQuotaExceeded(_) => {
                                self.re_register_all_regions(Some(&cause.to_string()));
                            }
                            cause @ Error::Other(_) => {
                                self.re_register_region(
                                    region_id,
                                    observe_id,
                                    Some(&cause.to_string()),
                                    None,
                                );
                            }
                        };
                    }
                } else {
                    debug!("resolved ts CmdBatch discarded";
                        "region_id" => batch.region_id,
                        "observe_id" => ?batch.rts_id,
                        "current" => ?observe_region.handle.id,
                    );
                }
            }
        }
        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;