Note that declaring no aliasing is probably unsafe for concurrent or moving garbage collectors, as then the C compiler can conveniently "forget" to either store or load values to the shadow stack at some points...
(though it is fine if GC can only happen inside a function call and the call takes the shadow stack as an argument)
Concurrent GC's isn't a mess I've dealt with (majority single-threaded languages), moving should be ok if all heap accesses are in single statements through the shadow stack and a pointer to the shadow-stack is always passed on to called functions (Thus the compiler shouldn't be allowed to retain anything, I could be wrong on some slight C standard detail here though).
(though it is fine if GC can only happen inside a function call and the call takes the shadow stack as an argument)