C pointers have undefined behaviors which are not found in the machine language.
For anything that can go wrong with C pointers (and other types) in the abstract, there is some computer out there where it is an issue. That computer is usually in a museum; it's not one that understands a popular instruction set.
The problem is that the omissions in the definition of behavior done because of portability across machines turn into an optimization hint. Things that were once left undefined because they worked in reliable, but machine-spcific ways became booby traps.
To be sure your code will work with optimizations, you have to write it as if it had to be portable to machines you don't care about.
You don't have that problem in assembly language, or not on the same scale. You sometimes worry about different members of the same instruction set family, and that's about it.
> Even as we speak, systems programmers are doing pointer arithmetic so that children and artists can pretend that their x86 chips do not expose an architecture designed by Sauron.
> You might ask, “Why would someone write code in a grotesque language that exposes raw memory addresses? Why not use a modern language with garbage collection and functional programming and free massages after lunch?” Here’s the answer: Pointers are real. They’re what the hardware understands. Somebody has to deal with them. You can’t just place a LISP book on top of an x86 chip and hope that the hardware learns about lambda calculus by osmosis.
Really, I recommend everything by James Mickens every chance I get: https://mickens.seas.harvard.edu/wisdom-james-mickens