clang-tidy - bugprone-sizeof-expression — Extra Clang Tools 18.1.8 documentation

# Extra Clang Tools 18.1.8 documentation

## clang-tidy - bugprone-sizeof-expression

# 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.