Open ivmai opened 8 months ago
Current status: I've done a lot of refactoring to simplify porting to CHERI, and backported some changes from https://github.com/capablevms/bdwgc/ (see c29365b). Still many CHERI-specific changes to be backported.
And below is the list of code places worth attention during enabling of CHERI in master:
A number of changes are not ported yet (as of commit be1e3a3), here's a diff:
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index c93710be..18d7a321 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -2103,6 +2132,26 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
LOAD_TAGGED_VALUE(v, tag, p); \
if (tag != 0) continue; \
}
+#elif defined(CHERI_PURECAP)
+ /* Load value, check tag and permissions of the target memory. */
+# define LOAD_WORD_OR_CONTINUE(v, p) \
+ { \
+ v = *(void **)(p); \
+ if (!cheri_tag_get(v)) continue; \
+ size_t in_bounds = (v >= (word)cheri_base_get(v)) \
+ && (v < (word)cheri_base_get(v) \
+ + (word)cheri_length_get(v)); \
+ size_t has_rwx = cheri_perms_get(v) & (CHERI_PERM_LOAD \
+ | CHERI_PERM_STORE \
+ | CHERI_PERM_EXECUTE); \
+ if (!in_bounds || !has_rwx) continue; \
+ }
#else
# define LOAD_WORD_OR_CONTINUE(v, p) (void)(v = *(word *)(p))
#endif /* !E2K */
diff --git a/mark.c b/mark.c
index ae8f314f..69133827 100644
--- a/mark.c
+++ b/mark.c
@@ -548,7 +548,12 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
{
signed_word credit = HBLKSIZE; /* Remaining credit for marking work. */
ptr_t current_p; /* Pointer to current candidate ptr. */
+# ifdef CHERI_PURECAP
+ void **current; /* Candidate pointer. */
+ word has_rwx; /* permissions on capability */
+# else
word current; /* Candidate pointer. */
+# endif
ptr_t limit = 0; /* (Incl) limit of current candidate range. */
word descr;
ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
@@ -728,16 +733,17 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# define PREF_DIST 4
# if !defined(SMALL_CONFIG) && !defined(USE_PTR_HWTAG)
+# ifndef CHERI_PURECAP
word deferred;
@@ -763,6 +769,50 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
}
if ((word)current_p > (word)limit) goto next_object;
}
+# else //?? it is better to avoid code duplication
+ void **deferred;
+
+ /* Check each pointer for validity before dereferencing */
+ /* to prevent capability exceptions. */
+ /* Utilise the pointer meta-data to speed-up the loop. */
+ /* If the loop is below the pointer bounds, skip the rest of */
+ /* marking for that chunk. */
+ /* If the *limit* capability restricts us to reading fewer than */
+ /* sizeof(ptr_t), */
+ /* a. there can't possibly be a pointer at limit's pointer */
+ /* b. reading at that location will raise a capability */
+ /* exception */
+ if (ADDR(limit) + sizeof(ptr_t) - 1
+ >= (cheri_base_get(limit) + cheri_length_get(limit))) {
+ /* Decrement limit so that it's within current_p's bounds */
+ limit = cheri_address_set( current_p, ((cheri_base_get(limit)
+ + cheri_length_get(limit) - sizeof(ptr_t))
+ & ~(sizeof(ptr_t)-1)));
+ if ((word)current_p > (word)limit) goto next_object;
+ }
+ for(;;) {
+ GC_ASSERT((word)limit >= (word)current_p);
+ if (ADDR(limit) < cheri_base_get(limit)) goto next_object;
+
+ has_rwx = cheri_perms_get(limit) & (CHERI_PERM_LOAD
+ | CHERI_PERM_STORE
+ | CHERI_PERM_EXECUTE);
+ if ((cheri_tag_get(limit) == 0) || !has_rwx) {
+ limit -= ALIGNMENT;
+ } else {
+ deferred = *(void **)limit;
+ FIXUP_POINTER(deferred);
+ limit -= ALIGNMENT;
+ has_rwx = cheri_perms_get(deferred) & (CHERI_PERM_LOAD
+ | CHERI_PERM_STORE
+ | CHERI_PERM_EXECUTE);
+ if (((cheri_tag_get(deferred) != 0) && has_rwx)
+ && (deferred >= (word)least_ha && deferred < (word)greatest_ha))
+ break;
+ }
+ if ((word)current_p > (word)limit) goto next_object;
+ }
+# endif
# endif
for (; (word)current_p <= (word)limit; current_p += ALIGNMENT) {
@@ -1502,7 +1557,13 @@ GC_API void GC_CALL GC_print_trace(word gc_no)
GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY GC_ATTR_NO_SANITIZE_THREAD
GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
{
+# ifdef CHERI_PURECAP
+ REGISTER void ** current_p; // it is better to use ptr_t instead of void**
+# else
REGISTER ptr_t current_p;
+# endif
REGISTER word *lim;
REGISTER ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
REGISTER ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
@@ -1512,6 +1573,18 @@ GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
if (top == 0) return;
/* Check all pointers in range and push if they appear to be valid. */
+# ifdef CHERI_PURECAP
+ lim = t - 1;
+ if ((intptr_t)lim >= (cheri_base_get(b) + cheri_length_get(b)))
+ lim = cheri_base_get(b) + cheri_length_get(b) - sizeof(ptr_t);
+
+ for (current_p = b; (word)current_p <= (word)lim; current_p++) {
+ REGISTER void *q = *current_p;
+
+ LOAD_WORD_OR_CONTINUE(q, current_p);
+ GC_PUSH_ONE_STACK(q, current_p);
+ }
+# else
lim = (word *)(((word)top) & ~(ALIGNMENT-1)) - 1;
for (current_p = (ptr_t)(((word)bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
(word)current_p <= (word)lim; current_p += ALIGNMENT) {
@@ -1520,6 +1593,7 @@ GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
LOAD_WORD_OR_CONTINUE(q, current_p);
GC_PUSH_ONE_STACK(q, current_p);
}
+# endif
# undef GC_greatest_plausible_heap_addr
# undef GC_least_plausible_heap_addr
}
As of commit e1fb227, bdwgc could be built using:
./configure --disable-dynamic-loading --enable-cplusplus --enable-gc-assertions --enable-werror
make check CFLAGS_EXTRA="-Wno-cheri-capability-misuse -Wno-capability-to-integer-cast"
All tests fail currently, because of missing some patches from https://github.com/capablevms/bdwgc
Note: some suppressed warnings could be eliminated by modifying GC_CAST_AWAY_CONST_PVOID() and CAST_THRU_UINTPTR() - remove intermediate GC_uintptr_t if __CHERI_PURE_CAPABILITY__
.
As of commit 5d619ee, bdwgc could be built using:
./autogen.sh
./configure --enable-cplusplus --enable-gc-assertions --enable-werror
make check
Or, using make -f Makefile.direct check
or using cmake.
All tests fail currently (as noted above).
As of commit 5d619ee, bdwgc could be built using:
./autogen.sh
./configure --enable-cplusplus --enable-gc-assertions --enable-werror
make check
Or, using make -f Makefile.direct check
or using cmake.
All tests fail currently (as noted above).
GCJ support is not working because it expects granule to be at least twice bigger than pointer currently. Should be fixed by #652. For now, we set granule size to 2 pointers (32 bytes).
The purpose of this is not only support the protected mode but also better test bdwgc.
The patches in https://github.com/capablevms/bdwgc (master) should be useful.
Related issue: #461