4 ms·
IMHO, casts from integer to pointer should have been deprecated in C (and derivative languages) a long time ago. Not only do they encourage unsafe practices, b
by Findecanor 5y ago
IMHO, casts from integer to pointer should have been deprecated in C (and derivative languages) a long time ago.
Not only do they encourage unsafe practices, being forbidden in most C/C++ style guides.
They can also wreak havoc with any hardware or software-hardening that puts non-address bits in pointers. For instance, ARM PAC has been in Apple's CPUs for years now and support is mandatory in ARM v8.3 and up. Intel and AMD have also had experimental extensions that use those bits, and new ones are on the way.
When an integer is cast to pointer in those schemes, the pointer can become invalid.
Therefore, an integer cast to a pointer type should always result in an invalid pointer, IMHO.
Integers are sometimes used to set alignment. I'd suggest that the macros in CHERI C be added to <stdalign.h>: align_up, align_down and is_aligned. Those can be expressed in normal C without having to cast an integer to pointer, or use faster expressions depending on the platform.
- andi999 5y agoHow do you do embedded then? I mean you need to specify the addrese of lets say the spi interface. Usually numbers are written as integers. So we would need a syntax for pointer literals?
- addaon 5y agoI don't particularly agree with the grandparent that getting rid of pointer-to-integer casts makes sense, but at least the specific question you're asking doesn't seem like a non-starter. Two options that come to mind immediately would be making a union { intptr_t; foo * } well-defined; or adding a 'p' or 'ptr' literal suffix so 0x80004000p has type void *.
- andi999 5y agoYes type punning is still possiblem, but doesnt this violate the 'spirit' of the original idea (to get rid of conversions between int and *)
- addaon 5y agoType punning in general is undefined (unless one of the types is char * or equivalent); but defining it between intptr_t and pointer types in a few restricted contexts (e.g. for const variables of static storage duration only) would be sufficient to address memory mapped registers and restrictive enough that it should be possible to define clearly.
- kmonsen 5y agoOr language interop? At least in jni it’s normal to store a c/c++ pointer in Java as long, and then send it back to c where it has to be converted to a pointer.
- deleted 5y ago[deleted]
- saagarjha 5y agoOn the contrary, code that needs to do integer-to-pointer casts is almost exclusively written in C and C++. Hardware features such as PAC and CHERI were designed to work with those languages assuming that integer-to-pointer casts are possible. Any extension that prevents pointer tagging, extracting signatures, and the like is dead on arrival. Most code doesn't need to touch this kind of stuff, but the whole point of the languages is that it lets you do this when you need to.
- kibwen 5y agoThe Rust APIs mentioned in the OP support things like pointer tagging without exposing a raw integer address to the user. AIUI CHERI had to bend over backwards to support these operations in C, not because it wanted to but because it had to out of pragmatism. I wager that the CHERI authors would be thrilled if the grandparent's proposal to disallow int2ptr casts were possible to implement without ruling out every significant C codebase in history.
- saagarjha 5y agoI understand what you’re saying but I think we’re talking about two separate contexts, I’ll call them “CHERI unaware” and “CHERI aware”. There’s plenty of low-level, pointer casting CHERI unaware code, that should continue to work on the hardware. But there’s also people who write secure systems on top of it, and would like to do so in C and C++, so it’s important that they are able to access tags and such. Whether that is through wrappers over assembly instructions, or compiler intrinsics, or whatever, but the easier it is to use from high-level code the more likely it will see adoption there.
- im3w1l 5y agoWell one reason I think is the following pattern in some library. struct SomeStruct { ... void (*callback)(A); A user_data; } Here A will be either int or void*. But regardless of stated type, the expectation is that the user puts whatever they find the most convenient there, whether thats a pointer or integer (fd maybe?).
- flohofwoe 5y agoTBH I feel the opposite. "Pointers" should be simple memory addresses again without any compiler magic attached, and memory load/stores should be explicit, with the same level of control as assembly. At the least this would make manual performance optimization more predictable. There are plenty of languages "above" C, no need to move C into that direction even more, but I think the unexplored area "below" C (and above assembly) is much more interesting.
- deleted 5y ago[deleted]
- kibwen 5y agoThe problem is that C developers want their code to work as they expect, which is reasonable, and at the same time they want their code to be as fast as possible, which is also reasonable. But in practice these two desires are often at odds. So when C compilers start exploiting more UB in order to make code faster programmers turn around and complain, and then when C turns out to be slower than Fortran due to a lack of UB-exploiting optimizations a different segment of programmers will complain. It's a difficult balancing act for compiler and language developers.
- xscott 5y agoI think "restrict" is a really nice compromise in C: Your code declares that you're willing to follow additional rules, and the compiler can make additional optimizations. The article shows a piece of code that makes that promise and then doesn't hold up its part of the agreement. I can't even follow the rest of the argument from there because it's all based on a faulty foundation.
- cstrahan 5y ago> The article shows a piece of code that makes that promise and then doesn't hold up its part of the agreement. Edit: disregard; I now see your other comments. Incorrect. The article shows a piece of code that makes and fulfills that promise, and then the optimization passes break the code. If you disagree, I would be interested in hearing how/where you think the code itself is faulty.
- MaxBarraclough 5y ago> When an integer is cast to pointer in those schemes, the pointer can become invalid Doesn't that mean the compilers are non-compliant? uintptr_t is defined in terms of supporting round-trip conversions, no?