Fix pointer provenance in SDL_SIMDRealloc
This is needed to support CHERI, and thus Arm's experimental Morello prototype, where pointers are implemented using unforgeable capabilities that include bounds and permissions metadata to provide fine-grained spatial and referential memory safety, as well as revocation by sweeping memory to provide heap temporal memory safety. The C standard does not guarantee that if two pointers compare equal they are the same pointer, as C pointers have a notion of provenance, and compilers have been known to exploit this during optimisation. For CHERI, this becomes even more important, as in-place expansion can result in realloc returning a capability to the same address but with increased capability bounds, and so reusing the old capability will trap trying to access outside the bounds of the original allocation. In the case that ptr == mem, memdiff and ptrdiff should still be equal, so the only overhead is a small amount of pointer arithmetic and a store of the new pointer (which is required per the C standard in order to not be undefined behaviour when next loaded). This also fixes the calculation of oldmem to use uintptr_t rather than size_t as casting the pointer to size_t on CHERI will strip the capability metadata, including the validity tag, with the subsequent cast back to void * resulting in a null-derived capability whose validity tag is clear and thus cannot be dereferenced without trapping.main
parent
8f38ba4d68
commit
02daab8736
|
@ -1087,9 +1087,6 @@ SDL_SIMDRealloc(void *mem, const size_t len)
|
||||||
|
|
||||||
ptr = (Uint8 *) SDL_realloc(mem, padded + alignment + sizeof (void *));
|
ptr = (Uint8 *) SDL_realloc(mem, padded + alignment + sizeof (void *));
|
||||||
|
|
||||||
if (ptr == mem) {
|
|
||||||
return retval; /* Pointer didn't change, nothing to do */
|
|
||||||
}
|
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
return NULL; /* Out of memory, bail! */
|
return NULL; /* Out of memory, bail! */
|
||||||
}
|
}
|
||||||
|
@ -1102,7 +1099,7 @@ SDL_SIMDRealloc(void *mem, const size_t len)
|
||||||
if (mem) {
|
if (mem) {
|
||||||
ptrdiff = ((size_t) retval) - ((size_t) ptr);
|
ptrdiff = ((size_t) retval) - ((size_t) ptr);
|
||||||
if (memdiff != ptrdiff) { /* Delta has changed, copy to new offset! */
|
if (memdiff != ptrdiff) { /* Delta has changed, copy to new offset! */
|
||||||
oldmem = (void*) (((size_t) ptr) + memdiff);
|
oldmem = (void*) (((uintptr_t) ptr) + memdiff);
|
||||||
|
|
||||||
/* Even though the data past the old `len` is undefined, this is the
|
/* Even though the data past the old `len` is undefined, this is the
|
||||||
* only length value we have, and it guarantees that we copy all the
|
* only length value we have, and it guarantees that we copy all the
|
||||||
|
|
Loading…
Reference in New Issue