Start using the exported TEB structure from winternl.h where
[wine] / memory / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "winbase.h"
35 #include "winnls.h"
36 #include "winternl.h"
37 #include "winerror.h"
38 #include "wine/exception.h"
39 #include "excpt.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(virtual);
43
44 static unsigned int page_size;
45
46 /* filter for page-fault exceptions */
47 static WINE_EXCEPTION_FILTER(page_fault)
48 {
49     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
50         return EXCEPTION_EXECUTE_HANDLER;
51     return EXCEPTION_CONTINUE_SEARCH;
52 }
53
54
55 /***********************************************************************
56  *             VirtualAlloc   (KERNEL32.@)
57  * Reserves or commits a region of pages in virtual address space
58  *
59  * RETURNS
60  *      Base address of allocated region of pages
61  *      NULL: Failure
62  */
63 LPVOID WINAPI VirtualAlloc(
64               LPVOID addr,  /* [in] Address of region to reserve or commit */
65               SIZE_T size,  /* [in] Size of region */
66               DWORD type,   /* [in] Type of allocation */
67               DWORD protect)/* [in] Type of access protection */
68 {
69     return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
70 }
71
72
73 /***********************************************************************
74  *             VirtualAllocEx   (KERNEL32.@)
75  *
76  * Seems to be just as VirtualAlloc, but with process handle.
77  */
78 LPVOID WINAPI VirtualAllocEx(
79               HANDLE hProcess, /* [in] Handle of process to do mem operation */
80               LPVOID addr,     /* [in] Address of region to reserve or commit */
81               SIZE_T size,     /* [in] Size of region */
82               DWORD type,      /* [in] Type of allocation */
83               DWORD protect )  /* [in] Type of access protection */
84 {
85     LPVOID ret;
86     NTSTATUS status;
87
88     if ((status = NtAllocateVirtualMemory( hProcess, &ret, addr, &size, type, protect )))
89     {
90         SetLastError( RtlNtStatusToDosError(status) );
91         ret = NULL;
92     }
93     return ret;
94 }
95
96
97 /***********************************************************************
98  *             VirtualFree   (KERNEL32.@)
99  * Release or decommits a region of pages in virtual address space.
100  *
101  * RETURNS
102  *      TRUE: Success
103  *      FALSE: Failure
104  */
105 BOOL WINAPI VirtualFree(
106               LPVOID addr, /* [in] Address of region of committed pages */
107               SIZE_T size, /* [in] Size of region */
108               DWORD type   /* [in] Type of operation */
109 ) {
110     return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
111 }
112
113
114 /***********************************************************************
115  *             VirtualFreeEx   (KERNEL32.@)
116  * Release or decommits a region of pages in virtual address space.
117  *
118  * RETURNS
119  *      TRUE: Success
120  *      FALSE: Failure
121  */
122 BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, SIZE_T size, DWORD type )
123 {
124     NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type );
125     if (status) SetLastError( RtlNtStatusToDosError(status) );
126     return !status;
127 }
128
129
130 /***********************************************************************
131  *             VirtualLock   (KERNEL32.@)
132  * Locks the specified region of virtual address space
133  *
134  * NOTE
135  *      Always returns TRUE
136  *
137  * RETURNS
138  *      TRUE: Success
139  *      FALSE: Failure
140  */
141 BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */
142                          SIZE_T size ) /* [in] Number of bytes in range to lock */
143 {
144     NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
145     if (status) SetLastError( RtlNtStatusToDosError(status) );
146     return !status;
147 }
148
149
150 /***********************************************************************
151  *             VirtualUnlock   (KERNEL32.@)
152  * Unlocks a range of pages in the virtual address space
153  *
154  * NOTE
155  *      Always returns TRUE
156  *
157  * RETURNS
158  *      TRUE: Success
159  *      FALSE: Failure
160  */
161 BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */
162                            SIZE_T size ) /* [in] Number of bytes in range */
163 {
164     NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
165     if (status) SetLastError( RtlNtStatusToDosError(status) );
166     return !status;
167 }
168
169
170 /***********************************************************************
171  *             VirtualProtect   (KERNEL32.@)
172  * Changes the access protection on a region of committed pages
173  *
174  * RETURNS
175  *      TRUE: Success
176  *      FALSE: Failure
177  */
178 BOOL WINAPI VirtualProtect(
179               LPVOID addr,     /* [in] Address of region of committed pages */
180               SIZE_T size,     /* [in] Size of region */
181               DWORD new_prot,  /* [in] Desired access protection */
182               LPDWORD old_prot /* [out] Address of variable to get old protection */
183 ) {
184     return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
185 }
186
187
188 /***********************************************************************
189  *             VirtualProtectEx   (KERNEL32.@)
190  * Changes the access protection on a region of committed pages in the
191  * virtual address space of a specified process
192  *
193  * RETURNS
194  *      TRUE: Success
195  *      FALSE: Failure
196  */
197 BOOL WINAPI VirtualProtectEx(
198               HANDLE process,  /* [in]  Handle of process */
199               LPVOID addr,     /* [in]  Address of region of committed pages */
200               SIZE_T size,     /* [in]  Size of region */
201               DWORD new_prot,  /* [in]  Desired access protection */
202               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
203 {
204     NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot );
205     if (status) SetLastError( RtlNtStatusToDosError(status) );
206     return !status;
207 }
208
209
210 /***********************************************************************
211  *             VirtualQuery   (KERNEL32.@)
212  * Provides info about a range of pages in virtual address space
213  *
214  * RETURNS
215  *      Number of bytes returned in information buffer
216  *      or 0 if addr is >= 0xc0000000 (kernel space).
217  */
218 SIZE_T WINAPI VirtualQuery(
219              LPCVOID addr,                    /* [in]  Address of region */
220              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
221              SIZE_T len                       /* [in]  Size of buffer */
222 ) {
223     return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
224 }
225
226
227 /***********************************************************************
228  *             VirtualQueryEx   (KERNEL32.@)
229  * Provides info about a range of pages in virtual address space of a
230  * specified process
231  *
232  * RETURNS
233  *      Number of bytes returned in information buffer
234  */
235 SIZE_T WINAPI VirtualQueryEx(
236              HANDLE process,                  /* [in] Handle of process */
237              LPCVOID addr,                    /* [in] Address of region */
238              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
239              SIZE_T len                       /* [in] Size of buffer */ )
240 {
241     DWORD ret;
242     NTSTATUS status;
243
244     if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
245     {
246         SetLastError( RtlNtStatusToDosError(status) );
247         ret = 0;
248     }
249     return ret;
250 }
251
252
253 /***********************************************************************
254  *             CreateFileMappingA   (KERNEL32.@)
255  * Creates a named or unnamed file-mapping object for the specified file
256  *
257  * RETURNS
258  *      Handle: Success
259  *      0: Mapping object does not exist
260  *      NULL: Failure
261  */
262 HANDLE WINAPI CreateFileMappingA(
263                 HANDLE hFile,   /* [in] Handle of file to map */
264                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
265                 DWORD protect,   /* [in] Protection for mapping object */
266                 DWORD size_high, /* [in] High-order 32 bits of object size */
267                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
268                 LPCSTR name      /* [in] Name of file-mapping object */ )
269 {
270     WCHAR buffer[MAX_PATH];
271
272     if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
273
274     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
275     {
276         SetLastError( ERROR_FILENAME_EXCED_RANGE );
277         return 0;
278     }
279     return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
280 }
281
282
283 /***********************************************************************
284  *             CreateFileMappingW   (KERNEL32.@)
285  * See CreateFileMappingA
286  */
287 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
288                                   DWORD protect, DWORD size_high,
289                                   DWORD size_low, LPCWSTR name )
290 {
291     static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
292
293     HANDLE ret;
294     OBJECT_ATTRIBUTES attr;
295     UNICODE_STRING nameW;
296     NTSTATUS status;
297     DWORD access, sec_type;
298     LARGE_INTEGER size;
299
300     attr.Length                   = sizeof(attr);
301     attr.RootDirectory            = 0;
302     attr.ObjectName               = NULL;
303     attr.Attributes               = (sa && sa->bInheritHandle) ? OBJ_INHERIT : 0;
304     attr.SecurityDescriptor       = sa ? sa->lpSecurityDescriptor : NULL;
305     attr.SecurityQualityOfService = NULL;
306
307     if (name)
308     {
309         RtlInitUnicodeString( &nameW, name );
310         attr.ObjectName = &nameW;
311     }
312
313     sec_type = protect & sec_flags;
314     protect &= ~sec_flags;
315     if (!sec_type) sec_type = SEC_COMMIT;
316
317     switch(protect)
318     {
319     case 0:
320     case PAGE_READONLY:
321     case PAGE_WRITECOPY:
322         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
323         break;
324     case PAGE_READWRITE:
325         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
326         break;
327     default:
328         SetLastError( ERROR_INVALID_PARAMETER );
329         return 0;
330     }
331
332     if (hFile == INVALID_HANDLE_VALUE)
333     {
334         hFile = 0;
335         if (!size_low && !size_high)
336         {
337             SetLastError( ERROR_INVALID_PARAMETER );
338             return 0;
339         }
340     }
341
342     size.s.LowPart  = size_low;
343     size.s.HighPart = size_high;
344
345     status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile );
346     SetLastError( RtlNtStatusToDosError(status) );
347     return ret;
348 }
349
350
351 /***********************************************************************
352  *             OpenFileMappingA   (KERNEL32.@)
353  * Opens a named file-mapping object.
354  *
355  * RETURNS
356  *      Handle: Success
357  *      NULL: Failure
358  */
359 HANDLE WINAPI OpenFileMappingA(
360                 DWORD access,   /* [in] Access mode */
361                 BOOL inherit, /* [in] Inherit flag */
362                 LPCSTR name )   /* [in] Name of file-mapping object */
363 {
364     WCHAR buffer[MAX_PATH];
365
366     if (!name) return OpenFileMappingW( access, inherit, NULL );
367
368     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
369     {
370         SetLastError( ERROR_FILENAME_EXCED_RANGE );
371         return 0;
372     }
373     return OpenFileMappingW( access, inherit, buffer );
374 }
375
376
377 /***********************************************************************
378  *             OpenFileMappingW   (KERNEL32.@)
379  * See OpenFileMappingA
380  */
381 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
382 {
383     OBJECT_ATTRIBUTES attr;
384     UNICODE_STRING nameW;
385     HANDLE ret;
386     NTSTATUS status;
387
388     if (!name)
389     {
390         SetLastError( ERROR_INVALID_PARAMETER );
391         return 0;
392     }
393     attr.Length = sizeof(attr);
394     attr.RootDirectory = 0;
395     attr.ObjectName = &nameW;
396     attr.Attributes = inherit ? OBJ_INHERIT : 0;
397     attr.SecurityDescriptor = NULL;
398     attr.SecurityQualityOfService = NULL;
399     RtlInitUnicodeString( &nameW, name );
400
401     if (access == FILE_MAP_COPY) access = FILE_MAP_READ;
402
403     if ((status = NtOpenSection( &ret, access, &attr )))
404     {
405         SetLastError( RtlNtStatusToDosError(status) );
406         ret = 0;
407     }
408     return ret;
409 }
410
411
412 /***********************************************************************
413  *             MapViewOfFile   (KERNEL32.@)
414  * Maps a view of a file into the address space
415  *
416  * RETURNS
417  *      Starting address of mapped view
418  *      NULL: Failure
419  */
420 LPVOID WINAPI MapViewOfFile(
421               HANDLE mapping,  /* [in] File-mapping object to map */
422               DWORD access,      /* [in] Access mode */
423               DWORD offset_high, /* [in] High-order 32 bits of file offset */
424               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
425               SIZE_T count       /* [in] Number of bytes to map */
426 ) {
427     return MapViewOfFileEx( mapping, access, offset_high,
428                             offset_low, count, NULL );
429 }
430
431
432 /***********************************************************************
433  *             MapViewOfFileEx   (KERNEL32.@)
434  * Maps a view of a file into the address space
435  *
436  * RETURNS
437  *      Starting address of mapped view
438  *      NULL: Failure
439  */
440 LPVOID WINAPI MapViewOfFileEx(
441               HANDLE handle,   /* [in] File-mapping object to map */
442               DWORD access,      /* [in] Access mode */
443               DWORD offset_high, /* [in] High-order 32 bits of file offset */
444               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
445               SIZE_T count,      /* [in] Number of bytes to map */
446               LPVOID addr        /* [in] Suggested starting address for mapped view */
447 ) {
448     NTSTATUS status;
449     LARGE_INTEGER offset;
450     ULONG protect;
451
452     offset.s.LowPart  = offset_low;
453     offset.s.HighPart = offset_high;
454
455     if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE;
456     else if (access & FILE_MAP_READ) protect = PAGE_READONLY;
457     else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY;
458     else protect = PAGE_NOACCESS;
459
460     if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
461                                       &count, ViewShare, 0, protect )))
462     {
463         SetLastError( RtlNtStatusToDosError(status) );
464         addr = NULL;
465     }
466     return addr;
467 }
468
469
470 /***********************************************************************
471  *             UnmapViewOfFile   (KERNEL32.@)
472  * Unmaps a mapped view of a file.
473  *
474  * NOTES
475  *      Should addr be an LPCVOID?
476  *
477  * RETURNS
478  *      TRUE: Success
479  *      FALSE: Failure
480  */
481 BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */
482 {
483     NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr );
484     if (status) SetLastError( RtlNtStatusToDosError(status) );
485     return !status;
486 }
487
488
489 /***********************************************************************
490  *             FlushViewOfFile   (KERNEL32.@)
491  * Writes to the disk a byte range within a mapped view of a file
492  *
493  * RETURNS
494  *      TRUE: Success
495  *      FALSE: Failure
496  */
497 BOOL WINAPI FlushViewOfFile( LPCVOID base,  /* [in] Start address of byte range to flush */
498                              SIZE_T size )   /* [in] Number of bytes in range */
499 {
500     NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
501     if (status)
502     {
503         if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
504         else SetLastError( RtlNtStatusToDosError(status) );
505     }
506     return !status;
507 }
508
509
510 /***********************************************************************
511  *             IsBadReadPtr   (KERNEL32.@)
512  *
513  * RETURNS
514  *      FALSE: Process has read access to entire block
515  *      TRUE: Otherwise
516  */
517 BOOL WINAPI IsBadReadPtr(
518               LPCVOID ptr, /* [in] Address of memory block */
519               UINT size )  /* [in] Size of block */
520 {
521     if (!size) return FALSE;  /* handle 0 size case w/o reference */
522     if (!page_size) page_size = getpagesize();
523     __TRY
524     {
525         volatile const char *p = ptr;
526         char dummy;
527         UINT count = size;
528
529         while (count > page_size)
530         {
531             dummy = *p;
532             p += page_size;
533             count -= page_size;
534         }
535         dummy = p[0];
536         dummy = p[count - 1];
537     }
538     __EXCEPT(page_fault) { return TRUE; }
539     __ENDTRY
540     return FALSE;
541 }
542
543
544 /***********************************************************************
545  *             IsBadWritePtr   (KERNEL32.@)
546  *
547  * RETURNS
548  *      FALSE: Process has write access to entire block
549  *      TRUE: Otherwise
550  */
551 BOOL WINAPI IsBadWritePtr(
552               LPVOID ptr, /* [in] Address of memory block */
553               UINT size ) /* [in] Size of block in bytes */
554 {
555     if (!size) return FALSE;  /* handle 0 size case w/o reference */
556     if (!page_size) page_size = getpagesize();
557     __TRY
558     {
559         volatile char *p = ptr;
560         UINT count = size;
561
562         while (count > page_size)
563         {
564             *p |= 0;
565             p += page_size;
566             count -= page_size;
567         }
568         p[0] |= 0;
569         p[count - 1] |= 0;
570     }
571     __EXCEPT(page_fault) { return TRUE; }
572     __ENDTRY
573     return FALSE;
574 }
575
576
577 /***********************************************************************
578  *             IsBadHugeReadPtr   (KERNEL32.@)
579  * RETURNS
580  *      FALSE: Process has read access to entire block
581  *      TRUE: Otherwise
582  */
583 BOOL WINAPI IsBadHugeReadPtr(
584               LPCVOID ptr, /* [in] Address of memory block */
585               UINT size  /* [in] Size of block */
586 ) {
587     return IsBadReadPtr( ptr, size );
588 }
589
590
591 /***********************************************************************
592  *             IsBadHugeWritePtr   (KERNEL32.@)
593  * RETURNS
594  *      FALSE: Process has write access to entire block
595  *      TRUE: Otherwise
596  */
597 BOOL WINAPI IsBadHugeWritePtr(
598               LPVOID ptr, /* [in] Address of memory block */
599               UINT size /* [in] Size of block */
600 ) {
601     return IsBadWritePtr( ptr, size );
602 }
603
604
605 /***********************************************************************
606  *             IsBadCodePtr   (KERNEL32.@)
607  *
608  * RETURNS
609  *      FALSE: Process has read access to specified memory
610  *      TRUE: Otherwise
611  */
612 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
613 {
614     return IsBadReadPtr( ptr, 1 );
615 }
616
617
618 /***********************************************************************
619  *             IsBadStringPtrA   (KERNEL32.@)
620  *
621  * RETURNS
622  *      FALSE: Read access to all bytes in string
623  *      TRUE: Else
624  */
625 BOOL WINAPI IsBadStringPtrA(
626               LPCSTR str, /* [in] Address of string */
627               UINT max )  /* [in] Maximum size of string */
628 {
629     __TRY
630     {
631         volatile const char *p = str;
632         while (p != str + max) if (!*p++) break;
633     }
634     __EXCEPT(page_fault) { return TRUE; }
635     __ENDTRY
636     return FALSE;
637 }
638
639
640 /***********************************************************************
641  *             IsBadStringPtrW   (KERNEL32.@)
642  * See IsBadStringPtrA
643  */
644 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
645 {
646     __TRY
647     {
648         volatile const WCHAR *p = str;
649         while (p != str + max) if (!*p++) break;
650     }
651     __EXCEPT(page_fault) { return TRUE; }
652     __ENDTRY
653     return FALSE;
654 }