Skip to content

Commit 2f4baf9

Browse files
authored
Ensure termination of syslog writer (#857)
Closing #856 This particular code has been struck by lightning a couple of times now and is pretty hard to reason about using formal reasoning (e.g. a loop invariant like `self.cursor < LIMIT` would seen to have to hold, but it doesn't really). This PR doesn't improve that situation (i.e. the formal reasoning), but it does ensure termination. As a minor side-fix, the code could also panic on line 54 if we hit the middle of a UTF8 character in exactly the wrong position, that is fixed as well. I'll work on an implementation of this writer in a more declarative style.
2 parents 2ac8cbb + 6b5151d commit 2f4baf9

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

src/log/syslog.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,20 @@ impl Write for SysLogWriter {
5151
if self.cursor + message.len() > LIMIT {
5252
// floor_char_boundary is currently unstable
5353
let mut truncate_boundary = LIMIT - self.cursor;
54-
while !message.is_char_boundary(truncate_boundary) {
54+
while truncate_boundary > 0 && !message.is_char_boundary(truncate_boundary) {
5555
truncate_boundary -= 1;
5656
}
5757

58+
// don't overzealously truncate log messages
5859
truncate_boundary = message[..truncate_boundary]
5960
.rfind(|c: char| c.is_ascii_whitespace())
6061
.unwrap_or(truncate_boundary);
6162

63+
if truncate_boundary == 0 {
64+
// we failed to find a "nice" cut off point, abruptly cut off the msg
65+
truncate_boundary = LIMIT - self.cursor;
66+
}
67+
6268
let left = &message[..truncate_boundary];
6369
let right = &message[truncate_boundary..];
6470

test-framework/e2e-tests/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![cfg(test)]
22

33
mod pty;
4+
mod regression;
45
mod su;
56

67
type Error = Box<dyn std::error::Error>;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use sudo_test::{Command, Env, TextFile};
2+
3+
use crate::Result;
4+
5+
#[test]
6+
fn syslog_writer_should_not_hang() -> Result<()> {
7+
let env = Env(TextFile("ALL ALL=(ALL:ALL) NOPASSWD: ALL").chmod("644")).build()?;
8+
9+
let stdout = Command::new("sudo")
10+
.args(["env", "CC=clang-18", "CXX=clang++-18", "FOO=\"........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................\"", "whoami"])
11+
.output(&env)?
12+
.stdout()?;
13+
14+
assert_eq!(stdout, "root");
15+
16+
Ok(())
17+
}

0 commit comments

Comments
 (0)