From 2555efadbc1f8124448fcd73c1c208f3abe430e5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 17 Jun 2021 11:37:51 +0200 Subject: [PATCH] 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`. Co-authored-by: Nikita Popov Closes GH-7158. --- NEWS | 4 +++ ext/standard/tests/file/bug81145.phpt | 48 +++++++++++++++++++++++++++ main/streams/plain_wrapper.c | 11 +++--- 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 ext/standard/tests/file/bug81145.phpt diff --git a/NEWS b/NEWS index e40545a8f75..fcbc083fe9c 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 7.4.22 +- Core: + . Fixed bug #81145 (copy() and stream_copy_to_stream() fail for +4GB files). + (cmb, Nikita) + - Intl: . Fixed bug #72809 (Locale::lookup() wrong result with canonicalize option). (cmb) diff --git a/ext/standard/tests/file/bug81145.phpt b/ext/standard/tests/file/bug81145.phpt new file mode 100644 index 00000000000..2f12d9eee81 --- /dev/null +++ b/ext/standard/tests/file/bug81145.phpt @@ -0,0 +1,48 @@ +--TEST-- +Bug #81145 (copy() and stream_copy_to_stream() fail for +4GB files) +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +Identical diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index d187c23a593..4d10e688b5f 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) { @@ -838,8 +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; + 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 */ @@ -847,7 +850,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 */