The OS decides when what.
So far, memory tagging is only done per allocation from malloc or alloca. The compiler backend inserts special new instructions (such as STG) to scramble the tag for a specific 16B "block". [0]
I propose that the zig compiler _frontend_ can also insert some STG instructions. Whenever the user does an = operation to replace one union member with another, we should do an STG on the union's containing blocks. Suddenly, we are much more memory safe, pretty much closing the gap with Rust.
Indeed, only some CPUs support memory tagging, and that's unfortunate. However, that doesn't stop us from using it where it is supported ;) if for nothing else, its help as a debugging tool would be amazing, like a much faster ASan or valgrind.
[0] https://developer.arm.com/-/media/Arm%20Developer%20Communit...
https://docs.oracle.com/cd/E53394_01/html/E54815/gqajs.html
https://docs.oracle.com/cd/E86824_01/html/E54765/adi-2.html
https://docs.oracle.com/cd/E86824_01/html/E54766/adi-3c.html
https://docs.oracle.com/cd/E37838_01/html/E61021/sysauth-adi...
And for iOS,
https://developer.apple.com/documentation/security/preparing...
https://developer.apple.com/documentation/security/hardened_...
And for Android,
https://developer.android.com/ndk/guides/hwasan
So you cannot just assume that calling a couple of Assembly instructions from userspace will do for hardware memory tagging.
iOS works a bit more like I expected, though they don't list the instructions we might use to scramble the tags for a block of memory like the ARM paper's STG instruction does. I wonder if that might be possible one day.