Commit e3144513cacff511fe7c9374ae4daabe4728b7b3
Workaround for Windows CE seek issue on a memory-mapped file
Platform: Windows CE 5 (Windows Mobile 5.x & 6.x)
Compiler: Visual Studio 2008; the issue is not compiler-related
Problem: on files larger than 4K opened in binary mode, ifstream::tellg()
does not return correct values. Short snippet demonstrates the issue:
=================================
std::ifstream in( filename, std::ios_base::in | std::ios_base::binary );
in.get();
std::streampos pos = in.tellg();
assert( pos == 1 );
=================================
Underlying problem: the sequence
- create mapping
- SetFilePosition( file, pos /* == file size */, FILE_BEGIN )
- first access to mapped page
- SetFilePosition( file, 0, FILE_CURRENT )
does not work as expected: last SetFilePosition() returns 4096 instead of
file size. If the first access to mapped page happens before the call to
SetFilePosition() that sets file pointer to EOF, everything works fine.
Workaround: in fstream_win32io.cpp, method
_Filebuf_base::_M_mmap() explicitly accesses the first page of the
mapping before calling _M_seek(). Note that with full & global
optimizations enabled, the optimizer is very aggressive and tends to cut
away expressions producing unused values (hence the assignment to a static
variable).
Issue discovered on Windows Mobile 6 (emulator) and later had it
reproduced on Windows Mobile 5.x on PPC-type hardware.
From the look of things it ought to be a problem in Windows CE 5 core
implementation. It's no idea if this is new for CE 5 or was
there before or whether M$ came around to fixing it in CE 6.
Patch tracker ID: 2941143
| |   |
| 575 | 575 | return result; |
| 576 | 576 | } |
| 577 | 577 | |
| #ifdef _STLP_WCE |
| inline void access_page_aux( void* p ) |
| { static char c = *static_cast<const char*>( p ); } |
| #endif |
| 578 | 582 | |
| 579 | 583 | // Attempts to memory-map len bytes of the current file, starting |
| 580 | 584 | // at position offset. Precondition: offset is a multiple of the |
| … | … | |
| 609 | 609 | __STATIC_CAST(DWORD, len)); |
| 610 | 610 | #endif |
| 611 | 611 | // check if mapping succeded and is usable |
| if (base == 0 || _M_seek(offset + len, ios_base::beg) < 0) { |
| #ifdef _STLP_WCE |
| /* Workaround for Windows CE 5 (Windows Mobile 5.x & 6.x): |
| SetFilePosition() returns wrong number before first read; |
| access_page_aux try to read. See patch tracker ID 2941143. |
| */ |
| if ( base == 0 || (access_page_aux(base), _M_seek(offset + len, ios_base::beg)) < 0 ) |
| #else |
| if ( base == 0 || _M_seek(offset + len, ios_base::beg) < 0 ) |
| #endif |
| { |
| 613 | 622 | this->_M_unmap(base, len); |
| 614 | 623 | base = 0; |
| 615 | 624 | } |