From 976e71a2fa239cd7336bdcc56fcd7639b2e4edfd Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 13 Apr 2021 12:35:10 +0200 Subject: [PATCH] Fix #80933: SplFileObject::DROP_NEW_LINE is broken for NUL and CR `buf` may contain NUL bytes, so we must not use `strcspn()` but rather a binary safe variant. However, we also must not detect a stray CR as line ending, and since we only need to check line endings at the end of the buffer, we can nicely optimize. Co-authored-by: Nikita Popov Closes GH-6836. --- NEWS | 4 +++- ext/spl/spl_directory.c | 9 +++++++-- ext/spl/tests/bug80933.phpt | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 ext/spl/tests/bug80933.phpt diff --git a/NEWS b/NEWS index 95c3ab60483..8a3d541a6ec 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 7.4.19 - +- SPL: + . Fixed bug #80933 (SplFileObject::DROP_NEW_LINE is broken for NUL and CR). + (cmb, Nikita) 29 Apr 2021, PHP 7.4.18 diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index daed72d8470..202a815e82c 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2046,8 +2046,13 @@ static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent) / intern->u.file.current_line_len = 0; } else { if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) { - line_len = strcspn(buf, "\r\n"); - buf[line_len] = '\0'; + if (line_len > 0 && buf[line_len - 1] == '\n') { + line_len--; + if (line_len > 0 && buf[line_len - 1] == '\r') { + line_len--; + } + buf[line_len] = '\0'; + } } intern->u.file.current_line = buf; diff --git a/ext/spl/tests/bug80933.phpt b/ext/spl/tests/bug80933.phpt new file mode 100644 index 00000000000..78e94aba409 --- /dev/null +++ b/ext/spl/tests/bug80933.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #80933 (SplFileObject::DROP_NEW_LINE is broken for NUL and CR) +--FILE-- +fwrite($line); + + $temp->rewind(); + $read = $temp->fgets(); + var_dump($line === $read); + + $temp->rewind(); + $temp->setFlags(SplFileObject::DROP_NEW_LINE); + $read = $temp->fgets(); + var_dump($line === $read); +} +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true)