<feed xmlns='http://www.w3.org/2005/Atom'>
<title>unit.git, branch str-v3</title>
<subtitle>Universal Web Application Server</subtitle>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/'/>
<entry>
<title>Split nxt_str_t struct declaration and definition.</title>
<updated>2022-11-16T12:04:08+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-10-30T12:13:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=bdcbcf3dacb20a8a532e3318efc1af23577f5ba2'/>
<id>bdcbcf3dacb20a8a532e3318efc1af23577f5ba2</id>
<content type='text'>
This allows using the type in declarations before it's actually
defined, and also to move the typedef to another file.

Reviewed-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This allows using the type in declarations before it's actually
defined, and also to move the typedef to another file.

Reviewed-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Added nxt_usts2str() to make C strings from nxt_str_t.</title>
<updated>2022-11-16T12:04:08+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-10-27T11:22:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=5ab7ae702c0e4a65653ba346bd5bf20506224842'/>
<id>5ab7ae702c0e4a65653ba346bd5bf20506224842</id>
<content type='text'>
This function is identical to nxt_ustr2str(), except that it takes
a nxt_str_t structure as input, instead of a 'u_char *' and a size.

The documentation of the function:

/*
 * SYNOPSIS
 *      void nxt_usts2str(char dst[restrict .src-&gt;length+1],
 *                        const nxt_str_t *restrict src);
 *
 * ARGUMENTS
 *      dst     Pointer to the first byte of the destination buffer.
 *      src     Pointer to the source Unterminated STring Structure.
 *
 * DESCRIPTION
 *      Copy a string from the source nxt_str_t, which may be
 *      not-NUL-terminated, into a NUL-terminated string in the
 *      destination buffer.
 *
 * CAVEATS
 *      If the destination buffer is not wider than the source buffer
 *      at least by 1 byte, the behavior is undefined.
 *
 * EXAMPLES
 *      nxt_str_t  src = nxt_string("0123456789");
 *      char       dst[src.length + 1];
 *
 *      nxt_usts2str(dst, &amp;src);
 *
 * SEE ALSO
 *      ustr2str(3), strlcpy(3), strscpy(9)
 */

Suggested-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This function is identical to nxt_ustr2str(), except that it takes
a nxt_str_t structure as input, instead of a 'u_char *' and a size.

The documentation of the function:

/*
 * SYNOPSIS
 *      void nxt_usts2str(char dst[restrict .src-&gt;length+1],
 *                        const nxt_str_t *restrict src);
 *
 * ARGUMENTS
 *      dst     Pointer to the first byte of the destination buffer.
 *      src     Pointer to the source Unterminated STring Structure.
 *
 * DESCRIPTION
 *      Copy a string from the source nxt_str_t, which may be
 *      not-NUL-terminated, into a NUL-terminated string in the
 *      destination buffer.
 *
 * CAVEATS
 *      If the destination buffer is not wider than the source buffer
 *      at least by 1 byte, the behavior is undefined.
 *
 * EXAMPLES
 *      nxt_str_t  src = nxt_string("0123456789");
 *      char       dst[src.length + 1];
 *
 *      nxt_usts2str(dst, &amp;src);
 *
 * SEE ALSO
 *      ustr2str(3), strlcpy(3), strscpy(9)
 */

Suggested-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Added nxt_ustr2str() to make C strings from fixed-width buffers.</title>
<updated>2022-11-16T12:02:04+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-10-25T16:42:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=647c349be1235ce9f43bb53d30e21f4e6dae0bd3'/>
<id>647c349be1235ce9f43bb53d30e21f4e6dae0bd3</id>
<content type='text'>
This function makes it easy to transform a fixed-width buffer
(which is how we represent strings in Unit most of the time) into
a proper C string (NUL-terminated).  We need to do this when
interfacing libraries or the kernel, where most APIs expect
NUL-terminated strings.

The implementation is similar to strncpy_s(3), but avoids the
unnecessary runtime checks.  It's better to wrap the function in a
macro and do as many static_assert(3)s as one considers necessary;
in fact, if in the future C allows backwards VLA syntax, static
analysis could be better than those static_assert(3)s.

We use char for NUL-terminated strings, and u_char for the
*u*nterminated strings.

The documentation for the function:

/*
 * SYNOPSIS
 *   void ustr2str(char dst[restrict .n+1],
 *                 const u_char src[restrict .n],
 *                 size_t n);
 *
 * ARGUMENTS
 *	dst	Pointer to the first byte of the destination buffer.
 *	src	Pointer to the first byte of the source string.
 *	n	Size of 'src'.
 *
 * DESCRIPTION
 *	Copy a string from the fixed-width source string, which may be
 *	not-NUL-terminated, into a NUL-terminated string in the
 *	destination buffer.
 *
 * CAVEATS
 *	If the destination buffer is not wider than the source buffer
 *	at least by 1 byte, the behavior is undefined.
 *
 *	Use of this function normally indicates a problem in the design
 *	of the strings, since normally it's better to guarantee that all
 *	strings are properly terminated.  The main use for this function
 *	is to interface with some standard buffers, such as those
 *	defined in utmp(7), which for historical reasons are not
 *	guaranteed to be terminated.
 *
 * EXAMPLES
 *	u_char  src[10] = "0123456789";  // not NUL-terminated
 *	char    dst[sizeof(src) + 1];
 *
 *	static_assert(lengthof(src) &lt; lengthof(dst))
 *	ustr2str(dst, src, lengthof(src));
 *
 * SEE ALSO
 *	nxt_sts2str(3), strlcpy(3), strscpy(9)
 */

Cc: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This function makes it easy to transform a fixed-width buffer
(which is how we represent strings in Unit most of the time) into
a proper C string (NUL-terminated).  We need to do this when
interfacing libraries or the kernel, where most APIs expect
NUL-terminated strings.

The implementation is similar to strncpy_s(3), but avoids the
unnecessary runtime checks.  It's better to wrap the function in a
macro and do as many static_assert(3)s as one considers necessary;
in fact, if in the future C allows backwards VLA syntax, static
analysis could be better than those static_assert(3)s.

We use char for NUL-terminated strings, and u_char for the
*u*nterminated strings.

The documentation for the function:

/*
 * SYNOPSIS
 *   void ustr2str(char dst[restrict .n+1],
 *                 const u_char src[restrict .n],
 *                 size_t n);
 *
 * ARGUMENTS
 *	dst	Pointer to the first byte of the destination buffer.
 *	src	Pointer to the first byte of the source string.
 *	n	Size of 'src'.
 *
 * DESCRIPTION
 *	Copy a string from the fixed-width source string, which may be
 *	not-NUL-terminated, into a NUL-terminated string in the
 *	destination buffer.
 *
 * CAVEATS
 *	If the destination buffer is not wider than the source buffer
 *	at least by 1 byte, the behavior is undefined.
 *
 *	Use of this function normally indicates a problem in the design
 *	of the strings, since normally it's better to guarantee that all
 *	strings are properly terminated.  The main use for this function
 *	is to interface with some standard buffers, such as those
 *	defined in utmp(7), which for historical reasons are not
 *	guaranteed to be terminated.
 *
 * EXAMPLES
 *	u_char  src[10] = "0123456789";  // not NUL-terminated
 *	char    dst[sizeof(src) + 1];
 *
 *	static_assert(lengthof(src) &lt; lengthof(dst))
 *	ustr2str(dst, src, lengthof(src));
 *
 * SEE ALSO
 *	nxt_sts2str(3), strlcpy(3), strscpy(9)
 */

Cc: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Workarounded Ruby bug.</title>
<updated>2022-11-16T12:00:18+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-10-28T00:36:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=e957ddf43d32e8e6d8778c3dc34c50d7f66c5eab'/>
<id>e957ddf43d32e8e6d8778c3dc34c50d7f66c5eab</id>
<content type='text'>
Ruby redefines memcpy(3) in public headers.  Or at least they did until
they fixed it 4 months ago.  We need to undefine their broken definition.

Link: &lt;https://bugs.ruby-lang.org/issues/18893&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Ruby redefines memcpy(3) in public headers.  Or at least they did until
they fixed it 4 months ago.  We need to undefine their broken definition.

Link: &lt;https://bugs.ruby-lang.org/issues/18893&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Added nxt_char_cast() macro for casting safely.</title>
<updated>2022-11-15T14:50:38+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@kernel.org</email>
</author>
<published>2022-11-11T23:48:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=be3ce4f42507c07e55e7ae6389f3ebd544755bb3'/>
<id>be3ce4f42507c07e55e7ae6389f3ebd544755bb3</id>
<content type='text'>
This macro is similar to C++'s static_cast().  It allows a very-limited
set of casts to be performed, but rejects most casts.  Basically, it
only allows converting from char to u_char and vice-versa, while
respecting the const qualifier.

/*
 * SYNOPSIS
 *      type char_cast(type, string);
 *
 * ARGUMENTS
 *      type    Type to which 'string' should be cast.
 *      string  String that should be cast to 'type'.  It should be a
 *              pointer, or a pointer to a pointer, to a character type,
 *              possibly const-qualified.
 *
 * DESCRIPTION
 *      This macro resembles C++'s static_cast().  It performs a cast,
 *      as if '(type) string' was written, but it performs additional
 *      checks that make sure the cast is limited to character types,
 *      that the input expression is also of a character type, and that
 *      it doesn't remove a const qualifier.
 *
 *      It also makes it easier to find all casts easily with grep(1).
 *
 * CAVEATS
 *      It doesn't allow using 'volatile'.  However, this isn't a big
 *      issue, since we don't use it with strings.  If necessary, the
 *      macro can be improved to support volatile.
 *
 * EXAMPLES
 *      int         *ip = &amp;i;
 *      char        *s = "foo";
 *      const char  *cs = "bar";
 *
 *      p = (char *) s;             /* OK.  Although unsafe, because it
 *                                     can be confused with the case in
 *                                     the next line. */
 *      p = (char *) cs;            /* Very unsafe; it will probably
 *                                     result in Undefined Behaviour. */
 *
 *      p = char_cast(char *, s);   // OK.
 *      p = char_cast(char *, cs);  // Compiler error.  Cast not allowed.
 *
 *      p = (const char *) s;       // OK.
 *      p = (const char *) cs;      // OK.
 *
 *      p = char_cast(const char *, s);   // OK.
 *      p = char_cast(const char *, cs);  // OK.
 *
 *      p = (int *) cs;             /* Extremely unsafe; it will almost
 *                                     certainly result in Undefined
 *                                     Behaviour. */
 *      p = char_cast(int *, cs);   // Compiler error.  Cast not allowed.
 *
 *      p = (char *) ip;            /* Technically OK, but probably
 *                                     not what you want. */
 *      p = char_cast(char *, ip);  // Compiler error.  Cast not allowed.
 *
 * SEE ALSO
 *      _Generic(3)
 */

Acked-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This macro is similar to C++'s static_cast().  It allows a very-limited
set of casts to be performed, but rejects most casts.  Basically, it
only allows converting from char to u_char and vice-versa, while
respecting the const qualifier.

/*
 * SYNOPSIS
 *      type char_cast(type, string);
 *
 * ARGUMENTS
 *      type    Type to which 'string' should be cast.
 *      string  String that should be cast to 'type'.  It should be a
 *              pointer, or a pointer to a pointer, to a character type,
 *              possibly const-qualified.
 *
 * DESCRIPTION
 *      This macro resembles C++'s static_cast().  It performs a cast,
 *      as if '(type) string' was written, but it performs additional
 *      checks that make sure the cast is limited to character types,
 *      that the input expression is also of a character type, and that
 *      it doesn't remove a const qualifier.
 *
 *      It also makes it easier to find all casts easily with grep(1).
 *
 * CAVEATS
 *      It doesn't allow using 'volatile'.  However, this isn't a big
 *      issue, since we don't use it with strings.  If necessary, the
 *      macro can be improved to support volatile.
 *
 * EXAMPLES
 *      int         *ip = &amp;i;
 *      char        *s = "foo";
 *      const char  *cs = "bar";
 *
 *      p = (char *) s;             /* OK.  Although unsafe, because it
 *                                     can be confused with the case in
 *                                     the next line. */
 *      p = (char *) cs;            /* Very unsafe; it will probably
 *                                     result in Undefined Behaviour. */
 *
 *      p = char_cast(char *, s);   // OK.
 *      p = char_cast(char *, cs);  // Compiler error.  Cast not allowed.
 *
 *      p = (const char *) s;       // OK.
 *      p = (const char *) cs;      // OK.
 *
 *      p = char_cast(const char *, s);   // OK.
 *      p = char_cast(const char *, cs);  // OK.
 *
 *      p = (int *) cs;             /* Extremely unsafe; it will almost
 *                                     certainly result in Undefined
 *                                     Behaviour. */
 *      p = char_cast(int *, cs);   // Compiler error.  Cast not allowed.
 *
 *      p = (char *) ip;            /* Technically OK, but probably
 *                                     not what you want. */
 *      p = char_cast(char *, ip);  // Compiler error.  Cast not allowed.
 *
 * SEE ALSO
 *      _Generic(3)
 */

Acked-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Added NXT_HAVE_C11_GENERIC.</title>
<updated>2022-11-15T14:50:38+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@kernel.org</email>
</author>
<published>2022-11-11T23:41:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=947f7c6896c950ca575446e2676424a402efd081'/>
<id>947f7c6896c950ca575446e2676424a402efd081</id>
<content type='text'>
Test if _Generic(3) is available.  Although we require GNU C11, some
old compilers, like the one in CentOS 7 still don't have full support
for C11, and _Generic(3) is not available there.

Acked-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Test if _Generic(3) is available.  Although we require GNU C11, some
old compilers, like the one in CentOS 7 still don't have full support
for C11, and _Generic(3) is not available there.

Acked-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Requiring GNU C11.</title>
<updated>2022-11-15T14:50:38+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-10-27T23:49:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=9b2f2e1c3f4890810461482d23740e116412a7bc'/>
<id>9b2f2e1c3f4890810461482d23740e116412a7bc</id>
<content type='text'>
Suggested-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Suggested-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Using nxt_sizeof_array() instead of sizeof() for strings (arrays).</title>
<updated>2022-11-15T14:50:20+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-11-07T10:27:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=d9a43d25a03d889a54401024cac372997bdb4b4c'/>
<id>d9a43d25a03d889a54401024cac372997bdb4b4c</id>
<content type='text'>
The new documentation for nxt_length() is:

/*
 * SYNOPSIS
 *      size_t nxt_length(string-literal);
 *
 * ARGUMENTS
 *      string-literal
 *              String literal of which we want to measure its length.
 *
 * DESCRIPTION
 *      This macro measures the length (as strlen(3) would do) of a
 *      string literal.
 *
 *      It is functionally-equivalent to 'sizeof(s) - 1', and in fact,
 *      it uses sizeof(), so it shouldn't be used with strings that
 *      aren't string literals.
 *
 *      This macro is safe from most misuses, since it guarantees that
 *      the argument is an array.  If the argument is a pointer instead
 *      of an array, it will generate a compiler warning:
 *      '-Wsizeof-pointer-div'.  This will avoid most silly mistakes.
 *
 * EXAMPLES
 *      size_t  len;
 *
 *      len = sizeof(1 ? "a" : "b");      // 8; this is not what you want/
 *      len = nxt_length(1 ? "a" : "b");  // Compiler warning.
 *
 * SEE ALSO
 *      &lt;https://stackoverflow.com/a/57537491&gt;
 */

sizeof() should never be used to get the size of an array.  It is
very unsafe, since arrays easily decay to pointers, and sizeof()
applied to a pointer gives false results that compile and produce
silent bugs.

It's better to use nxt_sizeof_array(), which implements sizeof()
division, which recent compilers warn when used with pointers.

This change would have avoided a bug that we almost introduced
recently by using:

    nxt_str_set(&amp;port, (r-&gt;tls ? "https://" : "http://"));

which in the macro expansion runs:

    (&amp;port)-&gt;length = nxt_length((r-&gt;tls ? : "https://" : "http://"));

which evaluates to:

    port.length = sizeof(r-&gt;tls ? "https://" : "http://") - 1;

which evaluates to:

    port.length = 8 - 1;

Of course, we didn't want a compile-time-constant 8 there, but
rather the length of the string.

The above bug is not obvious to the untrained eye, so let's show some
example programs that may give some more hints about the problem.

$ cat sizeof.c
 #include &lt;stdio.h&gt;

int
main(void)
{
    printf("%zu\n", sizeof("01"));
    printf("%zu\n", sizeof("012"));
    printf("%zu\n", sizeof(char *));
}
$ cc -Wall -Wextra sizeof.c
$ ./a.out
3
4
8

sizeof() returns the size in bytes of the array passed to it, which in
case of char strings, it is equivalent to the length of the string + 1
(for the terminating '\0').

However, arrays decay very easily in C, and they decay to a pointer to
the first element in the array.  In case of strings, that is a 'char *'.

When sizeof() is given a pointer, it returns the size of the pointer,
which in most platforms is 8.

The ternary operator (?) performs default promotions (and other
nefarious stuff) that may surprise even the most experienced
programmers.  It contrasts the __builtin_choose_expr() GCC builtin [1],
which performs almost equivalently, but without the unwanted effects of
the ternary operator.

[1]: &lt;https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fchoose_005fexpr&gt;

$ cat ?.c
 #include &lt;stdio.h&gt;

int
main(void)
{
    printf("%zu\n", sizeof("01"));
    printf("%zu\n", sizeof(__builtin_choose_expr(1, "01", "01")));
    printf("%zu\n", sizeof(1 ? "01" : "01"));
    printf("%zu\n", sizeof(char *));
}
$ cc -Wall -Wextra ?.c
$ ./a.out
3
3
8
8

In the above program, we can see how the ternary operator (?) decays
the array into a pointer, and makes it so that sizeof() will return a
constant 8.

As we can see, everything in the use of the macro would make it look
like it should work, but the combination of some seemingly-safe side
effects of various C features produces a completely unexpected bug.

The bug dissected here was originally found in our Review Board:
&lt;https://rb.nginx.com/r/1113/#review4063&gt;
even though it was not fully understood what was causing it.

Link: &lt;https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c/57537491#57537491&gt;
Cc: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The new documentation for nxt_length() is:

/*
 * SYNOPSIS
 *      size_t nxt_length(string-literal);
 *
 * ARGUMENTS
 *      string-literal
 *              String literal of which we want to measure its length.
 *
 * DESCRIPTION
 *      This macro measures the length (as strlen(3) would do) of a
 *      string literal.
 *
 *      It is functionally-equivalent to 'sizeof(s) - 1', and in fact,
 *      it uses sizeof(), so it shouldn't be used with strings that
 *      aren't string literals.
 *
 *      This macro is safe from most misuses, since it guarantees that
 *      the argument is an array.  If the argument is a pointer instead
 *      of an array, it will generate a compiler warning:
 *      '-Wsizeof-pointer-div'.  This will avoid most silly mistakes.
 *
 * EXAMPLES
 *      size_t  len;
 *
 *      len = sizeof(1 ? "a" : "b");      // 8; this is not what you want/
 *      len = nxt_length(1 ? "a" : "b");  // Compiler warning.
 *
 * SEE ALSO
 *      &lt;https://stackoverflow.com/a/57537491&gt;
 */

sizeof() should never be used to get the size of an array.  It is
very unsafe, since arrays easily decay to pointers, and sizeof()
applied to a pointer gives false results that compile and produce
silent bugs.

It's better to use nxt_sizeof_array(), which implements sizeof()
division, which recent compilers warn when used with pointers.

This change would have avoided a bug that we almost introduced
recently by using:

    nxt_str_set(&amp;port, (r-&gt;tls ? "https://" : "http://"));

which in the macro expansion runs:

    (&amp;port)-&gt;length = nxt_length((r-&gt;tls ? : "https://" : "http://"));

which evaluates to:

    port.length = sizeof(r-&gt;tls ? "https://" : "http://") - 1;

which evaluates to:

    port.length = 8 - 1;

Of course, we didn't want a compile-time-constant 8 there, but
rather the length of the string.

The above bug is not obvious to the untrained eye, so let's show some
example programs that may give some more hints about the problem.

$ cat sizeof.c
 #include &lt;stdio.h&gt;

int
main(void)
{
    printf("%zu\n", sizeof("01"));
    printf("%zu\n", sizeof("012"));
    printf("%zu\n", sizeof(char *));
}
$ cc -Wall -Wextra sizeof.c
$ ./a.out
3
4
8

sizeof() returns the size in bytes of the array passed to it, which in
case of char strings, it is equivalent to the length of the string + 1
(for the terminating '\0').

However, arrays decay very easily in C, and they decay to a pointer to
the first element in the array.  In case of strings, that is a 'char *'.

When sizeof() is given a pointer, it returns the size of the pointer,
which in most platforms is 8.

The ternary operator (?) performs default promotions (and other
nefarious stuff) that may surprise even the most experienced
programmers.  It contrasts the __builtin_choose_expr() GCC builtin [1],
which performs almost equivalently, but without the unwanted effects of
the ternary operator.

[1]: &lt;https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fchoose_005fexpr&gt;

$ cat ?.c
 #include &lt;stdio.h&gt;

int
main(void)
{
    printf("%zu\n", sizeof("01"));
    printf("%zu\n", sizeof(__builtin_choose_expr(1, "01", "01")));
    printf("%zu\n", sizeof(1 ? "01" : "01"));
    printf("%zu\n", sizeof(char *));
}
$ cc -Wall -Wextra ?.c
$ ./a.out
3
3
8
8

In the above program, we can see how the ternary operator (?) decays
the array into a pointer, and makes it so that sizeof() will return a
constant 8.

As we can see, everything in the use of the macro would make it look
like it should work, but the combination of some seemingly-safe side
effects of various C features produces a completely unexpected bug.

The bug dissected here was originally found in our Review Board:
&lt;https://rb.nginx.com/r/1113/#review4063&gt;
even though it was not fully understood what was causing it.

Link: &lt;https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c/57537491#57537491&gt;
Cc: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Added nxt_sizeof_array() to safely use sizeof() on arrays.</title>
<updated>2022-11-15T12:05:23+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2022-11-15T11:24:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=269bc8e4e86b6be5cd7acd5ca41b1a86a9032c8c'/>
<id>269bc8e4e86b6be5cd7acd5ca41b1a86a9032c8c</id>
<content type='text'>
This macro is just sizeof(array), with compiler warnings for when the
input is not an array.  nxt_nitems() will trigger -Wsizeof-pointer-div
when the input is not an array.  The multiplication by 0 is to ignore
the result of nxt_nitems(), which we only want for the warning.

/*
 * SYNOPSIS
 *      size_t sizeof_array(array);
 *
 * ARGUMENTS
 *      array   Array to be sized.
 *
 * DESCRIPTION
 *      Measure the size of an array --equivalent to sizeof(array)--.
 *      This macro has the benefit that it triggers the warning
 *      '-Wsizeof-pointer-div' when the argument is a pointer instead
 *      of an array, which can cause subtle bugs, sometimes impossible
 *      to detect through tests.
 *
 * EXAMPLES
 *      int     *p;
 *      int     a[1];
 *      size_t  sp, sa;
 *
 *      sp = sizeof_array(p);  // Warning: -Wsizeof-pointer-div
 *      sa = sizeof_array(a);  // OK
 *
 * SEE ALSO
 *      &lt;https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c/57537491#57537491&gt;
 */

Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This macro is just sizeof(array), with compiler warnings for when the
input is not an array.  nxt_nitems() will trigger -Wsizeof-pointer-div
when the input is not an array.  The multiplication by 0 is to ignore
the result of nxt_nitems(), which we only want for the warning.

/*
 * SYNOPSIS
 *      size_t sizeof_array(array);
 *
 * ARGUMENTS
 *      array   Array to be sized.
 *
 * DESCRIPTION
 *      Measure the size of an array --equivalent to sizeof(array)--.
 *      This macro has the benefit that it triggers the warning
 *      '-Wsizeof-pointer-div' when the argument is a pointer instead
 *      of an array, which can cause subtle bugs, sometimes impossible
 *      to detect through tests.
 *
 * EXAMPLES
 *      int     *p;
 *      int     a[1];
 *      size_t  sp, sa;
 *
 *      sp = sizeof_array(p);  // Warning: -Wsizeof-pointer-div
 *      sa = sizeof_array(a);  // OK
 *
 * SEE ALSO
 *      &lt;https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c/57537491#57537491&gt;
 */

Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: fixed _check_processes() checks in "--restart" mode.</title>
<updated>2022-11-15T01:07:41+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2022-11-15T01:07:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=9ea5ed2813c7dc57c8997ef21d779baae19d784c'/>
<id>9ea5ed2813c7dc57c8997ef21d779baae19d784c</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
</feed>
