Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strict aliasing and memory locations

Strict aliasing prevents us from accessing the same memory location using an incompatible type.

int* i = malloc( sizeof( int ) ) ;  //assuming sizeof( int ) >= sizeof( float )
*i = 123 ;
float* f = ( float* )i ;
*f = 3.14f ;

this would be illegal according to C standard, because the compiler "knows" that int cannot accessed by a float lvalue.

What if I use that pointer to point to correct memory, like this:

int* i = malloc( sizeof( int ) + sizeof( float ) + MAX_PAD ) ;
*i = 456 ;

First I allocate memory for int, float and the last part is memory which will allow float to be stored on aligned address. float requires to be aligned on multiples of 4. MAX_PAD is usually 8 of 16 bytes depending on the system. In any case, MAX_PAD is large enough so float can be aligned properly.

Then I write an int into i, so far so good.

float* f = ( float* )( ( char* )i + sizeof( int ) + PaddingBytesFloat( (char*)i ) ) ;
*f= 2.71f ;

I use the pointer i, increment it with the size of int and align it correctly with the function PaddingBytesFloat(), which returns the number of bytes required to align a float, given an address. Then I write a float into it.

In this case, f points to a different memory location that doesn't overlap; it has a different type.


Here are some parts from the standard (ISO/IEC 9899:201x) 6.5 , I was relying on when writing this example.

Aliasing is when more than one lvalue points to the same memory location. Standard requires that those lvalues have a compatible type with the effective type of the object.

What is effective type, quote from standard:

The effective type of an object for an access to its stored value is the declared type of the object, if any.87)If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

87) Allocated objects have no declared type.

I'm trying to connect the pieces and figure out if this is allowed. In my interpretation the effective type of an allocated object can be changed depending on the type of the lvalue used on that memory, because of this part: For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

Is this legal? If not, what if I used a void pointer as lvalue instead of an int pointer i in my second example? If even that wouldn't work, what if I got the address, which is assigned to the float pointer in the second example, as a memcopied value, and that address was never used as an lvalue before.

like image 913
this Avatar asked May 10 '14 14:05

this


People also ask

What is aliasing in memory?

When a given location in the physical address space has multiple virtual addresses, this is called aliasing. Attributes are based on virtual addresses. This is because attributes come from the translation tables.

How do you get around strict aliasing?

The answer typically is to type pun, often the methods used violate strict aliasing rules. Sometimes we want to circumvent the type system and interpret an object as a different type. This is called type punning, to reinterpret a segment of memory as another type.

What is the problem of aliasing while using pointers?

Two seemingly different pointers may point to storage locations in the same array (aliasing). As a result, data dependencies can arise when performing loop-based computations using pointers, as the pointers may potentially point to overlapping regions in memory.

What is C++ aliasing?

In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.


1 Answers

I think that yes, it is legal.

To illustrate my point, let's see this code:

struct S
{
    int i;
    float f;
};
char *p = malloc(sizeof(struct S));

int *i = p + offsetof(struct S, i);  //this offset is 0 by definition
*i = 456;
float *f = p + offsetof(struct S, f);
*f= 2.71f;

This code is, IMO, clearly legal, and it is equivalent to yours from a compiler point of view, for appropriate values of PaddingBytesFloat() and MAX_PAD.

Note that my code does not use any l-value of type struct S, it is only used to ease the calculation of the paddings.

As I read the standard, in malloc'ed memory has no declared type until something is written there. Then the declared type is whatever is written. Thus the declared type of such memory can be changed any time, overwriting the memory with a value of different type, much like an union.

TL; DR: My conclusion is that with dynamic memory you are safe, with regard to strict-aliasing as long as you read the memory using the same type (or a compatible one) you use to last write to that memory.

like image 73
rodrigo Avatar answered Dec 16 '22 08:12

rodrigo