forked from OSchip/llvm-project
133 lines
4.9 KiB
ReStructuredText
133 lines
4.9 KiB
ReStructuredText
.. title:: clang-tidy - bugprone-not-null-terminated-result
|
|
|
|
bugprone-not-null-terminated-result
|
|
===================================
|
|
|
|
Finds function calls where it is possible to cause a not null-terminated result.
|
|
Usually the proper length of a string is ``strlen(src) + 1`` or equal length of
|
|
this expression, because the null terminator needs an extra space. Without the
|
|
null terminator it can result in undefined behaviour when the string is read.
|
|
|
|
The following and their respective ``wchar_t`` based functions are checked:
|
|
|
|
``memcpy``, ``memcpy_s``, ``memchr``, ``memmove``, ``memmove_s``,
|
|
``strerror_s``, ``strncmp``, ``strxfrm``
|
|
|
|
The following is a real-world example where the programmer forgot to increase
|
|
the passed third argument, which is ``size_t length``. That is why the length
|
|
of the allocated memory is not enough to hold the null terminator.
|
|
|
|
.. code-block:: c
|
|
|
|
static char *stringCpy(const std::string &str) {
|
|
char *result = reinterpret_cast<char *>(malloc(str.size()));
|
|
memcpy(result, str.data(), str.size());
|
|
return result;
|
|
}
|
|
|
|
In addition to issuing warnings, fix-it rewrites all the necessary code. It also
|
|
tries to adjust the capacity of the destination array:
|
|
|
|
.. code-block:: c
|
|
|
|
static char *stringCpy(const std::string &str) {
|
|
char *result = reinterpret_cast<char *>(malloc(str.size() + 1));
|
|
strcpy(result, str.data());
|
|
return result;
|
|
}
|
|
|
|
Note: It cannot guarantee to rewrite every of the path-sensitive memory
|
|
allocations.
|
|
|
|
.. _MemcpyTransformation:
|
|
|
|
Transformation rules of 'memcpy()'
|
|
----------------------------------
|
|
|
|
It is possible to rewrite the ``memcpy()`` and ``memcpy_s()`` calls as the
|
|
following four functions: ``strcpy()``, ``strncpy()``, ``strcpy_s()``,
|
|
``strncpy_s()``, where the latter two are the safer versions of the former two.
|
|
It rewrites the ``wchar_t`` based memory handler functions respectively.
|
|
|
|
Rewrite based on the destination array
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
- If copy to the destination array cannot overflow [1] the new function should
|
|
be the older copy function (ending with ``cpy``), because it is more
|
|
efficient than the safe version.
|
|
|
|
- If copy to the destination array can overflow [1] and
|
|
:option:`WantToUseSafeFunctions` is set to `true` and it is possible to
|
|
obtain the capacity of the destination array then the new function could be
|
|
the safe version (ending with ``cpy_s``).
|
|
|
|
- If the new function is could be safe version and C++ files are analysed and
|
|
the destination array is plain ``char``/``wchar_t`` without ``un/signed`` then
|
|
the length of the destination array can be omitted.
|
|
|
|
- If the new function is could be safe version and the destination array is
|
|
``un/signed`` it needs to be casted to plain ``char *``/``wchar_t *``.
|
|
|
|
[1] It is possible to overflow:
|
|
- If the capacity of the destination array is unknown.
|
|
- If the given length is equal to the destination array's capacity.
|
|
|
|
Rewrite based on the length of the source string
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
- If the given length is ``strlen(source)`` or equal length of this expression
|
|
then the new function should be the older copy function (ending with ``cpy``),
|
|
as it is more efficient than the safe version (ending with ``cpy_s``).
|
|
|
|
- Otherwise we assume that the programmer wanted to copy 'N' characters, so the
|
|
new function is ``ncpy``-like which copies 'N' characters.
|
|
|
|
Transformations with 'strlen()' or equal length of this expression
|
|
------------------------------------------------------------------
|
|
|
|
It transforms the ``wchar_t`` based memory and string handler functions
|
|
respectively (where only ``strerror_s`` does not have ``wchar_t`` based alias).
|
|
|
|
Memory handler functions
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
``memcpy``
|
|
Please visit the
|
|
:ref:`Transformation rules of 'memcpy()'<MemcpyTransformation>` section.
|
|
|
|
``memchr``
|
|
Usually there is a C-style cast and it is needed to be removed, because the
|
|
new function ``strchr``'s return type is correct. The given length is going
|
|
to be removed.
|
|
|
|
``memmove``
|
|
If safe functions are available the new function is ``memmove_s``, which has
|
|
a new second argument which is the length of the destination array, it is
|
|
adjusted, and the length of the source string is incremented by one.
|
|
If safe functions are not available the given length is incremented by one.
|
|
|
|
``memmove_s``
|
|
The given length is incremented by one.
|
|
|
|
String handler functions
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
``strerror_s``
|
|
The given length is incremented by one.
|
|
|
|
``strncmp``
|
|
If the third argument is the first or the second argument's ``length + 1``
|
|
it has to be truncated without the ``+ 1`` operation.
|
|
|
|
``strxfrm``
|
|
The given length is incremented by one.
|
|
|
|
Options
|
|
-------
|
|
|
|
.. option:: WantToUseSafeFunctions
|
|
|
|
The value `true` specifies that the target environment is considered to
|
|
implement '_s' suffixed memory and string handler functions which are safer
|
|
than older versions (e.g. 'memcpy_s()'). The default value is `true`.
|