Skip to content

Commit f5cf23c

Browse files
committed
Merge pull request #2470 from Shopify/at-fix-mmap
Fix unavailable MAP_ANONYMOUS
1 parent a10410e commit f5cf23c

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

include/rbs/util/rbs_allocator.h

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,32 @@
33

44
#include <stddef.h>
55

6-
#ifndef alignof
7-
#if defined(__GNUC__) || defined(__clang__)
8-
#define alignof(type) __alignof__(type)
6+
/* Include stdalign.h for C11 and later for alignof support */
7+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
8+
#include <stdalign.h>
9+
#endif
10+
11+
/*
12+
* Define a portable alignment macro that works across all supported environments
13+
*/
14+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
15+
/* C11 or later - use _Alignof directly (always available in C11+) */
16+
#define rbs_alignof(type) _Alignof(type)
17+
#elif defined(__cplusplus) && __cplusplus >= 201103L
18+
/* C++11 or later has alignof keyword */
19+
#define rbs_alignof(type) alignof(type)
20+
#elif defined(__GNUC__) || defined(__clang__)
21+
/* GCC and Clang provide __alignof__ */
22+
#define rbs_alignof(type) __alignof__(type)
923
#elif defined(_MSC_VER)
10-
#define alignof(type) __alignof(type)
24+
/* MSVC provides __alignof */
25+
#define rbs_alignof(type) __alignof(type)
1126
#else
12-
// Fallback using offset trick
13-
#define alignof(type) offsetof(struct { char c; type member; }, member)
14-
#endif
27+
/* Fallback using offset trick for other compilers */
28+
#define rbs_alignof(type) offsetof( \
29+
struct { char c; type member; }, \
30+
member \
31+
)
1532
#endif
1633

1734
struct rbs_allocator;
@@ -26,13 +43,13 @@ void *rbs_allocator_calloc_impl(rbs_allocator_t *, size_t count, size_t size, si
2643
void *rbs_allocator_realloc_impl(rbs_allocator_t *, void *ptr, size_t old_size, size_t new_size, size_t alignment);
2744

2845
// Use this when allocating memory for a single instance of a type.
29-
#define rbs_allocator_alloc(allocator, type) ((type *) rbs_allocator_malloc_impl((allocator), sizeof(type), alignof(type)))
46+
#define rbs_allocator_alloc(allocator, type) ((type *) rbs_allocator_malloc_impl((allocator), sizeof(type), rbs_alignof(type)))
3047
// Use this when allocating memory that will be immediately written to in full.
3148
// Such as allocating strings
32-
#define rbs_allocator_alloc_many(allocator, count, type) ((type *) rbs_allocator_malloc_many_impl((allocator), (count), sizeof(type), alignof(type)))
49+
#define rbs_allocator_alloc_many(allocator, count, type) ((type *) rbs_allocator_malloc_many_impl((allocator), (count), sizeof(type), rbs_alignof(type)))
3350
// Use this when allocating memory that will NOT be immediately written to in full.
3451
// Such as allocating buffers
35-
#define rbs_allocator_calloc(allocator, count, type) ((type *) rbs_allocator_calloc_impl((allocator), (count), sizeof(type), alignof(type)))
36-
#define rbs_allocator_realloc(allocator, ptr, old_size, new_size, type) ((type *) rbs_allocator_realloc_impl((allocator), (ptr), (old_size), (new_size), alignof(type)))
52+
#define rbs_allocator_calloc(allocator, count, type) ((type *) rbs_allocator_calloc_impl((allocator), (count), sizeof(type), rbs_alignof(type)))
53+
#define rbs_allocator_realloc(allocator, ptr, old_size, new_size, type) ((type *) rbs_allocator_realloc_impl((allocator), (ptr), (old_size), (new_size), rbs_alignof(type)))
3754

3855
#endif

src/location.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
void rbs_loc_alloc_children(rbs_allocator_t *allocator, rbs_location_t *loc, size_t capacity) {
99
rbs_assert(capacity <= sizeof(rbs_loc_entry_bitmap) * 8, "Capacity %zu is too large. Max is %zu", capacity, sizeof(rbs_loc_entry_bitmap) * 8);
1010

11-
loc->children = rbs_allocator_malloc_impl(allocator, RBS_LOC_CHILDREN_SIZE(capacity), alignof(rbs_loc_children));
11+
loc->children = rbs_allocator_malloc_impl(allocator, RBS_LOC_CHILDREN_SIZE(capacity), rbs_alignof(rbs_loc_children));
1212

1313
loc->children->len = 0;
1414
loc->children->required_p = 0;

src/util/rbs_allocator.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,38 @@
2020
#include <unistd.h>
2121
#include <sys/types.h>
2222
#include <sys/mman.h>
23-
#endif
24-
25-
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun)
26-
#define MAP_ANONYMOUS MAP_ANON
23+
#include <fcntl.h>
2724
#endif
2825

2926
struct rbs_allocator {
3027
uintptr_t heap_ptr;
3128
uintptr_t size;
3229
};
3330

31+
static void *portable_mmap_anon(size_t size) {
32+
#ifdef _WIN32
33+
/* Windows doesn't use this function - VirtualAlloc is used instead */
34+
return NULL;
35+
#else
36+
void *ptr;
37+
38+
#if defined(MAP_ANONYMOUS)
39+
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
40+
#elif defined(MAP_ANON)
41+
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
42+
#else
43+
/* Fallback to /dev/zero for systems without anonymous mapping */
44+
int fd = open("/dev/zero", O_RDWR);
45+
rbs_assert(fd != -1, "open('/dev/zero') failed");
46+
47+
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
48+
close(fd); /* Can close fd after mapping */
49+
#endif
50+
51+
return ptr;
52+
#endif
53+
}
54+
3455
static size_t get_system_page_size(void) {
3556
#ifdef _WIN32
3657
SYSTEM_INFO si;
@@ -48,7 +69,7 @@ static void *map_memory(size_t size) {
4869
LPVOID result = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
4970
rbs_assert(result != NULL, "VirtualAlloc failed");
5071
#else
51-
void *result = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
72+
void *result = portable_mmap_anon(size);
5273
rbs_assert(result != MAP_FAILED, "mmap failed");
5374
#endif
5475
return result;

0 commit comments

Comments
 (0)