Coverage Report

Created: 2025-06-13 06:34

/src/icu/icu4c/source/common/umapfile.cpp
Line
Count
Source (jump to first uncovered line)
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
123
        UDataMemory_init(pData); /* Clear the output struct.        */
124
125
        /* open the input file */
126
#if U_PLATFORM_HAS_WINUWP_API == 0
127
        // Note: In the non-UWP code-path (ie: Win32), the value of the path variable might have come from 
128
        // the CRT 'getenv' function, and would be therefore be encoded in the default ANSI code page.
129
        // This means that we can't call the *W version of API below, whereas in the UWP code-path
130
        // there is no 'getenv' call, and thus the string will be only UTF-8/Invariant characters.
131
        file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr,
132
            OPEN_EXISTING,
133
            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, nullptr);
134
#else
135
        // Convert from UTF-8 string to UTF-16 string.
136
        wchar_t utf16Path[MAX_PATH];
137
        int32_t pathUtf16Len = 0;
138
        u_strFromUTF8(reinterpret_cast<char16_t*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
139
140
        if (U_FAILURE(*status)) {
141
            return false;
142
        }
143
        if (*status == U_STRING_NOT_TERMINATED_WARNING) {
144
            // Report back an error instead of a warning.
145
            *status = U_BUFFER_OVERFLOW_ERROR;
146
            return false;
147
        }
148
149
        file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr,
150
            OPEN_EXISTING,
151
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
152
#endif
153
        if (file == INVALID_HANDLE_VALUE) {
154
            // If we failed to open the file due to an out-of-memory error, then we want
155
            // to report that error back to the caller.
156
            if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
157
                *status = U_MEMORY_ALLOCATION_ERROR;
158
            }
159
            return false;
160
        }
161
162
        // Note: We use nullptr/nullptr for lpAttributes parameter below.
163
        // This means our handle cannot be inherited and we will get the default security descriptor.
164
        /* create an unnamed Windows file-mapping object for the specified file */
165
        map = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
166
167
        CloseHandle(file);
168
        if (map == nullptr) {
169
            // If we failed to create the mapping due to an out-of-memory error, then 
170
            // we want to report that error back to the caller.
171
            if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
172
                *status = U_MEMORY_ALLOCATION_ERROR;
173
            }
174
            return false;
175
        }
176
177
        /* map a view of the file into our address space */
178
        pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0));
179
        if (pData->pHeader == nullptr) {
180
            CloseHandle(map);
181
            return false;
182
        }
183
        pData->map = map;
184
        return true;
185
    }
186
187
    U_CFUNC void
188
    uprv_unmapFile(UDataMemory *pData) {
189
        if (pData != nullptr && pData->map != nullptr) {
190
            UnmapViewOfFile(pData->pHeader);
191
            CloseHandle(pData->map);
192
            pData->pHeader = nullptr;
193
            pData->map = nullptr;
194
        }
195
    }
196
197
198
199
#elif MAP_IMPLEMENTATION==MAP_POSIX
200
    U_CFUNC UBool
201
0
    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
202
0
        int fd;
203
0
        int length;
204
0
        struct stat mystat;
205
0
        void *data;
206
207
0
        if (U_FAILURE(*status)) {
208
0
            return false;
209
0
        }
210
211
0
        UDataMemory_init(pData); /* Clear the output struct.        */
212
213
        /* determine the length of the file */
214
0
        if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
215
0
            return false;
216
0
        }
217
0
        length=mystat.st_size;
218
219
        /* open the file */
220
0
        fd=open(path, O_RDONLY);
221
0
        if(fd==-1) {
222
0
            return false;
223
0
        }
224
225
        /* get a view of the mapping */
226
0
#if U_PLATFORM != U_PF_HPUX
227
0
        data=mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0);
228
#else
229
        data=mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0);
230
#endif
231
0
        close(fd); /* no longer needed */
232
0
        if(data==MAP_FAILED) {
233
            // Possibly check the errno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR?
234
0
            return false;
235
0
        }
236
237
0
        pData->map = (char *)data + length;
238
0
        pData->pHeader=(const DataHeader *)data;
239
0
        pData->mapAddr = data;
240
#if U_PLATFORM == U_PF_IPHONE || U_PLATFORM == U_PF_ANDROID
241
    // Apparently supported from Android 23 and higher:
242
    //   https://github.com/ggml-org/llama.cpp/pull/3631
243
    // Checking for the flag itself is safer than checking for __ANDROID_API__.
244
#   ifdef POSIX_MADV_RANDOM
245
        posix_madvise(data, length, POSIX_MADV_RANDOM);
246
#   endif
247
#endif
248
0
        return true;
249
0
    }
250
251
    U_CFUNC void
252
0
    uprv_unmapFile(UDataMemory *pData) {
253
0
        if(pData!=nullptr && pData->map!=nullptr) {
254
0
            size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
255
0
            if(munmap(pData->mapAddr, dataLen)==-1) {
256
0
            }
257
0
            pData->pHeader=nullptr;
258
0
            pData->map=nullptr;
259
0
            pData->mapAddr=nullptr;
260
0
        }
261
0
    }
262
263
264
265
#elif MAP_IMPLEMENTATION==MAP_STDIO
266
    /* copy of the filestrm.c/T_FileStream_size() implementation */
267
    static int32_t
268
    umap_fsize(FILE *f) {
269
        int32_t savedPos = ftell(f);
270
        int32_t size = 0;
271
272
        /*Changes by Bertrand A. D. doesn't affect the current position
273
        goes to the end of the file before ftell*/
274
        fseek(f, 0, SEEK_END);
275
        size = (int32_t)ftell(f);
276
        fseek(f, savedPos, SEEK_SET);
277
        return size;
278
    }
279
280
    U_CFUNC UBool
281
    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
282
        FILE *file;
283
        int32_t fileLength;
284
        void *p;
285
286
        if (U_FAILURE(*status)) {
287
            return false;
288
        }
289
290
        UDataMemory_init(pData); /* Clear the output struct.        */
291
        /* open the input file */
292
        file=fopen(path, "rb");
293
        if(file==nullptr) {
294
            return false;
295
        }
296
297
        /* get the file length */
298
        fileLength=umap_fsize(file);
299
        if(ferror(file) || fileLength<=20) {
300
            fclose(file);
301
            return false;
302
        }
303
304
        /* allocate the memory to hold the file data */
305
        p=uprv_malloc(fileLength);
306
        if(p==nullptr) {
307
            fclose(file);
308
            *status = U_MEMORY_ALLOCATION_ERROR;
309
            return false;
310
        }
311
312
        /* read the file */
313
        if(fileLength!=fread(p, 1, fileLength, file)) {
314
            uprv_free(p);
315
            fclose(file);
316
            return false;
317
        }
318
319
        fclose(file);
320
        pData->map=p;
321
        pData->pHeader=(const DataHeader *)p;
322
        pData->mapAddr=p;
323
        return true;
324
    }
325
326
    U_CFUNC void
327
    uprv_unmapFile(UDataMemory *pData) {
328
        if(pData!=nullptr && pData->map!=nullptr) {
329
            uprv_free(pData->map);
330
            pData->map     = nullptr;
331
            pData->mapAddr = nullptr;
332
            pData->pHeader = nullptr;
333
        }
334
    }
335
#else
336
#   error MAP_IMPLEMENTATION is set incorrectly
337
#endif