| /* |
| * Win32 virtual memory functions |
| * |
| * Copyright 1997 Alexandre Julliard |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <fcntl.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| #include "ntstatus.h" |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "winreg.h" |
| #include "winternl.h" |
| #include "winerror.h" |
| #include "wine/exception.h" |
| #include "excpt.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(virtual); |
| |
| static unsigned int page_size; |
| |
| /* filter for page-fault exceptions */ |
| static WINE_EXCEPTION_FILTER(page_fault) |
| { |
| if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) |
| return EXCEPTION_EXECUTE_HANDLER; |
| return EXCEPTION_CONTINUE_SEARCH; |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualAlloc (KERNEL32.@) |
| * Reserves or commits a region of pages in virtual address space |
| * |
| * RETURNS |
| * Base address of allocated region of pages |
| * NULL: Failure |
| */ |
| LPVOID WINAPI VirtualAlloc( |
| LPVOID addr, /* [in] Address of region to reserve or commit */ |
| SIZE_T size, /* [in] Size of region */ |
| DWORD type, /* [in] Type of allocation */ |
| DWORD protect)/* [in] Type of access protection */ |
| { |
| return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect ); |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualAllocEx (KERNEL32.@) |
| * |
| * Seems to be just as VirtualAlloc, but with process handle. |
| */ |
| LPVOID WINAPI VirtualAllocEx( |
| HANDLE hProcess, /* [in] Handle of process to do mem operation */ |
| LPVOID addr, /* [in] Address of region to reserve or commit */ |
| SIZE_T size, /* [in] Size of region */ |
| DWORD type, /* [in] Type of allocation */ |
| DWORD protect ) /* [in] Type of access protection */ |
| { |
| LPVOID ret; |
| NTSTATUS status; |
| |
| if ((status = NtAllocateVirtualMemory( hProcess, &ret, addr, &size, type, protect ))) |
| { |
| SetLastError( RtlNtStatusToDosError(status) ); |
| ret = NULL; |
| } |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualFree (KERNEL32.@) |
| * Release or decommits a region of pages in virtual address space. |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI VirtualFree( |
| LPVOID addr, /* [in] Address of region of committed pages */ |
| SIZE_T size, /* [in] Size of region */ |
| DWORD type /* [in] Type of operation */ |
| ) { |
| return VirtualFreeEx( GetCurrentProcess(), addr, size, type ); |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualFreeEx (KERNEL32.@) |
| * Release or decommits a region of pages in virtual address space. |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, SIZE_T size, DWORD type ) |
| { |
| NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type ); |
| if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| return !status; |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualLock (KERNEL32.@) |
| * Locks the specified region of virtual address space |
| * |
| * NOTE |
| * Always returns TRUE |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */ |
| SIZE_T size ) /* [in] Number of bytes in range to lock */ |
| { |
| NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ); |
| if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| return !status; |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualUnlock (KERNEL32.@) |
| * Unlocks a range of pages in the virtual address space |
| * |
| * NOTE |
| * Always returns TRUE |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */ |
| SIZE_T size ) /* [in] Number of bytes in range */ |
| { |
| NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ); |
| if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| return !status; |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualProtect (KERNEL32.@) |
| * Changes the access protection on a region of committed pages |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI VirtualProtect( |
| LPVOID addr, /* [in] Address of region of committed pages */ |
| SIZE_T size, /* [in] Size of region */ |
| DWORD new_prot, /* [in] Desired access protection */ |
| LPDWORD old_prot /* [out] Address of variable to get old protection */ |
| ) { |
| return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot ); |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualProtectEx (KERNEL32.@) |
| * Changes the access protection on a region of committed pages in the |
| * virtual address space of a specified process |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI VirtualProtectEx( |
| HANDLE process, /* [in] Handle of process */ |
| LPVOID addr, /* [in] Address of region of committed pages */ |
| SIZE_T size, /* [in] Size of region */ |
| DWORD new_prot, /* [in] Desired access protection */ |
| LPDWORD old_prot /* [out] Address of variable to get old protection */ ) |
| { |
| NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot ); |
| if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| return !status; |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualQuery (KERNEL32.@) |
| * Provides info about a range of pages in virtual address space |
| * |
| * RETURNS |
| * Number of bytes returned in information buffer |
| * or 0 if addr is >= 0xc0000000 (kernel space). |
| */ |
| SIZE_T WINAPI VirtualQuery( |
| LPCVOID addr, /* [in] Address of region */ |
| PMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */ |
| SIZE_T len /* [in] Size of buffer */ |
| ) { |
| return VirtualQueryEx( GetCurrentProcess(), addr, info, len ); |
| } |
| |
| |
| /*********************************************************************** |
| * VirtualQueryEx (KERNEL32.@) |
| * Provides info about a range of pages in virtual address space of a |
| * specified process |
| * |
| * RETURNS |
| * Number of bytes returned in information buffer |
| */ |
| SIZE_T WINAPI VirtualQueryEx( |
| HANDLE process, /* [in] Handle of process */ |
| LPCVOID addr, /* [in] Address of region */ |
| PMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */ |
| SIZE_T len /* [in] Size of buffer */ ) |
| { |
| DWORD ret; |
| NTSTATUS status; |
| |
| if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret ))) |
| { |
| SetLastError( RtlNtStatusToDosError(status) ); |
| ret = 0; |
| } |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * CreateFileMappingA (KERNEL32.@) |
| * Creates a named or unnamed file-mapping object for the specified file |
| * |
| * RETURNS |
| * Handle: Success |
| * 0: Mapping object does not exist |
| * NULL: Failure |
| */ |
| HANDLE WINAPI CreateFileMappingA( |
| HANDLE hFile, /* [in] Handle of file to map */ |
| SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/ |
| DWORD protect, /* [in] Protection for mapping object */ |
| DWORD size_high, /* [in] High-order 32 bits of object size */ |
| DWORD size_low, /* [in] Low-order 32 bits of object size */ |
| LPCSTR name /* [in] Name of file-mapping object */ ) |
| { |
| WCHAR buffer[MAX_PATH]; |
| |
| if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL ); |
| |
| if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) |
| { |
| SetLastError( ERROR_FILENAME_EXCED_RANGE ); |
| return 0; |
| } |
| return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreateFileMappingW (KERNEL32.@) |
| * See CreateFileMappingA |
| */ |
| HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, |
| DWORD protect, DWORD size_high, |
| DWORD size_low, LPCWSTR name ) |
| { |
| static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE; |
| |
| HANDLE ret; |
| OBJECT_ATTRIBUTES attr; |
| UNICODE_STRING nameW; |
| NTSTATUS status; |
| DWORD access, sec_type; |
| LARGE_INTEGER size; |
| |
| attr.Length = sizeof(attr); |
| attr.RootDirectory = 0; |
| attr.ObjectName = NULL; |
| attr.Attributes = (sa && sa->bInheritHandle) ? OBJ_INHERIT : 0; |
| attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL; |
| attr.SecurityQualityOfService = NULL; |
| |
| if (name) |
| { |
| RtlInitUnicodeString( &nameW, name ); |
| attr.ObjectName = &nameW; |
| } |
| |
| sec_type = protect & sec_flags; |
| protect &= ~sec_flags; |
| if (!sec_type) sec_type = SEC_COMMIT; |
| |
| switch(protect) |
| { |
| case 0: |
| protect = PAGE_READONLY; /* Win9x compatibility */ |
| /* fall through */ |
| case PAGE_READONLY: |
| case PAGE_WRITECOPY: |
| access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ; |
| break; |
| case PAGE_READWRITE: |
| access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE; |
| break; |
| default: |
| SetLastError( ERROR_INVALID_PARAMETER ); |
| return 0; |
| } |
| |
| if (hFile == INVALID_HANDLE_VALUE) |
| { |
| hFile = 0; |
| if (!size_low && !size_high) |
| { |
| SetLastError( ERROR_INVALID_PARAMETER ); |
| return 0; |
| } |
| } |
| |
| size.u.LowPart = size_low; |
| size.u.HighPart = size_high; |
| |
| status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile ); |
| SetLastError( RtlNtStatusToDosError(status) ); |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * OpenFileMappingA (KERNEL32.@) |
| * Opens a named file-mapping object. |
| * |
| * RETURNS |
| * Handle: Success |
| * NULL: Failure |
| */ |
| HANDLE WINAPI OpenFileMappingA( |
| DWORD access, /* [in] Access mode */ |
| BOOL inherit, /* [in] Inherit flag */ |
| LPCSTR name ) /* [in] Name of file-mapping object */ |
| { |
| WCHAR buffer[MAX_PATH]; |
| |
| if (!name) return OpenFileMappingW( access, inherit, NULL ); |
| |
| if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) |
| { |
| SetLastError( ERROR_FILENAME_EXCED_RANGE ); |
| return 0; |
| } |
| return OpenFileMappingW( access, inherit, buffer ); |
| } |
| |
| |
| /*********************************************************************** |
| * OpenFileMappingW (KERNEL32.@) |
| * See OpenFileMappingA |
| */ |
| HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name) |
| { |
| OBJECT_ATTRIBUTES attr; |
| UNICODE_STRING nameW; |
| HANDLE ret; |
| NTSTATUS status; |
| |
| if (!name) |
| { |
| SetLastError( ERROR_INVALID_PARAMETER ); |
| return 0; |
| } |
| attr.Length = sizeof(attr); |
| attr.RootDirectory = 0; |
| attr.ObjectName = &nameW; |
| attr.Attributes = inherit ? OBJ_INHERIT : 0; |
| attr.SecurityDescriptor = NULL; |
| attr.SecurityQualityOfService = NULL; |
| RtlInitUnicodeString( &nameW, name ); |
| |
| if (access == FILE_MAP_COPY) access = FILE_MAP_READ; |
| |
| if ((status = NtOpenSection( &ret, access, &attr ))) |
| { |
| SetLastError( RtlNtStatusToDosError(status) ); |
| ret = 0; |
| } |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * MapViewOfFile (KERNEL32.@) |
| * Maps a view of a file into the address space |
| * |
| * RETURNS |
| * Starting address of mapped view |
| * NULL: Failure |
| */ |
| LPVOID WINAPI MapViewOfFile( |
| HANDLE mapping, /* [in] File-mapping object to map */ |
| DWORD access, /* [in] Access mode */ |
| DWORD offset_high, /* [in] High-order 32 bits of file offset */ |
| DWORD offset_low, /* [in] Low-order 32 bits of file offset */ |
| SIZE_T count /* [in] Number of bytes to map */ |
| ) { |
| return MapViewOfFileEx( mapping, access, offset_high, |
| offset_low, count, NULL ); |
| } |
| |
| |
| /*********************************************************************** |
| * MapViewOfFileEx (KERNEL32.@) |
| * Maps a view of a file into the address space |
| * |
| * RETURNS |
| * Starting address of mapped view |
| * NULL: Failure |
| */ |
| LPVOID WINAPI MapViewOfFileEx( |
| HANDLE handle, /* [in] File-mapping object to map */ |
| DWORD access, /* [in] Access mode */ |
| DWORD offset_high, /* [in] High-order 32 bits of file offset */ |
| DWORD offset_low, /* [in] Low-order 32 bits of file offset */ |
| SIZE_T count, /* [in] Number of bytes to map */ |
| LPVOID addr /* [in] Suggested starting address for mapped view */ |
| ) { |
| NTSTATUS status; |
| LARGE_INTEGER offset; |
| ULONG protect; |
| |
| offset.u.LowPart = offset_low; |
| offset.u.HighPart = offset_high; |
| |
| if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE; |
| else if (access & FILE_MAP_READ) protect = PAGE_READONLY; |
| else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY; |
| else protect = PAGE_NOACCESS; |
| |
| if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset, |
| &count, ViewShare, 0, protect ))) |
| { |
| SetLastError( RtlNtStatusToDosError(status) ); |
| addr = NULL; |
| } |
| return addr; |
| } |
| |
| |
| /*********************************************************************** |
| * UnmapViewOfFile (KERNEL32.@) |
| * Unmaps a mapped view of a file. |
| * |
| * NOTES |
| * Should addr be an LPCVOID? |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */ |
| { |
| NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr ); |
| if (status) SetLastError( RtlNtStatusToDosError(status) ); |
| return !status; |
| } |
| |
| |
| /*********************************************************************** |
| * FlushViewOfFile (KERNEL32.@) |
| * Writes to the disk a byte range within a mapped view of a file |
| * |
| * RETURNS |
| * TRUE: Success |
| * FALSE: Failure |
| */ |
| BOOL WINAPI FlushViewOfFile( LPCVOID base, /* [in] Start address of byte range to flush */ |
| SIZE_T size ) /* [in] Number of bytes in range */ |
| { |
| NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 ); |
| if (status) |
| { |
| if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS; |
| else SetLastError( RtlNtStatusToDosError(status) ); |
| } |
| return !status; |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadReadPtr (KERNEL32.@) |
| * |
| * RETURNS |
| * FALSE: Process has read access to entire block |
| * TRUE: Otherwise |
| */ |
| BOOL WINAPI IsBadReadPtr( |
| LPCVOID ptr, /* [in] Address of memory block */ |
| UINT size ) /* [in] Size of block */ |
| { |
| if (!size) return FALSE; /* handle 0 size case w/o reference */ |
| if (!page_size) page_size = getpagesize(); |
| __TRY |
| { |
| volatile const char *p = ptr; |
| char dummy; |
| UINT count = size; |
| |
| while (count > page_size) |
| { |
| dummy = *p; |
| p += page_size; |
| count -= page_size; |
| } |
| dummy = p[0]; |
| dummy = p[count - 1]; |
| } |
| __EXCEPT(page_fault) { return TRUE; } |
| __ENDTRY |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadWritePtr (KERNEL32.@) |
| * |
| * RETURNS |
| * FALSE: Process has write access to entire block |
| * TRUE: Otherwise |
| */ |
| BOOL WINAPI IsBadWritePtr( |
| LPVOID ptr, /* [in] Address of memory block */ |
| UINT size ) /* [in] Size of block in bytes */ |
| { |
| if (!size) return FALSE; /* handle 0 size case w/o reference */ |
| if (!page_size) page_size = getpagesize(); |
| __TRY |
| { |
| volatile char *p = ptr; |
| UINT count = size; |
| |
| while (count > page_size) |
| { |
| *p |= 0; |
| p += page_size; |
| count -= page_size; |
| } |
| p[0] |= 0; |
| p[count - 1] |= 0; |
| } |
| __EXCEPT(page_fault) { return TRUE; } |
| __ENDTRY |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadHugeReadPtr (KERNEL32.@) |
| * RETURNS |
| * FALSE: Process has read access to entire block |
| * TRUE: Otherwise |
| */ |
| BOOL WINAPI IsBadHugeReadPtr( |
| LPCVOID ptr, /* [in] Address of memory block */ |
| UINT size /* [in] Size of block */ |
| ) { |
| return IsBadReadPtr( ptr, size ); |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadHugeWritePtr (KERNEL32.@) |
| * RETURNS |
| * FALSE: Process has write access to entire block |
| * TRUE: Otherwise |
| */ |
| BOOL WINAPI IsBadHugeWritePtr( |
| LPVOID ptr, /* [in] Address of memory block */ |
| UINT size /* [in] Size of block */ |
| ) { |
| return IsBadWritePtr( ptr, size ); |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadCodePtr (KERNEL32.@) |
| * |
| * RETURNS |
| * FALSE: Process has read access to specified memory |
| * TRUE: Otherwise |
| */ |
| BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */ |
| { |
| return IsBadReadPtr( ptr, 1 ); |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadStringPtrA (KERNEL32.@) |
| * |
| * RETURNS |
| * FALSE: Read access to all bytes in string |
| * TRUE: Else |
| */ |
| BOOL WINAPI IsBadStringPtrA( |
| LPCSTR str, /* [in] Address of string */ |
| UINT max ) /* [in] Maximum size of string */ |
| { |
| __TRY |
| { |
| volatile const char *p = str; |
| while (p != str + max) if (!*p++) break; |
| } |
| __EXCEPT(page_fault) { return TRUE; } |
| __ENDTRY |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * IsBadStringPtrW (KERNEL32.@) |
| * See IsBadStringPtrA |
| */ |
| BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max ) |
| { |
| __TRY |
| { |
| volatile const WCHAR *p = str; |
| while (p != str + max) if (!*p++) break; |
| } |
| __EXCEPT(page_fault) { return TRUE; } |
| __ENDTRY |
| return FALSE; |
| } |