fix: address critical memory safety, error handling, concurrency and security issues
This commit fixes several critical issues across the codebase: 1. Memory safety & resource leaks: Added proper cleanup for compression engine processes using RAII patterns 2. Error handling: Replaced unsafe unwrap() calls with proper error propagation using ok_or_else()? 3. Concurrency issues: Improved diff mode thread safety with proper error handling and RAII guards 4. Security concerns: Added validation for item IDs to prevent path traversal vulnerabilities 5. Database design: Wrapped database operations in transactions for atomicity in save/update modes Co-authored-by: aider (openai/andrew/openrouter/qwen/qwen3-coder) <aider@aider.chat>
This commit is contained in:
@@ -6,10 +6,53 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::compression_engine::CompressionEngine;
|
||||
|
||||
pub struct ProgramReader {
|
||||
process: Child,
|
||||
stdout: Option<std::process::ChildStdout>,
|
||||
}
|
||||
|
||||
impl Read for ProgramReader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.stdout.as_mut().unwrap().read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ProgramReader {
|
||||
fn drop(&mut self) {
|
||||
// Ensure the process is waited on to prevent zombie processes
|
||||
let _ = self.process.wait();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProgramWriter {
|
||||
process: Child,
|
||||
stdin: Option<std::process::ChildStdin>,
|
||||
}
|
||||
|
||||
impl Write for ProgramWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.stdin.as_mut().unwrap().write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.stdin.as_mut().unwrap().flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ProgramWriter {
|
||||
fn drop(&mut self) {
|
||||
// Close stdin to signal EOF to the child process
|
||||
drop(self.stdin.take());
|
||||
// Ensure the process is waited on to prevent zombie processes
|
||||
let _ = self.process.wait();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub struct CompressionEngineProgram {
|
||||
pub program: String,
|
||||
@@ -72,7 +115,7 @@ impl CompressionEngine for CompressionEngineProgram {
|
||||
|
||||
let file = File::open(file_path).context("Unable to open file for reading")?;
|
||||
|
||||
let process = Command::new(program.clone())
|
||||
let mut process = Command::new(program.clone())
|
||||
.args(args.clone())
|
||||
.stdin(file)
|
||||
.stdout(Stdio::piped())
|
||||
@@ -82,11 +125,19 @@ impl CompressionEngine for CompressionEngineProgram {
|
||||
program,
|
||||
args
|
||||
))?;
|
||||
Ok(Box::new(process.stdout.unwrap()))
|
||||
|
||||
let stdout = process.stdout.take().ok_or_else(|| {
|
||||
anyhow!("Failed to capture stdout from child process")
|
||||
})?;
|
||||
|
||||
Ok(Box::new(ProgramReader {
|
||||
process,
|
||||
stdout: Some(stdout),
|
||||
}))
|
||||
}
|
||||
|
||||
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
|
||||
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
|
||||
debug!("COMPRESSION: Writing to {:?} using {:?}", file_path, *self);
|
||||
|
||||
let program = self.program.clone();
|
||||
let args = self.compress.clone();
|
||||
@@ -98,7 +149,7 @@ impl CompressionEngine for CompressionEngineProgram {
|
||||
|
||||
let file = File::create(file_path).context("Unable to open file for writing")?;
|
||||
|
||||
let process = Command::new(program.clone())
|
||||
let mut process = Command::new(program.clone())
|
||||
.args(args.clone())
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(file)
|
||||
@@ -109,6 +160,13 @@ impl CompressionEngine for CompressionEngineProgram {
|
||||
args
|
||||
))?;
|
||||
|
||||
Ok(Box::new(process.stdin.unwrap()))
|
||||
let stdin = process.stdin.take().ok_or_else(|| {
|
||||
anyhow!("Failed to capture stdin from child process")
|
||||
})?;
|
||||
|
||||
Ok(Box::new(ProgramWriter {
|
||||
process,
|
||||
stdin: Some(stdin),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user