简体   繁体   中英

WINAPI C - CreateFileMapping fails with error 8 - ERROR_NOT_ENOUGH_MEMORY

I'm working with file mappings on Windows but having some troubles with them. First off, I have the necessity to partially map a file and setting the start and the end of it dynamically.

My code is the following:

long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
    long start = (i)*fiveMB;
    long end = (i + 1)*fiveMB;
    long realEnd = end;
    if (roundedDim<realEnd)
        realEnd = dim;

    long chunkDim = realEnd - start;
    LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
    LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
    LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
    long offset = start - fileMapStart.QuadPart;

    HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);

    if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
       printf("Error mapping file: %d\n",GetLastError());
       CloseHandle(fileH);
       return 1;
    }

    char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
    if ((LPVOID)mapView == NULL) {
        printf("Error mapView: %d\n", GetLastError());
        CloseHandle(fileMappingH);
        CloseHandle(file);
        return 1;
    }

    mapView += offset;

    /* doing all the stuff */

    UnmapViewOfFile((LPVOID)mapView);
    CloseHandle(fileMappingH);
}

As far as I know, only MapViewOfFile requires the starting byte to be aligned with the system granularity, so I didn't bother to fix the maximum file mapping size for that.

I tried this code on a 1448 KB file (printing out dim I get 1482159 bytes ) while calculating the available memory via GlobalMemoryStatusEx(&memstatus) and memstatus.ullAvailVirtual I get 2092208128 bytes but still stuck on having the CreateFileMapping call failed and with error code 8, ERROR_NOT_ENOUGH_MEMORY .

I also tried calling CreateFileMapping(fileH, NULL, PAGE_READONLY, 0, 0, NULL) to memory map the whole file, but instead there were problems on MapViewOfFile , error 5, ERROR_ACCESS_DENIED .

I don't understand what I'm doing wrong here, since I successfully did it with mmap on a Linux version of the same project.

Thanks anyone who may help.


EDITS:

  • c was a leftover, I actually meant i

  • added UnmapViewOfFile and CloseHandle calls

As far as I know, MapViewOfFile only requires the starting byte to be aligned with the system granularity, so I didn't bother to fix the maximum file mapping size for that.

this is root of error - really from MapViewOfFile

dwNumberOfBytesToMap [in]

The number of bytes of a file mapping to map to the view. All bytes must be within the maximum size specified by CreateFileMapping . If this parameter is 0 (zero), the mapping extends from the specified offset to the end of the file mapping.

if we use 0 as MaximumSize in CreateFileMapping the maximum size of the file mapping object is equal to the current size of the file. and :

if an application specifies a size for the file mapping object that is larger than the size of the actual named file on disk and if the page protection allows write access (that is, the flProtect parameter specifies PAGE_READWRITE or PAGE_EXECUTE_READWRITE ), then the file on disk is increased to match the specified size of the file mapping object.

and about GetLastError and win32 errors at all. the errors in most case returned from kernel as NTSTATUS code. the win32 layer converts the specified NTSTATUS code to its equivalent system error code via RtlNtStatusToDosError . unfortunately this conversion not injective - the many different NTSTATUS code can convert to same win32 error and we lost sensitive info here.

so in some case much more better call RtlGetLastNtStatus() instead of GetlastError() - this give to as much more info about error.

CreateFileMapping call failed and with error code ERROR_NOT_ENOUGH_MEMORY .

based on error ERROR_NOT_ENOUGH_MEMORY we can think that not enough memory in system ( STATUS_NO_MEMORY ). but also another status - STATUS_SECTION_TOO_BIG converted to the ERROR_NOT_ENOUGH_MEMORY . the CreateFileMapping is thin shell over ZwCreateSection the STATUS_SECTION_TOO_BIG returned when:

The value of MaximumSize is too big. This occurs when either MaximumSize is greater than the system-defined maximum for sections, or if MaximumSize is greater than the specified file and the section is not writable .

and this is exactly your case: you use PAGE_READONLY in call CreateFileMapping - so section is not writable and fileMapSize is greater than the specified file (size for the file mapping object that is larger than the size of the actual file on disk)

MapViewOfFile return ERROR_ACCESS_DENIED .

again GetLastError() plays here with us a cruel joke. the initial status is not STATUS_ACCESS_DENIED how we can wait, but STATUS_INVALID_VIEW_SIZE . this status also converted to ERROR_ACCESS_DENIED . the MapViewOfFile got it when not all bytes within the maximum size specified by CreateFileMapping

and call CreateFileMapping multiple time in loop - this is design error - need call this api only once, before loop. in loop only exist sense call MapViewOfFile . the test code can be:

void TestMap(PCWSTR lpFileName, ULONG dwChunkSize)
{
    HANDLE hFile = CreateFileW(lpFileName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        FILE_STANDARD_INFO fsi;
        if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
        {
            if (HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0))
            {
                if (ULONG n = (ULONG)((fsi.EndOfFile.QuadPart + (dwChunkSize - 1)) / dwChunkSize))
                {
                    LARGE_INTEGER ofs = {};
                    do 
                    {
                        if (PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, ofs.HighPart, ofs.LowPart, --n ? dwChunkSize : 0))
                        {
                            UnmapViewOfFile(pv);
                        }
                        else
                        {
                            RtlGetLastNtStatus();
                        }
                    } while (ofs.QuadPart += dwChunkSize, n);
                }

                CloseHandle(hSection);
            }
            else
            {
                RtlGetLastNtStatus();
            }
        }
        CloseHandle(hFile);
    }
    else
    {
        RtlGetLastNtStatus();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM