Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dereferencing type-punned pointer will break strict-aliasing rules

Tags:

c

pointers

gcc

I have a unsigned char pointer which contains a structure.Now I want to do the following

unsigned char buffer[24];

//code to fill the buffer with the relevant information.

int len = ntohs((record_t*)buffer->len);

where record_t structure contains a field called len.I am not able to do so and am getting the error.

error: request for member ‘len’ in something not a structure or union.

Then I tried:

int len = ntohs(((record_t*)buffer)->len);

so as to get the operator precedence right. That gave me the warning: dereferencing type-punned pointer will break strict-aliasing rules.

then I declared

record_t *rec = null;

rec = (record_t*)

what am I doing wrong here?

like image 413
liv2hak Avatar asked Oct 03 '11 00:10

liv2hak


3 Answers

According to the C and C++ standards, it is undefined behaviour to access a variable of a given type through a pointer to another type. Example:

int a;
float * p = (float*)&a;  // #1
float b = *p;            // #2

Here #2 causes undefined behaviour. The assignment at #1 is called "type punning". The term "aliasing" refers to the idea that several different pointer variables may be pointing at the same data -- in this case, p aliases the data a. Legal aliasing is a problem for optimization (which is one of the main reasons for Fortran's superior performance in certain situations), but what we have here is flat-out illegal aliasing.

Your situation is no different; you're accessing data at buffer through a pointer to a different type (i.e. a pointer that isn't char *). This is simply not allowed.

The upshot is: You should never have had data at buffer in the first place.

But how to solve it? Make sure you have a valid pointer! There is one exception to type punning, namely accessing data through a pointer to char, which is allowed. So we can write this:

record_t data;
record_t * p = &data;          // good pointer
char * buffer = (char*)&data;  // this is allowed!

return p->len;                 // access through correct pointer!

The crucial difference is that we store the real data in a variable of the correct type, and only after having allocated that variable do we treat the variable as an array of chars (which is allowed). The moral here is that the character array always comes second, and the real data type comes first.

like image 187
Kerrek SB Avatar answered Oct 15 '22 12:10

Kerrek SB


You're getting that warning because you're breaking strict-aliasing by having two pointers of different types pointing to the same location.

One way to get around that is to use unions:

union{
    unsigned char buffer[24];
    record_t record_part;
};

//code to fill the buffer with the relavent information.

int len = ntohs(record_part.len);

EDIT:

Strictly speaking, this isn't much safer than your original code, but it doesn't violate strict-aliasing.

like image 27
Mysticial Avatar answered Oct 15 '22 13:10

Mysticial


You might try this:

unsigned char buffer[sizeof(record_t)];
record_t rec;
int len;

// code to fill in buffer goes here...

memcpy(&rec, buffer, sizeof(rec));
len = ntohs(rec.len);
like image 27
Jim Rhodes Avatar answered Oct 15 '22 13:10

Jim Rhodes