(Rereading your comment, it sounds like you might already know all of this. Apologies.)
If I understand correctly, here's a C++ example that has undefined behavior:
int foo() {
const int x = 42;
int *p = (int *)&x;
*p += 1;
return x;
}
foo() is UB, because it modifies the const object x, using a pointer cast to "cast away const". (Unfortunately, UBSan doesn't catch this, and I'm not aware of any sanitizer that does.) It's tempting to say that the pointer cast is "at fault" for the UB, but consider this very similar example that's not UB:
int bar() {
int x = 42;
const int *const_p = &x;
int *p = (int *)&const_p;
*p += 1;
return x;
}
bar() has exactly the same pointer cast as foo(), however in this case the original x object is not const. That makes "casting away const" legal in this case. So the problem we're left with, is that knowing all the types isn't enough for us to tell whether this cast is going to cause UB. We have to know where the pointer originally came from, which might be in another function or another file.
Right, gotcha, I just found it confusing to say "modifying a `const` value" but if course you meant modifying the underlying value [through a cast]. All good.
If I understand correctly, here's a C++ example that has undefined behavior:
foo() is UB, because it modifies the const object x, using a pointer cast to "cast away const". (Unfortunately, UBSan doesn't catch this, and I'm not aware of any sanitizer that does.) It's tempting to say that the pointer cast is "at fault" for the UB, but consider this very similar example that's not UB: bar() has exactly the same pointer cast as foo(), however in this case the original x object is not const. That makes "casting away const" legal in this case. So the problem we're left with, is that knowing all the types isn't enough for us to tell whether this cast is going to cause UB. We have to know where the pointer originally came from, which might be in another function or another file.