Differences From Artifact [4b72bb7708]:
- File src/OFSecureData.m — part of check-in [9122facff6] at 2019-10-20 13:15:41 on branch trunk — Fix missing fast paths in -[isEqual:] (user: js, size: 13479) [annotate] [blame] [check-ins using]
To Artifact [0b2ff22574]:
- File
src/OFSecureData.m
— part of check-in
[60caadeb5d]
at
2019-12-15 14:42:19
on branch trunk
— Make +[OFSecureData isSecure] per instance
The reason for this change is that whether non-swappable memory can be
allocated or not is something that changes over time, so calling
+[isSecure] always had a potential for a race. The only reliable way is
to allocate the memory and then report whether it's swappable or not.It's also called -[isSwappable] now to be more precise. (user: js, size: 12950) [annotate] [blame] [check-ins using] [more...]
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #endif #define CHUNK_SIZE 16 struct page { struct page *next, *previous; void *map; unsigned char *page; }; #if defined(OF_HAVE_COMPILER_TLS) static thread_local struct page *firstPage = NULL; static thread_local struct page *lastPage = NULL; static thread_local struct page **preallocatedPages = NULL; static thread_local size_t numPreallocatedPages = 0; #elif defined(OF_HAVE_THREADS) static of_tlskey_t firstPageKey, lastPageKey; static of_tlskey_t preallocatedPagesKey, numPreallocatedPagesKey; #else static struct page *firstPage = NULL; static struct page *lastPage = NULL; static struct page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; #endif static void * | > | | < < > > | > | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #endif #define CHUNK_SIZE 16 struct page { struct page *next, *previous; void *map; bool swappable; unsigned char *page; }; #if defined(OF_HAVE_COMPILER_TLS) static thread_local struct page *firstPage = NULL; static thread_local struct page *lastPage = NULL; static thread_local struct page **preallocatedPages = NULL; static thread_local size_t numPreallocatedPages = 0; #elif defined(OF_HAVE_THREADS) static of_tlskey_t firstPageKey, lastPageKey; static of_tlskey_t preallocatedPagesKey, numPreallocatedPagesKey; #else static struct page *firstPage = NULL; static struct page *lastPage = NULL; static struct page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; #endif static void * mapPages(size_t numPages, bool *swappable) { size_t pageSize = [OFSystemInfo pageSize]; void *pointer; if (numPages > SIZE_MAX / pageSize) @throw [OFOutOfRangeException exception]; #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) if ((pointer = mmap(NULL, numPages * pageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) @throw [OFOutOfMemoryException exceptionWithRequestedSize: pageSize]; *swappable = (mlock(pointer, numPages * pageSize) != 0); #else if ((pointer = malloc(numPages * pageSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: pageSize]; *swappable = true; #endif return pointer; } static void unmapPages(void *pointer, size_t numPages, bool swappable) { size_t pageSize = [OFSystemInfo pageSize]; if (numPages > SIZE_MAX / pageSize) @throw [OFOutOfRangeException exception]; #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) if (!swappable) munlock(pointer, numPages * pageSize); munmap(pointer, numPages * pageSize); #else free(pointer); #endif } static struct page * |
︙ | ︙ | |||
150 151 152 153 154 155 156 | @throw [OFOutOfMemoryException exceptionWithRequestedSize: sizeof(*page)]; if ((page->map = calloc(1, mapSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: mapSize]; | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | @throw [OFOutOfMemoryException exceptionWithRequestedSize: sizeof(*page)]; if ((page->map = calloc(1, mapSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: mapSize]; page->page = mapPages(1, &page->swappable); of_explicit_memset(page->page, 0, pageSize); #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) lastPage = of_tlskey_get(lastPageKey); #endif page->previous = lastPage; |
︙ | ︙ | |||
189 190 191 192 193 194 195 | size_t pageSize = [OFSystemInfo pageSize]; size_t mapSize = OF_ROUND_UP_POW2(8, pageSize / CHUNK_SIZE) / 8; for (size_t i = 0; i < mapSize; i++) if (map[i] != 0) return; | | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | size_t pageSize = [OFSystemInfo pageSize]; size_t mapSize = OF_ROUND_UP_POW2(8, pageSize / CHUNK_SIZE) / 8; for (size_t i = 0; i < mapSize; i++) if (map[i] != 0) return; unmapPages(page->page, 1, page->swappable); free(page->map); if (page->previous != NULL) page->previous->next = page->next; if (page->next != NULL) page->next->previous = page->previous; |
︙ | ︙ | |||
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | of_explicit_memset(pointer, 0, bytes); for (size_t i = 0; i < chunks; i++) of_bitset_clear(page->map, chunkIndex + i); } @implementation OFSecureData #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) + (void)initialize { if (self != [OFSecureData class]) return; if (!of_tlskey_new(&firstPageKey) || !of_tlskey_new(&lastPageKey) || !of_tlskey_new(&preallocatedPagesKey) || !of_tlskey_new(&numPreallocatedPagesKey)) @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | of_explicit_memset(pointer, 0, bytes); for (size_t i = 0; i < chunks; i++) of_bitset_clear(page->map, chunkIndex + i); } @implementation OFSecureData @synthesize swappable = _swappable; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) + (void)initialize { if (self != [OFSecureData class]) return; if (!of_tlskey_new(&firstPageKey) || !of_tlskey_new(&lastPageKey) || !of_tlskey_new(&preallocatedPagesKey) || !of_tlskey_new(&numPreallocatedPagesKey)) @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif + (void)preallocateMemoryWithSize: (size_t)size { size_t pageSize = [OFSystemInfo pageSize]; size_t numPages = OF_ROUND_UP_POW2(pageSize, size) / pageSize; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page **preallocatedPages = of_tlskey_get(preallocatedPagesKey); size_t numPreallocatedPages; |
︙ | ︙ | |||
394 395 396 397 398 399 400 | size_t pageSize = [OFSystemInfo pageSize]; if (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; if (count * itemSize >= pageSize) _items = mapPages(OF_ROUND_UP_POW2(pageSize, | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | size_t pageSize = [OFSystemInfo pageSize]; if (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; if (count * itemSize >= pageSize) _items = mapPages(OF_ROUND_UP_POW2(pageSize, count * itemSize) / pageSize, &_swappable); else { #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page *lastPage = of_tlskey_get(lastPageKey); #endif for (struct page *page = lastPage; page != NULL; page = page->previous) { |
︙ | ︙ | |||
420 421 422 423 424 425 426 427 428 429 430 431 432 433 | count * itemSize); if (_items == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: count * itemSize]; } } _itemSize = itemSize; _count = count; } @catch (id e) { [self release]; @throw e; | > > | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | count * itemSize); if (_items == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: count * itemSize]; } _swappable = _page->swappable; } _itemSize = itemSize; _count = count; } @catch (id e) { [self release]; @throw e; |
︙ | ︙ | |||
494 495 496 497 498 499 500 | - (void)dealloc { size_t pageSize = [OFSystemInfo pageSize]; if (_count * _itemSize > pageSize) unmapPages(_items, | | > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | - (void)dealloc { size_t pageSize = [OFSystemInfo pageSize]; if (_count * _itemSize > pageSize) unmapPages(_items, OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / pageSize, _swappable); else if (_page != NULL) { if (_items != NULL) freeMemory(_page, _items, _count * _itemSize); removePageIfEmpty(_page); } |
︙ | ︙ |