bugprone-sizeof-expression

The check finds usages of sizeof expressions which are most likely errors.

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. Misuse of this operator may be leading to errors and possible software vulnerabilities.

Suspicious usage of ‘sizeof(K)’

A common mistake is to query the sizeof of an integer literal. This is equivalent to query the size of its type (probably int). The intent of the programmer was probably to simply get the integer and not its size.

#define BUFLEN 42
char buf[BUFLEN];
memset(buf, 0, sizeof(BUFLEN));  // sizeof(42) ==> sizeof(int)

Suspicious usage of ‘sizeof(expr)’

In cases, where there is an enum or integer to represent a type, a common mistake is to query the sizeof on the integer or enum that represents the type that should be used by sizeof. This results in the size of the integer and not of the type the integer represents:

enum data_type {
  FLOAT_TYPE,
  DOUBLE_TYPE
};

struct data {
  data_type type;
  void* buffer;
  data_type get_type() {
    return type;
  }
};

void f(data d, int numElements) {
  // should be sizeof(float) or sizeof(double), depending on d.get_type()
  int numBytes = numElements * sizeof(d.get_type());
  ...
}

Suspicious usage of ‘sizeof(this)’

The this keyword is evaluated to a pointer to an object of a given type. The expression sizeof(this) is returning the size of a pointer. The programmer most likely wanted the size of the object and not the size of the pointer.

class Point {
  [...]
  size_t size() { return sizeof(this); }  // should probably be sizeof(*this)
  [...]
};

Suspicious usage of ‘sizeof(char*)’

There is a subtle difference between declaring a string literal with char* A = "" and char A[] = "". The first case has the type char* instead of the aggregate type char[]. Using sizeof on an object declared with char* type is returning the size of a pointer instead of the number of characters (bytes) in the string literal.

const char* kMessage = "Hello World!";      // const char kMessage[] = "...";
void getMessage(char* buf) {
  memcpy(buf, kMessage, sizeof(kMessage));  // sizeof(char*)
}

Suspicious usage of ‘sizeof(A*)’

A common mistake is to compute the size of a pointer instead of its pointee. These cases may occur because of explicit cast or implicit conversion.

int A[10];
memset(A, 0, sizeof(A + 0));

struct Point point;
memset(point, 0, sizeof(&point));

Suspicious usage of ‘sizeof(…)/sizeof(…)’

Dividing sizeof expressions is typically used to retrieve the number of elements of an aggregate. This check warns on incompatible or suspicious cases.

In the following example, the entity has 10-bytes and is incompatible with the type int which has 4 bytes.

char buf[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  // sizeof(buf) => 10
void getMessage(char* dst) {
  memcpy(dst, buf, sizeof(buf) / sizeof(int));  // sizeof(int) => 4  [incompatible sizes]
}

In the following example, the expression sizeof(Values) is returning the size of char*. One can easily be fooled by its declaration, but in parameter declaration the size ‘10’ is ignored and the function is receiving a char*.

char OrderedValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
return CompareArray(char Values[10]) {
  return memcmp(OrderedValues, Values, sizeof(Values)) == 0;  // sizeof(Values) ==> sizeof(char*) [implicit cast to char*]
}

Suspicious ‘sizeof’ by ‘sizeof’ expression

Multiplying sizeof expressions typically makes no sense and is probably a logic error. In the following example, the programmer used * instead of /.

const char kMessage[] = "Hello World!";
void getMessage(char* buf) {
  memcpy(buf, kMessage, sizeof(kMessage) * sizeof(char));  //  sizeof(kMessage) / sizeof(char)
}

This check may trigger on code using the arraysize macro. The following code is working correctly but should be simplified by using only the sizeof operator.

extern Object objects[100];
void InitializeObjects() {
  memset(objects, 0, arraysize(objects) * sizeof(Object));  // sizeof(objects)
}

Suspicious usage of ‘sizeof(sizeof(…))’

Getting the sizeof of a sizeof makes no sense and is typically an error hidden through macros.

#define INT_SZ sizeof(int)
int buf[] = { 42 };
void getInt(int* dst) {
  memcpy(dst, buf, sizeof(INT_SZ));  // sizeof(sizeof(int)) is suspicious.
}

Options

WarnOnSizeOfConstant

When true, the check will warn on an expression like sizeof(CONSTANT). Default is true.

WarnOnSizeOfIntegerExpression

When true, the check will warn on an expression like sizeof(expr) where the expression results in an integer. Default is false.

WarnOnSizeOfThis

When true, the check will warn on an expression like sizeof(this). Default is true.

WarnOnSizeOfCompareToConstant

When true, the check will warn on an expression like sizeof(expr) <= k for a suspicious constant k while k is 0 or greater than 0x8000. Default is true.

WarnOnSizeOfPointerToAggregate

When true, the check will warn on an expression like ``sizeof(expr)` where the expression is a pointer to aggregate. Default is true.