From d28d2faed76ee111500346f80f2210dc292b2613 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 16 Jun 2021 13:15:06 +0200 Subject: [PATCH 1/5] Fix #81145: copy() and stream_copy_to_stream() fail for +4GB files When mapping the file, we need to pass the proper `dwFileOffsetHigh` instead of `0`. --- main/streams/plain_wrapper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index d187c23a59316..539181f2d9989 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -770,7 +770,7 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void { php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam; HANDLE hfile = (HANDLE)_get_osfhandle(fd); - DWORD prot, acc, loffs = 0, delta = 0; + DWORD prot, acc, loffs = 0, hoffs = 0, delta = 0; LARGE_INTEGER file_size; switch (value) { @@ -840,6 +840,7 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void gran = info.dwAllocationGranularity; loffs = ((DWORD)range->offset / gran) * gran; delta = (DWORD)range->offset - loffs; + hoffs = range->offset >> 32; } /* MapViewOfFile()ing zero bytes would map to the end of the file; match *nix behavior instead */ @@ -847,7 +848,7 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void return PHP_STREAM_OPTION_RETURN_ERR; } - data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, 0, loffs, range->length + delta); + data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, hoffs, loffs, range->length + delta); if (data->last_mapped_addr) { /* give them back the address of the start offset they requested */ From 8d6651c0b59fad3a759df95561598a7ae0020384 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 16 Jun 2021 15:24:45 +0200 Subject: [PATCH 2/5] Add regression test --- ext/standard/tests/file/bug81145.phpt | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 ext/standard/tests/file/bug81145.phpt diff --git a/ext/standard/tests/file/bug81145.phpt b/ext/standard/tests/file/bug81145.phpt new file mode 100644 index 0000000000000..8cd2af8fa27be --- /dev/null +++ b/ext/standard/tests/file/bug81145.phpt @@ -0,0 +1,42 @@ +--TEST-- +Bug #81145 (copy() and stream_copy_to_stream() fail for +4GB files) +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +Identical From 58e72db085b9e17ece3045c67c3c8ef1fb643b8a Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 16 Jun 2021 16:12:19 +0200 Subject: [PATCH 3/5] Mark test as slow and avoid fail if fallocate isn't available --- ext/standard/tests/file/bug81145.phpt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ext/standard/tests/file/bug81145.phpt b/ext/standard/tests/file/bug81145.phpt index 8cd2af8fa27be..b1ca045cfe7a5 100644 --- a/ext/standard/tests/file/bug81145.phpt +++ b/ext/standard/tests/file/bug81145.phpt @@ -2,7 +2,12 @@ Bug #81145 (copy() and stream_copy_to_stream() fail for +4GB files) --SKIPIF-- --FILE-- Date: Wed, 16 Jun 2021 17:43:01 +0200 Subject: [PATCH 4/5] Refactor code for better readability Co-authored-by: Nikita Popov --- main/streams/plain_wrapper.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 539181f2d9989..4d10e688b5f76 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -838,9 +838,11 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void GetSystemInfo(&info); gran = info.dwAllocationGranularity; - loffs = ((DWORD)range->offset / gran) * gran; - delta = (DWORD)range->offset - loffs; - hoffs = range->offset >> 32; + ZEND_ASSERT(gran != 0 && (gran & (gran - 1)) == 0); + size_t rounded_offset = (range->offset / gran) * gran; + delta = range->offset - rounded_offset; + loffs = (DWORD)rounded_offset; + hoffs = (DWORD)(rounded_offset >> 32); } /* MapViewOfFile()ing zero bytes would map to the end of the file; match *nix behavior instead */ From a3566e72da29776005792eb3b05f8c446053844b Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 17 Jun 2021 11:37:51 +0200 Subject: [PATCH 5/5] Skip test on 32bit platforms We can't copy files > 4GB there, anyway. --- ext/standard/tests/file/bug81145.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/standard/tests/file/bug81145.phpt b/ext/standard/tests/file/bug81145.phpt index b1ca045cfe7a5..2f12d9eee81da 100644 --- a/ext/standard/tests/file/bug81145.phpt +++ b/ext/standard/tests/file/bug81145.phpt @@ -3,6 +3,7 @@ Bug #81145 (copy() and stream_copy_to_stream() fail for +4GB files) --SKIPIF--