4 ms·
Is there a term for predicates that are checked by static analysis when possible, but relegated to runtime checks when not?
by CoastalCoder 2y ago
Is there a term for predicates that are checked by static analysis when possible, but relegated to runtime checks when not?
- account42 2y agoThat's just any runtime check with an optimizing compiler - conditionals that the compiler can prove are always true / always false can get eliminated.
- UncleMeat 2y agoExhaustive runtime checks for all forms of UB are basically impossible. A data race is UB. Are you going to find a way to insert correct data race detection on all writes? Writing through an invalid pointer alias is UB. How are you going to detect when that happens at runtime? Sanitizers exist and do detect a subset of UB via runtime checks, but there is nothing resembling a system that can detect all UB. That would basically require an entire VM implementing the C-standard with a truly outrageous amount of runtime overhead.
- torstenvl 2y agoThe problem is the conflation of at least three different working definitions of "undefined behavior." Strictly speaking, undefined behavior only means that the Standard does not impose a requirement. But what many people mean is that the ramifications are outside the scope of the language or are unpredictable. Writing through an invalid pointer is perfectly definable. The standard could easily specify solely that the write to the memory location indicated in the pointer will be attempted, but that whether the write succeeds and what second- and third-order effects result from such a write are dependent on the environment, including operating system. Boom. Not undefined behavior. But still potentially dangerous behavior with unpredictable results. (In my view, this is in fact what ANSI C requires for this type of "undefined behavior," but many others do not agree.)
- UncleMeat 2y ago> The standard could easily specify solely that the write to the memory location indicated in the pointer will be attempted It could. But now you can't optimize things to store data in registers hardly ever.
- trealira 2y ago> (In my view, this is in fact what ANSI C requires for this type of "undefined behavior," but many others do not agree.) By not imposing any requirements for undefined behavior, ISO C does not require that, but maybe it ought to. > Strictly speaking, undefined behavior only means that the Standard does not impose a requirement. > But what many people mean is that the ramifications are outside the scope of the language or are unpredictable. The latter is a consequence of the former. Compiler writers treat undefined behavior as though it can't happen, and this causes unpredictable behavior. Suppose you had code like this in C: #define Variant1 0 #define Variant2 1 void use_variant(int variant) { if (variant == 0) { // Variant1 } else { // Must be Variant2 } } You are assuming your code is always passed a 1 or a 0, not checking for any other possibilities, which is basically treating other possibilities as "can't happen". Code that passes it a 2 might get one kind of behavior now, and another kind of behavior later, when the function updates. Your function may have wildly inconsistent behavior on different versions of the same function when given inputs of 2 because you're treating that as undefined behavior. That's basically how compiler writers treat undefined behavior - just assume it doesn't happen. And, that's how standard C library functions work. Functions like strlen assume you never give it a null pointer; they will just dereference pointers unconditionally.
- torstenvl 2y ago> That's basically how compiler writers treat undefined behavior - just assume it doesn't happen. Yes, but this phrase is ambiguous. What it is meant to refer to is "ignoring the situation completely with unpredictable results," i.e., ignore that writing to that random address is theoretically unpredictable, and just do it, consequences be damned. What compiler writers sometimes actually do is prove by static analysis that the pointer was freed, or never initialized, and then predicated on that situation, rather than ignoring that situation, generate machine code that elides it entirely. Since they know the code is undefined behavior, and they "assume UB doesn't exist," they assume the code cannot execute. When strlen() keeps iterating through memory, the behavior is closer to the former than the latter.
- JonChesterfield 2y ago"types"
- trealira 2y agoI mean, the whole point of C is for it to be used by people who "know what they're doing" and just won't write code that dereferences invalid pointers (dangling pointers, null pointers, pointers that write past arrays, writes to read-only memory, uses of unaligned pointers on platforma where that causes a bus error, etc.) or divides by zero. That way, you get the maximum theoretical performance and flexibility without writing the assembly yourself, assuming you make no such mistakes. It's supposed to be a thin wrapper over the hardware. If you want a language that does these compile-time and runtime checks on pointers and integers, but is otherwise like C (in that it compiles natively and doesn't use garbage collection), your choices are basically Rust and Ada.