* [PATCH] docs: deprecated.rst: Add zero-length and one-element arrays
@ 2020-06-05 2:29 Gustavo A. R. Silva
0 siblings, 0 replies; only message in thread
From: Gustavo A. R. Silva @ 2020-06-05 2:29 UTC (permalink / raw)
To: Jonathan Corbet, Kees Cook; +Cc: linux-doc, linux-kernel, Gustavo A. R. Silva
Add zero-length and one-element arrays to the list.
While I continue replacing zero-length and one-element arrays with
flexible-array members, I need a reference to point people to, so
they don't introduce more instances of such arrays. And while here,
add a note to the "open-coded arithmetic in allocator arguments"
section, on the use of struct_size() and the arrays-to-deprecate
mentioned here.
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
Documentation/process/deprecated.rst | 84 ++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
index 652e2aa02a66c..622c8ac72a615 100644
--- a/Documentation/process/deprecated.rst
+++ b/Documentation/process/deprecated.rst
@@ -85,6 +85,12 @@ Instead, use the helper::
header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
+NOTE: If you are using struct_size() on a structure containing a zero-length
+or a one-element array as a trailing array member, stop using such arrays
+and switch to `flexible arrays
+<https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays>`_
+instead.
+
See array_size(), array3_size(), and struct_size(),
for more details as well as the related check_add_overflow() and
check_mul_overflow() family of functions.
@@ -200,3 +206,81 @@ All switch/case blocks must end in one of:
* continue;
* goto <label>;
* return [expression];
+
+Zero-length and one-element arrays
+----------------------------------
+Old code in the kernel uses the zero-length and one-element array extensions
+to the C90 standard, but the `preferred mechanism to declare variable-length
+types
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_
+such as these ones is a `flexible array member`, introduced in C99::
+
+ struct something {
+ int length;
+ char data[];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, data, size), GFP_KERNEL);
+ instance->length = size;
+ memcpy(instance->data, source, size);
+
+By making use of the mechanism above, we get a compiler error in case the
+flexible array does not occur last in the structure, which helps to prevent
+some kind of `undefined behavior <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=76497732932f15e7323dc805e8ea8dc11bb587cf>`_ bugs from being inadvertently introduced to
+the codebase.
+
+It is also important to notice that zero-length and one-element arrays pose
+confusion for things like sizeof() and `CONFIG_FORTIFY_SOURCE`. For instance,
+there is no mechanism that warns us that the following application of the
+sizeof() operator to a zero-length array always results in zero::
+
+ struct something {
+ int length;
+ char data[0];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, data, size), GFP_KERNEL);
+ instance->length = size;
+ memcpy(instance->data, source, size);
+ ...
+ size = sizeof(instance->data);
+
+At the last line of code above, ``size`` turns out to be zero --when one might have
+thought differently. Here are a couple examples of this issue `link 1
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
+`link 2
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
+On the other hand, `flexible array members have incomplete type, and so the sizeof()
+operator may not be applied <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_,
+so any misuse of such operator will be immediately noticed at build time.
+
+
+With respect to one-element arrays, one has to be acutely aware that `such arrays
+occupy at least as much space as a single object of the type
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_,
+hence they contribute to the size of the enclosing structure. This is prone
+to error every time people want to calculate the total size of dynamic memory
+to allocate for a structure containing an array of this kind as a member::
+
+ struct something {
+ int length;
+ char data[1];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, data, size - 1), GFP_KERNEL);
+ instance->length = size;
+ memcpy(instance->data, source, size);
+
+In the example above, we had to remember to calculate ``size - 1`` when using
+the struct_size() helper, otherwise we would have --unintentionally-- allocated
+memory for one too many ``data`` objects. The cleanest and least error-prone way
+to implement this is through the use of a `flexible array member`, which is
+exemplified at the `beginning
+<https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays>`_
+of this section.
--
2.27.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2020-06-05 2:24 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-05 2:29 [PATCH] docs: deprecated.rst: Add zero-length and one-element arrays Gustavo A. R. Silva
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.