Skip to content

Commit 76bb429

Browse files
authored
Merge pull request #8435 from julian-klode/tr-enomem
tr: fix high memory use, possible heap exhaustion
2 parents 69d0e93 + c93b9ed commit 76bb429

File tree

2 files changed

+14
-13
lines changed

2 files changed

+14
-13
lines changed

src/uu/tr/src/operation.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -672,15 +672,17 @@ where
672672
R: BufRead,
673673
W: Write,
674674
{
675-
let mut buf = Vec::new();
675+
let mut buf = [0; 8192];
676676
let mut output_buf = Vec::new();
677677

678-
while let Ok(length) = input.read_until(b'\n', &mut buf) {
678+
while let Ok(length) = input.read(&mut buf[..]) {
679679
if length == 0 {
680680
break; // EOF reached
681681
}
682682

683-
let filtered = buf.iter().filter_map(|&c| translator.translate(c));
683+
let filtered = buf[..length]
684+
.iter()
685+
.filter_map(|&c| translator.translate(c));
684686
output_buf.extend(filtered);
685687

686688
#[cfg(not(target_os = "windows"))]
@@ -698,7 +700,6 @@ where
698700
}
699701
}
700702

701-
buf.clear();
702703
output_buf.clear();
703704
}
704705

src/uu/tr/src/tr.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use operation::{
1212
translate_input,
1313
};
1414
use std::ffi::OsString;
15-
use std::io::{BufWriter, Write, stdin, stdout};
15+
use std::io::{Write, stdin, stdout};
1616
use uucore::display::Quotable;
1717
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
1818
use uucore::fs::is_stdin_directory;
@@ -107,7 +107,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
107107

108108
let stdin = stdin();
109109
let mut locked_stdin = stdin.lock();
110-
let mut buffered_stdout = BufWriter::new(stdout().lock());
110+
let mut locked_stdout = stdout().lock();
111111

112112
// According to the man page: translating only happens if deleting or if a second set is given
113113
let translating = !delete_flag && sets.len() > 1;
@@ -131,34 +131,34 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
131131
let delete_op = DeleteOperation::new(set1);
132132
let squeeze_op = SqueezeOperation::new(set2);
133133
let op = delete_op.chain(squeeze_op);
134-
translate_input(&mut locked_stdin, &mut buffered_stdout, op)?;
134+
translate_input(&mut locked_stdin, &mut locked_stdout, op)?;
135135
} else {
136136
let op = DeleteOperation::new(set1);
137-
translate_input(&mut locked_stdin, &mut buffered_stdout, op)?;
137+
translate_input(&mut locked_stdin, &mut locked_stdout, op)?;
138138
}
139139
} else if squeeze_flag {
140140
if sets_len == 1 {
141141
let op = SqueezeOperation::new(set1);
142-
translate_input(&mut locked_stdin, &mut buffered_stdout, op)?;
142+
translate_input(&mut locked_stdin, &mut locked_stdout, op)?;
143143
} else {
144144
let translate_op = TranslateOperation::new(set1, set2.clone())?;
145145
let squeeze_op = SqueezeOperation::new(set2);
146146
let op = translate_op.chain(squeeze_op);
147-
translate_input(&mut locked_stdin, &mut buffered_stdout, op)?;
147+
translate_input(&mut locked_stdin, &mut locked_stdout, op)?;
148148
}
149149
} else {
150150
let op = TranslateOperation::new(set1, set2)?;
151-
translate_input(&mut locked_stdin, &mut buffered_stdout, op)?;
151+
translate_input(&mut locked_stdin, &mut locked_stdout, op)?;
152152
}
153153

154154
#[cfg(not(target_os = "windows"))]
155-
buffered_stdout
155+
locked_stdout
156156
.flush()
157157
.map_err_context(|| translate!("tr-error-write-error"))?;
158158

159159
// SIGPIPE is not available on Windows.
160160
#[cfg(target_os = "windows")]
161-
match buffered_stdout.flush() {
161+
match locked_stdout.flush() {
162162
Ok(()) => {}
163163
Err(err) if err.kind() == std::io::ErrorKind::BrokenPipe => std::process::exit(13),
164164
Err(err) => return Err(err.map_err_context(|| translate!("tr-error-write-error"))),

0 commit comments

Comments
 (0)