#1040947 perl: readline fails to detect updated file

Package:
perl
Source:
perl
Description:
Larry Wall's Practical Extraction and Report Language
Submitter:
Eric Wong
Date:
2023-07-20 17:39:05 UTC
Severity:
normal
Tags:
#1040947#5
Date:
2023-07-12 21:17:54 UTC
From:
To:
Dear Maintainer,

The `readline' op (`<FH>') no longer detects updates to file
which is being written to in Perl 5.36.0 after updating to bookworm.

The attached script worked fine with Perl 5.32.1 in oldstable,
both scripts show the size changing with the `-s FH' op.
Same behavior on both amd64 and i386.

#1040947#10
Date:
2023-07-16 08:35:49 UTC
From:
To:
Control: forwarded -1 https://github.com/Perl/perl5/issues/21240

Thanks for the report.

This changed with

https://github.com/Perl/perl5/commit/80c1f1e45e8ef8c27d170fae7ade41971fe20218

which went upstream in 5.37.4. We backported it for 5.36 to fix #1016369 .

I've forwarded it upstream as https://github.com/Perl/perl5/issues/21240

#1040947#17
Date:
2023-07-17 05:17:19 UTC
From:
To:
Upstream says it's a direct consequence of fixing #1016369 so
the earlier behaviour of reading after EOF was a bug.

You need to clear the EOF flag by calling $rd->clearerr() or
seek($rd, 0, SEEK_CUR) to get the appended lines.

#1040947#22
Date:
2023-07-17 06:51:25 UTC
From:
To:
Niko Tyni <ntyni@debian.org> wrote:

+Cc Ian Jackson who reported #1016369

Bug #1016369 was reported for an issue which went unnoticed for
years (or decades, even?).  I hit this new bug within minutes of
upgrading to bookworm.

Both can be data loss bugs, but checking a log file which is
being written to by another process is a much more common
occurence than FS failures[1] (or attempting readline on a
directory (as given in the #1016369 example))

Thus I expect there's far more people negatively affected by
this bug than there were for #1016369.

Since this is Perl and TIMTOWTDI, I've never used IO::Handle->error;
instead I always check defined-ness on each critical return value and
also enable Perl warnings to catch undefined return values.
I've never used `eof' checks, either; checking `chomp' result
can ensure proper termination of lines to detect truncated reads.

When there's hardware (or network FS) failure; errors tend to
get very loud anyways with the system becoming unusable, console
spew, read-only remount, etc; so the error checking done via
Perl is often redundant in that case.


[1] yes, my early (by my standards) upgrade to bookworm was triggered
    by an SSD failure, but SSD failures aren't a common occurence
    compared to tailing a log file.

#1040947#27
Date:
2023-07-17 13:56:22 UTC
From:
To:
Hi.  I'm sorry that something I had a hand in is causing you an
inconvenience.

I'm afraid it's not clear to me what "working" and "non-working"
behaviour from your example program is.  I don't feel I can reply
comprehensively, so I will comment on some of the details in your
message.

Eric Wong writes ("Re: Bug#1040947: perl: readline fails to detect updated file"):

AFAICT you are saying that the fix to #1016369 broke a program which
was tailing a logfile.  I agree that one should be able to tail a
logfile in perl.  I don't think I have a complete opinion about
precisely what set of calls ought to be used to do that, but I would
expect them to mirror the calls needed in C with stdio.

AFIACT you are saying that you have always treated an undef value
from line-reading operations as EOF, and never checked for error.
I think that is erroneous.

That IO errors are rare doesn't mean they oughtn't to be checked for.
Reliable software must check for IO errors and not assume that undef
means EOF.

I believe perl's autodie gets this wrong, which is very unfortunate.

I don't think this is the right tradeoff calculus.

*With* the fix to #1016369 it is *possible* to write a reliable
program, but soee buggy programs lose data more often.

*Without* the fix to #1016369 it is completely impossible to write a
reliable program.

Having said all that, I don't see why the *eof* indicator ought to
have to persist.  It is only the *errors* that mustn't get lost.  So I
think it might be possible for perl to have behaviour that would
make it possible to write reliable programs, which still helping buggy
programs fail less often.

But, even if that's possible, I'm not sure that it's a good idea.
Buggy programs that lose data only in exceptional error conditions are
a menace.  Much better to make such buggy programs malfunction all the
time - then they will be found and fixed.

Thanks for your attention.

Ian.

#1040947#32
Date:
2023-07-18 01:23:51 UTC
From:
To:
Ian Jackson <ijackson@chiark.greenend.org.uk> wrote:

With each iteration of the loop in my example, the file size
increases as shown by `-s', yet readline isn't returning any
data after it sees a transient EOF.

Right, and C stdio.h is similarly tricky when it comes to
properly dealing with errors, too.  I often ended up using
unistd.h read(2) or Perl sysread directly for stuff I really
care about; combined with checking stat(2) st_size to ensure
I've read everything.

Data I care about tends to have checksumming built into it's
data format (git objects/packs, gzipped texts/tarballs, FLAC audio)

Uncompressed log files are transient data that ceases to be
relevant after a short time.

Maybe so, though most of the reads I do are less critical than
writes.  A failed read means there's *already* lost data and
there's nothing one can do about it.

A failed write can be retried on a different FS or rolled back.

IME, write errors are far more common (but perhaps that's because
I have errors=remount-ro in all my fstabs)

In the case of an application's log file, the application is
already toast if there's any I/O error; thus any monitoring on
application-level log files would cease to be relevant.

Right, autodie doesn't appear to handle readline at all.

For reliable programs (e.g. file servers), it's required to
check expected vs actual bytes read; that pattern can be
applied regardless of #1016369.

Right; EOF indicators should be transient for regular files.
It's wrong to consider EOF a permanent condition on regular files.

This mentality of breaking imperfect-but-practically-working
code in favor of some perfect ideal is damaging to Perl (based
on my experience with changes to Ruby driving away users).


Fwiw, using `strace -P $PATH -e inject=syscall...' to inject
errors for certain paths, both gawk and mawk fail as expected
when it fails to read STDIN:

  echo hello >x # create file named `x'

  strace -P x -e inject=read:error=EIO gawk '{ print }' <x
  # exits with 2

However, Neither Perl 5.36 nor 5.32.1 detect EIO on STDIN:

  strace -P x -e inject=read:error=EIO perl -ane '{ print $_ }' <x
  # exits with 0 even on Perl 5.36 bookworm

At this point (given Perl's maturity); it's less surprising if
it kept it's lack of error detection in all cases.

#1040947#37
Date:
2023-07-18 13:22:22 UTC
From:
To:
Thanks for caring, but please take your arguments upstream.

It's them you need to convince if you want that change to be
reverted or amended.

#1040947#42
Date:
2023-07-19 03:55:22 UTC
From:
To:
Niko Tyni <ntyni@debian.org> wrote:

First off, my apologies to Ian that I made him feel uncomfortable.

I merely wanted to point out the severity of incompatible changes in
case someone from upstream sees my comments.

Unfortunately, upstream's use of a proprietary platform,
said platform's terms-of-service and JavaScript CAPTCHA are all
non-starters for somebody like me :<

Thanks.