ntdll: Add helpers to lock the user output buffer during file reads.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2017-09-22 15:04:34 +02:00
parent a20c4e11df
commit 51d348c8c2
4 changed files with 55 additions and 15 deletions

View File

@ -1840,13 +1840,10 @@ static DWORD CALLBACK read_pipe( void *arg )
"%u: ConnectNamedPipe failed %u\n", args->index, GetLastError() );
success = ReadFile( args->pipe, args->base, args->size, &num_bytes, NULL );
todo_wine_if (!args->index)
{
ok( success, "%u: ReadFile failed %u\n", args->index, GetLastError() );
ok( num_bytes == sizeof(testdata), "%u: wrong number of bytes read %u\n", args->index, num_bytes );
ok( !memcmp( args->base, testdata, sizeof(testdata)),
"%u: didn't receive expected data\n", args->index );
}
return 0;
}
@ -2056,22 +2053,16 @@ static void test_write_watch(void)
num_bytes = 0;
success = GetOverlappedResult( readpipe, &overlapped, &num_bytes, TRUE );
todo_wine_if (!i)
{
ok( success, "%u: GetOverlappedResult failed %u\n", i, GetLastError() );
ok( num_bytes == sizeof(testdata), "%u: wrong number of bytes read %u\n", i, num_bytes );
ok( !memcmp( base, testdata, sizeof(testdata)), "%u: didn't receive expected data\n", i );
}
count = 64;
memset( results, 0, sizeof(results) );
ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
ok( !ret, "%u: GetWriteWatch failed %u\n", i, GetLastError() );
todo_wine_if (!i)
{
ok( count == 1, "%u: wrong count %lu\n", i, count );
ok( results[0] == base, "%u: wrong result %p\n", i, results[0] );
}
CloseHandle( readpipe );
CloseHandle( writepipe );
@ -2120,11 +2111,8 @@ static void test_write_watch(void)
memset( results, 0, sizeof(results) );
ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
ok( !ret, "%u: GetWriteWatch failed %u\n", i, GetLastError() );
todo_wine_if (!i)
{
ok( count == 1, "%u: wrong count %lu\n", i, count );
ok( results[0] == base, "%u: wrong result %p\n", i, results[0] );
}
CloseHandle( readpipe );
CloseHandle( writepipe );

View File

@ -517,7 +517,7 @@ static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb, NTSTAT
&needs_close, NULL, NULL )))
break;
result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
result = virtual_locked_read(fd, &fileio->buffer[fileio->already], fileio->count-fileio->already);
if (needs_close) close( fd );
if (result < 0)
@ -869,7 +869,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
{
/* async I/O doesn't make sense on regular files */
while ((result = pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
while ((result = virtual_locked_pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
{
if (errno != EINTR)
{
@ -911,7 +911,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
for (;;)
{
if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
if ((result = virtual_locked_read( unix_handle, (char *)buffer + total, length - total )) >= 0)
{
total += result;
if (!result || total == length)

View File

@ -171,6 +171,8 @@ extern BOOL virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN;
extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
extern ssize_t virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN;
extern ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) DECLSPEC_HIDDEN;
extern BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
extern BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;

View File

@ -1863,6 +1863,56 @@ unsigned int virtual_locked_server_call( void *req_ptr )
}
/***********************************************************************
* virtual_locked_read
*/
ssize_t virtual_locked_read( int fd, void *addr, size_t size )
{
sigset_t sigset;
BOOL has_write_watch = FALSE;
int err = EFAULT;
ssize_t ret = read( fd, addr, size );
if (ret != -1 || errno != EFAULT) return ret;
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (!check_write_access( addr, size, &has_write_watch ))
{
ret = read( fd, addr, size );
err = errno;
if (has_write_watch) update_write_watches( addr, size, max( 0, ret ));
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
errno = err;
return ret;
}
/***********************************************************************
* virtual_locked_pread
*/
ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset )
{
sigset_t sigset;
BOOL has_write_watch = FALSE;
int err = EFAULT;
ssize_t ret = pread( fd, addr, size, offset );
if (ret != -1 || errno != EFAULT) return ret;
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (!check_write_access( addr, size, &has_write_watch ))
{
ret = pread( fd, addr, size, offset );
err = errno;
if (has_write_watch) update_write_watches( addr, size, max( 0, ret ));
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
errno = err;
return ret;
}
/***********************************************************************
* virtual_is_valid_code_address