Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dereferencing an uninitialized pointer to pass into sizeof()

In a recent post, I realised that when allocating a structure variable, passing the dereferenced pointer deemed a better practice in contrast to passing the structure type to sizeof(). This is basically because the former is more resilient to code changes than the latter.

Which suggests, that in the following code method 1 is deemed a better practice than method 2.

typedef struct X_ {
    int x;
    int y;
    int z;
} X;

int main() {
    X* obj1 = malloc(sizeof(*obj1)); // ----> method 1
    X* obj2 = malloc(sizeof(X));     // ----> method 2
    return 0;
}

The question is, how valid is it to dereference obj1 in method 1 ? Inside malloc, obj1 is still unconstructed/uninitialized memory which suggests that dereferencing of obj1 happening inside sizeof() shouldn't be valid.

Let me make a guess what makes method 1 valid. Is this because since sizeof() is a compile time operation dereferencing obj1 gets translated into method 2 by the compiler?

Could someone please elaborate the technical validity of this by referring to the relevant C standards?

like image 553
aep Avatar asked Mar 02 '23 06:03

aep


1 Answers

The sizeof expression where the operand is not a variable length array is a non evaluated expression. So this expression

sizeof(*obj1)

is well-formed.

From the C Standard (6.5.3.4 The sizeof and alignof operators)

2 The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant

As for your question relative to the best method of specifying an argument of malloc

X* obj1 = malloc(sizeof(*obj1)); // ----> method 1
X* obj2 = malloc(sizeof(X));     // ----> method 2

then if the type X is visible in the point of using malloc like in this case

X* obj1 = malloc(sizeof(*obj1)); // ----> method 1

then this approach is preferable.

However if the type is not visible like for example

obj1 = malloc(sizeof(*obj1)); // ----> method 1

then I prefer explicitly to specify the type like

obj1 = malloc(sizeof( X ));

Otherwise for example this code snippet

p = malloc( *p );
q = malloc( *q );

does not give enough information for the reader of the code. And the reader will need to scroll the source code forward and backward to find the declarations of p and q to determine their types.

like image 117
Vlad from Moscow Avatar answered Apr 08 '23 00:04

Vlad from Moscow