fix: INI newline injection in backtest config generation

Add ini_safe() helper that strips CR/LF from user-supplied string params
before they are written into terminal.ini and backtest_config.ini.
Applies to: expert path, symbol, timeframe, set_file — any value that
could carry an embedded newline and inject extra INI directives.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Devid HW
2026-04-23 01:24:59 +07:00
parent 05214ff34b
commit b6171d0c56
2 changed files with 13 additions and 8 deletions
Generated
+1 -1
View File
@@ -481,7 +481,7 @@ dependencies = [
[[package]]
name = "mt5-quant"
version = "1.32.2"
version = "1.32.1"
dependencies = [
"anyhow",
"base64",
+12 -7
View File
@@ -823,12 +823,12 @@ impl BacktestPipeline {
};
let set_file_line = params.set_file.as_ref()
.map(|p| format!("ExpertParameters={}\n", p))
.map(|p| format!("ExpertParameters={}\n", Self::ini_safe(p)))
.unwrap_or_default();
let updates: &[(&str, String)] = &[
("Expert", expert_path),
("Symbol", params.symbol.clone()),
("Expert", Self::ini_safe(&expert_path)),
("Symbol", Self::ini_safe(&params.symbol)),
("Period", period.to_string()),
("DateRange", "3".into()),
("DateFrom", from_ts.to_string()),
@@ -855,6 +855,11 @@ impl BacktestPipeline {
Ok(())
}
/// Strip CR/LF from a user-supplied INI value to prevent newline injection.
fn ini_safe(value: &str) -> String {
value.replace(['\n', '\r'], "")
}
fn patch_ini_section(text: &str, section: &str, updates: &[(&str, String)]) -> String {
let section_header = format!("[{}]", section);
let mut result = String::with_capacity(text.len() + 256);
@@ -1025,9 +1030,9 @@ impl BacktestPipeline {
ini.push_str("[Tester]\n");
// Expert path is relative to MQL5/Experts/ in the /config: format (no "Experts\" prefix).
ini.push_str(&format!("Expert={}\n", self.resolve_backtest_ini_expert_path(&params.expert)));
ini.push_str(&format!("Symbol={}\n", params.symbol));
ini.push_str(&format!("Period={}\n", params.timeframe));
ini.push_str(&format!("Expert={}\n", Self::ini_safe(&self.resolve_backtest_ini_expert_path(&params.expert))));
ini.push_str(&format!("Symbol={}\n", Self::ini_safe(&params.symbol)));
ini.push_str(&format!("Period={}\n", Self::ini_safe(&params.timeframe)));
ini.push_str("Optimization=0\n");
ini.push_str(&format!("Model={}\n", params.model));
ini.push_str(&format!("FromDate={}\n", params.from_date));
@@ -1044,7 +1049,7 @@ impl BacktestPipeline {
ini.push_str(&format!("ShutdownTerminal={}\n", if params.shutdown { "1" } else { "0" }));
if let Some(set_file) = &params.set_file {
ini.push_str(&format!("ExpertParameters={}\n", set_file));
ini.push_str(&format!("ExpertParameters={}\n", Self::ini_safe(set_file)));
}
Ok(ini)