The code below looks crazy, because I am interested in finding out the limits of what’s possible, and it isn’t exactly what I’m doing in my real code. It compiles without warnings and works as expected, printing “onref: 42”, but what I’m wondering is if it’s guaranteed to work or if the line marked “the interesting line” is actually undefined behavior.
The top candidate for something constituting a problem here is that h is set to point outside of defined variables, so accessing h->other or h->map could in principle result in segmentation violation, but making sure that those are not accessed, by first checking the value of onref to determine if the struct is a valid H, should make it good, shouldn’t it?
#include <stdio.h>
#include <inttypes.h>
struct H {
struct H *other;
uint32_t *map;
uint64_t onref;
};
struct G {
uint64_t onref;
char data[10];
};
#define ONREF_VALUE_THAT_SHOWS_ITS_NOT_AN_H 42
void foo(void *p) {
struct H *h = (struct H *) p - 1; // the interesting line
printf("onref: %"PRIu64"\n", h->onref);
}
int main() {
static struct G g;
g.onref = ONREF_VALUE_THAT_SHOWS_ITS_NOT_AN_H;
foo(&g.data);
}
The pointer arithmetic is undefined behaviour in
struct H *h = (struct H *) p - 1;
even before you attempt to dereference it. C23 says
6.5.6 Additive operators
9 ... If the pointer operand and the result do not point to elements of the same array object or one past the last element of the array object, the behavior is undefined.
In your 'interesting' line p was pointing to the first element of an array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With