Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/source/common/umapfile.cpp
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
******************************************************************************
5
*
6
*   Copyright (C) 1999-2013, International Business Machines
7
*   Corporation and others.  All Rights Reserved.
8
*
9
******************************************************************************/
10
11
12
/*----------------------------------------------------------------------------
13
 *
14
 *       Memory mapped file wrappers for use by the ICU Data Implementation
15
 *       All of the platform-specific implementation for mapping data files
16
 *         is here.  The rest of the ICU Data implementation uses only the
17
 *         wrapper functions.
18
 *
19
 *----------------------------------------------------------------------------*/
20
/* Defines _XOPEN_SOURCE for access to POSIX functions.
21
 * Must be before any other #includes. */
22
#include "uposixdefs.h"
23
24
#include "unicode/putil.h"
25
#include "unicode/ustring.h"
26
#include "udatamem.h"
27
#include "umapfile.h"
28
29
/* memory-mapping base definitions ------------------------------------------ */
30
31
#if MAP_IMPLEMENTATION==MAP_WIN32
32
#ifndef WIN32_LEAN_AND_MEAN
33
#   define WIN32_LEAN_AND_MEAN
34
#endif
35
#   define VC_EXTRALEAN
36
#   define NOUSER
37
#   define NOSERVICE
38
#   define NOIME
39
#   define NOMCX
40
41
#   if U_PLATFORM_HAS_WINUWP_API == 1
42
        // Some previous versions of the Windows 10 SDK don't expose various APIs for UWP applications
43
        // to use, even though UWP apps are allowed to call and use them.  Temporarily change the
44
        // WINAPI family partition below to Desktop, so that function declarations are visible for UWP.
45
#       include <winapifamily.h>
46
#       if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM))
47
#           pragma push_macro("WINAPI_PARTITION_DESKTOP")
48
#           undef WINAPI_PARTITION_DESKTOP
49
#           define WINAPI_PARTITION_DESKTOP 1
50
#           define CHANGED_WINAPI_PARTITION_DESKTOP_VALUE
51
#       endif
52
#   endif
53
54
#   include <windows.h>
55
56
#   if U_PLATFORM_HAS_WINUWP_API == 1 && defined(CHANGED_WINAPI_PARTITION_DESKTOP_VALUE)
57
#       pragma pop_macro("WINAPI_PARTITION_DESKTOP")
58
#   endif
59
60
#   include "cmemory.h"
61
62
typedef HANDLE MemoryMap;
63
64
#   define IS_MAP(map) ((map)!=nullptr)
65
66
#elif MAP_IMPLEMENTATION==MAP_POSIX
67
    typedef size_t MemoryMap;
68
69
#   define IS_MAP(map) ((map)!=0)
70
71
#   include <unistd.h>
72
#   include <sys/mman.h>
73
#   include <sys/stat.h>
74
#   include <fcntl.h>
75
76
#   ifndef MAP_FAILED
77
#       define MAP_FAILED ((void*)-1)
78
#   endif
79
#elif MAP_IMPLEMENTATION==MAP_STDIO
80
#   include <stdio.h>
81
#   include "cmemory.h"
82
83
    typedef void *MemoryMap;
84
85
#   define IS_MAP(map) ((map)!=nullptr)
86
#endif
87
88
/*----------------------------------------------------------------------------*
89
 *                                                                            *
90
 *   Memory Mapped File support.  Platform dependent implementation of        *
91
 *                           functions used by the rest of the implementation.*
92
 *                                                                            *
93
 *----------------------------------------------------------------------------*/
94
#if MAP_IMPLEMENTATION==MAP_NONE
95
    U_CFUNC UBool
96
    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
97
        if (U_FAILURE(*status)) {
98
            return false;
99
        }
100
        UDataMemory_init(pData); /* Clear the output struct. */
101
        return false;            /* no file access */
102
    }
103
104
    U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
105
        /* nothing to do */
106
    }
107
#elif MAP_IMPLEMENTATION==MAP_WIN32
108
    U_CFUNC UBool
109
    uprv_mapFile(
110
         UDataMemory *pData,    /* Fill in with info on the result doing the mapping. */
111
                                /*   Output only; any original contents are cleared.  */
112
         const char *path,      /* File path to be opened/mapped.                     */
113
         UErrorCode *status     /* Error status, used to report out-of-memory errors. */
114
         )
115
    {
116
        if (U_FAILURE(*status)) {
117
            return false;
118
        }
119
120
        HANDLE map = nullptr;
121
        HANDLE file = INVALID_HANDLE_VALUE;
122
        DWORD fileLength = 0;
123
124
        UDataMemory_init(pData); /* Clear the output struct.        */
125
126
        /* open the input file */
127
#if U_PLATFORM_HAS_WINUWP_API == 0
128
        // Note: In the non-UWP code-path (ie: Win32), the value of the path variable might have come from 
129
        // the CRT 'getenv' function, and would be therefore be encoded in the default ANSI code page.
130
        // This means that we can't call the *W version of API below, whereas in the UWP code-path
131
        // there is no 'getenv' call, and thus the string will be only UTF-8/Invariant characters.
132
        file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr,
133
            OPEN_EXISTING,
134
            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, nullptr);
135
#else
136
        // Convert from UTF-8 string to UTF-16 string.
137
        wchar_t utf16Path[MAX_PATH];
138
        int32_t pathUtf16Len = 0;
139
        u_strFromUTF8(reinterpret_cast<char16_t*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
140
141
        if (U_FAILURE(*status)) {
142
            return false;
143
        }
144
        if (*status == U_STRING_NOT_TERMINATED_WARNING) {
145
            // Report back an error instead of a warning.
146
            *status = U_BUFFER_OVERFLOW_ERROR;
147
            return false;
148
        }
149
150
        file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr,
151
            OPEN_EXISTING,
152
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
153
#endif
154
        if (file == INVALID_HANDLE_VALUE) {
155
            // If we failed to open the file due to an out-of-memory error, then we want
156
            // to report that error back to the caller.
157
            if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
158
                *status = U_MEMORY_ALLOCATION_ERROR;
159
            }
160
            return false;
161
        }
162
163
        fileLength = GetFileSize(file, nullptr);
164
165
        // Note: We use nullptr/nullptr for lpAttributes parameter below.
166
        // This means our handle cannot be inherited and we will get the default security descriptor.
167
        /* create an unnamed Windows file-mapping object for the specified file */
168
        map = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
169
170
        CloseHandle(file);
171
        if (map == nullptr) {
172
            // If we failed to create the mapping due to an out-of-memory error, then 
173
            // we want to report that error back to the caller.
174
            if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
175
                *status = U_MEMORY_ALLOCATION_ERROR;
176
            }
177
            return false;
178
        }
179
180
        /* map a view of the file into our address space */
181
        pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0));
182
        if (pData->pHeader == nullptr) {
183
            CloseHandle(map);
184
            return false;
185
        }
186
        pData->map = map;
187
        pData->length = fileLength;
188
189
        return true;
190
    }
191
192
    U_CFUNC void
193
    uprv_unmapFile(UDataMemory *pData) {
194
        if (pData != nullptr && pData->map != nullptr) {
195
            UnmapViewOfFile(pData->pHeader);
196
            CloseHandle(pData->map);
197
            pData->pHeader = nullptr;
198
            pData->map = nullptr;
199
        }
200
    }
201
202
203
204
#elif MAP_IMPLEMENTATION==MAP_POSIX
205
    U_CFUNC UBool
206
0
    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
207
0
        int fd;
208
0
        int length;
209
0
        struct stat mystat;
210
0
        void *data;
211
212
0
        if (U_FAILURE(*status)) {
213
0
            return false;
214
0
        }
215
216
0
        UDataMemory_init(pData); /* Clear the output struct.        */
217
218
        /* determine the length of the file */
219
0
        if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
220
0
            return false;
221
0
        }
222
0
        length=mystat.st_size;
223
224
        /* open the file */
225
0
        fd=open(path, O_RDONLY);
226
0
        if(fd==-1) {
227
0
            return false;
228
0
        }
229
230
        /* get a view of the mapping */
231
0
#if U_PLATFORM != U_PF_HPUX
232
0
        data=mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0);
233
#else
234
        data=mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0);
235
#endif
236
0
        close(fd); /* no longer needed */
237
0
        if(data==MAP_FAILED) {
238
            // Possibly check the errno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR?
239
0
            return false;
240
0
        }
241
242
0
        pData->map = (char *)data + length;
243
0
        pData->pHeader=(const DataHeader *)data;
244
0
        pData->mapAddr = data;
245
0
        pData->length = length;
246
#if U_PLATFORM == U_PF_IPHONE || U_PLATFORM == U_PF_ANDROID
247
    // Apparently supported from Android 23 and higher:
248
    //   https://github.com/ggml-org/llama.cpp/pull/3631
249
    // Checking for the flag itself is safer than checking for __ANDROID_API__.
250
#   ifdef POSIX_MADV_RANDOM
251
        posix_madvise(data, length, POSIX_MADV_RANDOM);
252
#   endif
253
#endif
254
0
        return true;
255
0
    }
256
257
    U_CFUNC void
258
0
    uprv_unmapFile(UDataMemory *pData) {
259
0
        if(pData!=nullptr && pData->map!=nullptr) {
260
0
            size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
261
0
            if(munmap(pData->mapAddr, dataLen)==-1) {
262
0
            }
263
0
            pData->pHeader=nullptr;
264
0
            pData->map=nullptr;
265
0
            pData->mapAddr=nullptr;
266
0
        }
267
0
    }
268
269
270
271
#elif MAP_IMPLEMENTATION==MAP_STDIO
272
    /* copy of the filestrm.c/T_FileStream_size() implementation */
273
    static int32_t
274
    umap_fsize(FILE *f) {
275
        int32_t savedPos = ftell(f);
276
        int32_t size = 0;
277
278
        /*Changes by Bertrand A. D. doesn't affect the current position
279
        goes to the end of the file before ftell*/
280
        fseek(f, 0, SEEK_END);
281
        size = (int32_t)ftell(f);
282
        fseek(f, savedPos, SEEK_SET);
283
        return size;
284
    }
285
286
    U_CFUNC UBool
287
    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
288
        FILE *file;
289
        int32_t fileLength;
290
        void *p;
291
292
        if (U_FAILURE(*status)) {
293
            return false;
294
        }
295
296
        UDataMemory_init(pData); /* Clear the output struct.        */
297
        /* open the input file */
298
        file=fopen(path, "rb");
299
        if(file==nullptr) {
300
            return false;
301
        }
302
303
        /* get the file length */
304
        fileLength=umap_fsize(file);
305
        if(ferror(file) || fileLength<=20) {
306
            fclose(file);
307
            return false;
308
        }
309
310
        /* allocate the memory to hold the file data */
311
        p=uprv_malloc(fileLength);
312
        if(p==nullptr) {
313
            fclose(file);
314
            *status = U_MEMORY_ALLOCATION_ERROR;
315
            return false;
316
        }
317
318
        /* read the file */
319
        if(fileLength!=fread(p, 1, fileLength, file)) {
320
            uprv_free(p);
321
            fclose(file);
322
            return false;
323
        }
324
325
        fclose(file);
326
        pData->map=p;
327
        pData->pHeader=(const DataHeader *)p;
328
        pData->mapAddr=p;
329
        pData->length = fileLength;
330
        return true;
331
    }
332
333
    U_CFUNC void
334
    uprv_unmapFile(UDataMemory *pData) {
335
        if(pData!=nullptr && pData->map!=nullptr) {
336
            uprv_free(pData->map);
337
            pData->map     = nullptr;
338
            pData->mapAddr = nullptr;
339
            pData->pHeader = nullptr;
340
        }
341
    }
342
#else
343
#   error MAP_IMPLEMENTATION is set incorrectly
344
#endif