File: bugprone-sizeof-expression.rst

package info (click to toggle)
llvm-toolchain-11 1%3A11.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 995,808 kB
  • sloc: cpp: 4,767,656; ansic: 760,916; asm: 477,436; python: 170,940; objc: 69,804; lisp: 29,914; sh: 23,855; f90: 18,173; pascal: 7,551; perl: 7,471; ml: 5,603; awk: 3,489; makefile: 2,573; xml: 915; cs: 573; fortran: 503; javascript: 452
file content (189 lines) | stat: -rw-r--r-- 5,858 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
.. title:: 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.

.. code-block:: c++

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

.. code-block:: c++

  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.

.. code-block:: c++

  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.

.. code-block:: c++

  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.

.. code-block:: c++

  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.

.. code-block:: c++

  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*``.

.. code-block:: c++

  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
``/``.

.. code-block:: c++

  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.

.. code-block:: c++

  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.

.. code-block:: c++

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

Options
-------

.. option:: WarnOnSizeOfConstant

   When non-zero, the check will warn on an expression like
   ``sizeof(CONSTANT)``. Default is `1`.

.. option:: WarnOnSizeOfIntegerExpression

   When non-zero, the check will warn on an expression like ``sizeof(expr)``
   where the expression results in an integer. Default is `0`.

.. option:: WarnOnSizeOfThis

   When non-zero, the check will warn on an expression like ``sizeof(this)``.
   Default is `1`.

.. option:: WarnOnSizeOfCompareToConstant

   When non-zero, the check will warn on an expression like
   ``sizeof(epxr) <= k`` for a suspicious constant `k` while `k` is `0` or
   greater than `0x8000`. Default is `1`.