From 68442e2d7876ffdc42ca1a5e2106954aef4c8c70 Mon Sep 17 00:00:00 2001 From: Hessam Mehr Date: Fri, 16 Oct 2015 12:44:39 -0400 Subject: [PATCH 1/3] Fixing #13559 with more limited impact. Performance should be identical to baseline. Fixed infinite loop in previous fix for #13559. Do not throw EOFError if buffer already contains n bytes. #13559 --- src/sys.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sys.c b/src/sys.c index 002be1a597af6..c76abbdef1e07 100644 --- a/src/sys.c +++ b/src/sys.c @@ -310,9 +310,13 @@ static void NORETURN throw_eof_error(void) DLLEXPORT uint64_t jl_ios_get_nbyte_int(ios_t *s, const size_t n) { assert(n <= 8); - size_t ret = ios_readprep(s, n); - if (ret < n) - throw_eof_error(); + size_t space, ret; + do { + space = s->size - s->bpos; + ret = ios_readprep(s, n); + if (space == ret && ret < n) + throw_eof_error(); + } while(ret < n); uint64_t x = 0; uint8_t *buf = (uint8_t*)&s->buf[s->bpos]; if (n == 8) { From 0a79189a1ea287586056dbafe55859bbe0a7ac97 Mon Sep 17 00:00:00 2001 From: Hessam Mehr Date: Fri, 16 Oct 2015 23:09:52 -0400 Subject: [PATCH 2/3] Unit test for #13559. Uses the qualified path to launch julia --- test/file.jl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/file.jl b/test/file.jl index ed3a385229bbd..d359eb7ace627 100644 --- a/test/file.jl +++ b/test/file.jl @@ -922,3 +922,25 @@ test_12992() test2_12992() test2_12992() test2_12992() + +# issue 13559 + +function test_13559() + fn = tempname() + run(`mkfifo $fn`) + # use subprocess to write 127 bytes to FIFO + writer_cmds = "x=open(\"$fn\", \"w\"); for i=1:127 write(x,0xaa); flush(x); sleep(0.1) end; close(x); quit()" + open(`$(Base.julia_cmd()) -e $writer_cmds`) + #quickly read FIFO, draining it and blocking but not failing with EOFError yet + r = open(fn, "r") + # 15 proper reads + for i=1:15 + @test read(r, Int64) == -6148914691236517206 + end + # last read should throw EOFError when FIFO closes, since there are only 7 bytes available. + @test_throws EOFError read(r, Int64) + close(r) + rm(fn) +end + +@unix_only test_13559() From 9ef294921425b0dc6e730294e8ebfef421561ad7 Mon Sep 17 00:00:00 2001 From: Hessam Mehr Date: Sat, 17 Oct 2015 20:45:24 -0700 Subject: [PATCH 3/3] Cross-platform test coverage for n-byte reads and throwing EOF on insufficient bytes read. --- test/file.jl | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/test/file.jl b/test/file.jl index d359eb7ace627..bd08ef3215f49 100644 --- a/test/file.jl +++ b/test/file.jl @@ -942,5 +942,51 @@ function test_13559() close(r) rm(fn) end - @unix_only test_13559() + +function test_read_nbyte() + fn = tempname() + # Write one byte. One byte read should work once + # but 2-byte read should throw EOFError. + f = open(fn, "w+") do f + write(f, 0x55) + flush(f) + seek(f, 0) + @test read(f, UInt8) == 0x55 + @test_throws EOFError read(f, UInt8) + seek(f, 0) + @test_throws EOFError read(f, UInt16) + end + # Write 2 more bytes. Now 2-byte read should work once + # but 4-byte read should fail with EOFError. + open(fn, "a+") do f + write(f, 0x4444) + flush(f) + seek(f, 0) + @test read(f, UInt16) == 0x4455 + @test_throws EOFError read(f, UInt16) + seek(f,0) + @test_throws EOFError read(f, UInt32) + end + # Write 4 more bytes. Now 4-byte read should work once + # but 8-byte read should fail with EOFError. + open(fn, "a+") do f + write(f, 0x33333333) + flush(f) + seek(f, 0) + @test read(f, UInt32) == 0x33444455 + @test_throws EOFError read(f, UInt32) + seek(f,0) + @test_throws EOFError read(f, UInt64) + end + # Writing one more byte should allow an 8-byte + # read to proceed. + open(fn, "a+") do f + write(f, 0x22) + flush(f) + seek(f, 0) + @test read(f, UInt64) == 0x2233333333444455 + end + rm(fn) +end +test_read_nbyte()