xref: /freebsd/contrib/jemalloc/src/san_bump.c (revision c43cad87172039ccf38172129c79755ea79e6102)
1 #include "jemalloc/internal/jemalloc_preamble.h"
2 #include "jemalloc/internal/jemalloc_internal_includes.h"
3 
4 #include "jemalloc/internal/san_bump.h"
5 #include "jemalloc/internal/pac.h"
6 #include "jemalloc/internal/san.h"
7 #include "jemalloc/internal/ehooks.h"
8 #include "jemalloc/internal/edata_cache.h"
9 
10 static bool
11 san_bump_grow_locked(tsdn_t *tsdn, san_bump_alloc_t *sba, pac_t *pac,
12     ehooks_t *ehooks, size_t size);
13 
14 edata_t *
15 san_bump_alloc(tsdn_t *tsdn, san_bump_alloc_t* sba, pac_t *pac,
16     ehooks_t *ehooks, size_t size, bool zero) {
17 	assert(san_bump_enabled());
18 
19 	edata_t* to_destroy;
20 	size_t guarded_size = san_one_side_guarded_sz(size);
21 
22 	malloc_mutex_lock(tsdn, &sba->mtx);
23 
24 	if (sba->curr_reg == NULL ||
25 	    edata_size_get(sba->curr_reg) < guarded_size) {
26 		/*
27 		 * If the current region can't accommodate the allocation,
28 		 * try replacing it with a larger one and destroy current if the
29 		 * replacement succeeds.
30 		 */
31 		to_destroy = sba->curr_reg;
32 		bool err = san_bump_grow_locked(tsdn, sba, pac, ehooks,
33 		    guarded_size);
34 		if (err) {
35 			goto label_err;
36 		}
37 	} else {
38 		to_destroy = NULL;
39 	}
40 	assert(guarded_size <= edata_size_get(sba->curr_reg));
41 	size_t trail_size = edata_size_get(sba->curr_reg) - guarded_size;
42 
43 	edata_t* edata;
44 	if (trail_size != 0) {
45 		edata_t* curr_reg_trail = extent_split_wrapper(tsdn, pac,
46 		    ehooks, sba->curr_reg, guarded_size, trail_size,
47 		    /* holding_core_locks */ true);
48 		if (curr_reg_trail == NULL) {
49 			goto label_err;
50 		}
51 		edata = sba->curr_reg;
52 		sba->curr_reg = curr_reg_trail;
53 	} else {
54 		edata = sba->curr_reg;
55 		sba->curr_reg = NULL;
56 	}
57 
58 	malloc_mutex_unlock(tsdn, &sba->mtx);
59 
60 	assert(!edata_guarded_get(edata));
61 	assert(sba->curr_reg == NULL || !edata_guarded_get(sba->curr_reg));
62 	assert(to_destroy == NULL || !edata_guarded_get(to_destroy));
63 
64 	if (to_destroy != NULL) {
65 		extent_destroy_wrapper(tsdn, pac, ehooks, to_destroy);
66 	}
67 
68 	san_guard_pages(tsdn, ehooks, edata, pac->emap, /* left */ false,
69 	    /* right */ true, /* remap */ true);
70 
71 	if (extent_commit_zero(tsdn, ehooks, edata, /* commit */ true, zero,
72 	    /* growing_retained */ false)) {
73 		extent_record(tsdn, pac, ehooks, &pac->ecache_retained,
74 		    edata);
75 		return NULL;
76 	}
77 
78 	if (config_prof) {
79 		extent_gdump_add(tsdn, edata);
80 	}
81 
82 	return edata;
83 label_err:
84 	malloc_mutex_unlock(tsdn, &sba->mtx);
85 	return NULL;
86 }
87 
88 static bool
89 san_bump_grow_locked(tsdn_t *tsdn, san_bump_alloc_t *sba, pac_t *pac,
90     ehooks_t *ehooks, size_t size) {
91 	malloc_mutex_assert_owner(tsdn, &sba->mtx);
92 
93 	bool committed = false, zeroed = false;
94 	size_t alloc_size = size > SBA_RETAINED_ALLOC_SIZE ? size :
95 	    SBA_RETAINED_ALLOC_SIZE;
96 	assert((alloc_size & PAGE_MASK) == 0);
97 	sba->curr_reg = extent_alloc_wrapper(tsdn, pac, ehooks, NULL,
98 	    alloc_size, PAGE, zeroed, &committed,
99 	    /* growing_retained */ true);
100 	if (sba->curr_reg == NULL) {
101 		return true;
102 	}
103 	return false;
104 }
105