[v5] C, ObjC: Add -Wunterminated-string-initialization

Message ID 20231001162400.68141-1-alx@kernel.org
State Accepted
Headers
Series [v5] C, ObjC: Add -Wunterminated-string-initialization |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Alejandro Colomar Oct. 1, 2023, 4:24 p.m. UTC
  Warn about the following:

    char  s[3] = "foo";

Initializing a char array with a string literal of the same length as
the size of the array is usually a mistake.  Rarely is the case where
one wants to create a non-terminated character sequence from a string
literal.

In some cases, for writing faster code, one may want to use arrays
instead of pointers, since that removes the need for storing an array of
pointers apart from the strings themselves.

    char  *log_levels[]   = { "info", "warning", "err" };
vs.
    char  log_levels[][7] = { "info", "warning", "err" };

This forces the programmer to specify a size, which might change if a
new entry is later added.  Having no way to enforce null termination is
very dangerous, however, so it is useful to have a warning for this, so
that the compiler can make sure that the programmer didn't make any
mistakes.  This warning catches the bug above, so that the programmer
will be able to fix it and write:

    char  log_levels[][8] = { "info", "warning", "err" };

This warning already existed as part of -Wc++-compat, but this patch
allows enabling it separately.  It is also included in -Wextra, since
it may not always be desired (when unterminated character sequences are
wanted), but it's likely to be desired in most cases.

Since Wc++-compat now includes this warning, the test has to be modified
to expect the text of the new warning too, in <gcc.dg/Wcxx-compat-14.c>.

Link: <https://lists.gnu.org/archive/html/groff/2022-11/msg00059.html>
Link: <https://lists.gnu.org/archive/html/groff/2022-11/msg00063.html>
Link: <https://inbox.sourceware.org/gcc/36da94eb-1cac-5ae8-7fea-ec66160cf413@gmail.com/T/>
Acked-by: Doug McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: "G. Branden Robinson" <g.branden.robinson@gmail.com>
Cc: Ralph Corderoy <ralph@inputplus.co.uk>
Cc: Dave Kemper <saint.snit@gmail.com>
Cc: Larry McVoy <lm@mcvoy.com>
Cc: Andrew Pinski <pinskia@gmail.com>
Cc: Jonathan Wakely <jwakely.gcc@gmail.com>
Cc: Andrew Clayton <andrew@digital-domain.net>
Cc: Martin Uecker <muecker@gwdg.de>
Cc: David Malcolm <dmalcolm@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---

v5:

-  Fix existing C++-compat tests.  [reported by <ci_notify@linaro.org>]


 gcc/c-family/c.opt                                         | 4 ++++
 gcc/c/c-typeck.cc                                          | 6 +++---
 gcc/testsuite/gcc.dg/Wcxx-compat-14.c                      | 2 +-
 gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c | 6 ++++++
 4 files changed, 14 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
  

Comments

Alejandro Colomar Oct. 8, 2023, 1:05 p.m. UTC | #1
Hi,

Gentle ping here.

Thanks,
Alex

On Sun, Oct 01, 2023 at 06:24:00PM +0200, Alejandro Colomar wrote:
> Warn about the following:
> 
>     char  s[3] = "foo";
> 
> Initializing a char array with a string literal of the same length as
> the size of the array is usually a mistake.  Rarely is the case where
> one wants to create a non-terminated character sequence from a string
> literal.
> 
> In some cases, for writing faster code, one may want to use arrays
> instead of pointers, since that removes the need for storing an array of
> pointers apart from the strings themselves.
> 
>     char  *log_levels[]   = { "info", "warning", "err" };
> vs.
>     char  log_levels[][7] = { "info", "warning", "err" };
> 
> This forces the programmer to specify a size, which might change if a
> new entry is later added.  Having no way to enforce null termination is
> very dangerous, however, so it is useful to have a warning for this, so
> that the compiler can make sure that the programmer didn't make any
> mistakes.  This warning catches the bug above, so that the programmer
> will be able to fix it and write:
> 
>     char  log_levels[][8] = { "info", "warning", "err" };
> 
> This warning already existed as part of -Wc++-compat, but this patch
> allows enabling it separately.  It is also included in -Wextra, since
> it may not always be desired (when unterminated character sequences are
> wanted), but it's likely to be desired in most cases.
> 
> Since Wc++-compat now includes this warning, the test has to be modified
> to expect the text of the new warning too, in <gcc.dg/Wcxx-compat-14.c>.
> 
> Link: <https://lists.gnu.org/archive/html/groff/2022-11/msg00059.html>
> Link: <https://lists.gnu.org/archive/html/groff/2022-11/msg00063.html>
> Link: <https://inbox.sourceware.org/gcc/36da94eb-1cac-5ae8-7fea-ec66160cf413@gmail.com/T/>
> Acked-by: Doug McIlroy <douglas.mcilroy@dartmouth.edu>
> Cc: "G. Branden Robinson" <g.branden.robinson@gmail.com>
> Cc: Ralph Corderoy <ralph@inputplus.co.uk>
> Cc: Dave Kemper <saint.snit@gmail.com>
> Cc: Larry McVoy <lm@mcvoy.com>
> Cc: Andrew Pinski <pinskia@gmail.com>
> Cc: Jonathan Wakely <jwakely.gcc@gmail.com>
> Cc: Andrew Clayton <andrew@digital-domain.net>
> Cc: Martin Uecker <muecker@gwdg.de>
> Cc: David Malcolm <dmalcolm@redhat.com>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
> 
> v5:
> 
> -  Fix existing C++-compat tests.  [reported by <ci_notify@linaro.org>]
> 
> 
>  gcc/c-family/c.opt                                         | 4 ++++
>  gcc/c/c-typeck.cc                                          | 6 +++---
>  gcc/testsuite/gcc.dg/Wcxx-compat-14.c                      | 2 +-
>  gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c | 6 ++++++
>  4 files changed, 14 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 44b9c862c14..e8f6b836836 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1407,6 +1407,10 @@ Wunsuffixed-float-constants
>  C ObjC Var(warn_unsuffixed_float_constants) Warning
>  Warn about unsuffixed float constants.
>  
> +Wunterminated-string-initialization
> +C ObjC Var(warn_unterminated_string_initialization) Warning LangEnabledBy(C ObjC,Wextra || Wc++-compat)
> +Warn about character arrays initialized as unterminated character sequences by a string literal.
> +
>  Wunused
>  C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wall)
>  ; documented in common.opt
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index e55e887da14..7df9de819ed 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -8399,11 +8399,11 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
>  		pedwarn_init (init_loc, 0,
>  			      ("initializer-string for array of %qT "
>  			       "is too long"), typ1);
> -	      else if (warn_cxx_compat
> +	      else if (warn_unterminated_string_initialization
>  		       && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
> -		warning_at (init_loc, OPT_Wc___compat,
> +		warning_at (init_loc, OPT_Wunterminated_string_initialization,
>  			    ("initializer-string for array of %qT "
> -			     "is too long for C++"), typ1);
> +			     "is too long"), typ1);
>  	      if (compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
>  		{
>  		  unsigned HOST_WIDE_INT size
> diff --git a/gcc/testsuite/gcc.dg/Wcxx-compat-14.c b/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
> index 23783711be6..6df0ee197cc 100644
> --- a/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
> +++ b/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
> @@ -2,5 +2,5 @@
>  /* { dg-options "-Wc++-compat" } */
>  
>  char a1[] = "a";
> -char a2[1] = "a";	/* { dg-warning "C\[+\]\[+\]" } */
> +char a2[1] = "a";	/* { dg-warning "initializer-string for array of 'char' is too long" } */
>  char a3[2] = "a";
> diff --git a/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c b/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
> new file mode 100644
> index 00000000000..13d5dbc6640
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wunterminated-string-initialization" } */
> +
> +char a1[] = "a";
> +char a2[1] = "a";	/* { dg-warning "initializer-string for array of 'char' is too long" } */
> +char a3[2] = "a";
> -- 
> 2.40.1
>
  
Alejandro Colomar Nov. 13, 2023, 9:55 a.m. UTC | #2
Hi,

Gentle ping, just again a little before v14 stage 3.

Do I need to do anything else with this patch?  The CI seemed to say
it's ok.

Cheers,
Alex

On Sun, Oct 01, 2023 at 06:24:00PM +0200, Alejandro Colomar wrote:
> Warn about the following:
> 
>     char  s[3] = "foo";
> 
> Initializing a char array with a string literal of the same length as
> the size of the array is usually a mistake.  Rarely is the case where
> one wants to create a non-terminated character sequence from a string
> literal.
> 
> In some cases, for writing faster code, one may want to use arrays
> instead of pointers, since that removes the need for storing an array of
> pointers apart from the strings themselves.
> 
>     char  *log_levels[]   = { "info", "warning", "err" };
> vs.
>     char  log_levels[][7] = { "info", "warning", "err" };
> 
> This forces the programmer to specify a size, which might change if a
> new entry is later added.  Having no way to enforce null termination is
> very dangerous, however, so it is useful to have a warning for this, so
> that the compiler can make sure that the programmer didn't make any
> mistakes.  This warning catches the bug above, so that the programmer
> will be able to fix it and write:
> 
>     char  log_levels[][8] = { "info", "warning", "err" };
> 
> This warning already existed as part of -Wc++-compat, but this patch
> allows enabling it separately.  It is also included in -Wextra, since
> it may not always be desired (when unterminated character sequences are
> wanted), but it's likely to be desired in most cases.
> 
> Since Wc++-compat now includes this warning, the test has to be modified
> to expect the text of the new warning too, in <gcc.dg/Wcxx-compat-14.c>.
> 
> Link: <https://lists.gnu.org/archive/html/groff/2022-11/msg00059.html>
> Link: <https://lists.gnu.org/archive/html/groff/2022-11/msg00063.html>
> Link: <https://inbox.sourceware.org/gcc/36da94eb-1cac-5ae8-7fea-ec66160cf413@gmail.com/T/>
> Acked-by: Doug McIlroy <douglas.mcilroy@dartmouth.edu>
> Cc: "G. Branden Robinson" <g.branden.robinson@gmail.com>
> Cc: Ralph Corderoy <ralph@inputplus.co.uk>
> Cc: Dave Kemper <saint.snit@gmail.com>
> Cc: Larry McVoy <lm@mcvoy.com>
> Cc: Andrew Pinski <pinskia@gmail.com>
> Cc: Jonathan Wakely <jwakely.gcc@gmail.com>
> Cc: Andrew Clayton <andrew@digital-domain.net>
> Cc: Martin Uecker <muecker@gwdg.de>
> Cc: David Malcolm <dmalcolm@redhat.com>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
> 
> v5:
> 
> -  Fix existing C++-compat tests.  [reported by <ci_notify@linaro.org>]
> 
> 
>  gcc/c-family/c.opt                                         | 4 ++++
>  gcc/c/c-typeck.cc                                          | 6 +++---
>  gcc/testsuite/gcc.dg/Wcxx-compat-14.c                      | 2 +-
>  gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c | 6 ++++++
>  4 files changed, 14 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 44b9c862c14..e8f6b836836 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1407,6 +1407,10 @@ Wunsuffixed-float-constants
>  C ObjC Var(warn_unsuffixed_float_constants) Warning
>  Warn about unsuffixed float constants.
>  
> +Wunterminated-string-initialization
> +C ObjC Var(warn_unterminated_string_initialization) Warning LangEnabledBy(C ObjC,Wextra || Wc++-compat)
> +Warn about character arrays initialized as unterminated character sequences by a string literal.
> +
>  Wunused
>  C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wall)
>  ; documented in common.opt
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index e55e887da14..7df9de819ed 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -8399,11 +8399,11 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
>  		pedwarn_init (init_loc, 0,
>  			      ("initializer-string for array of %qT "
>  			       "is too long"), typ1);
> -	      else if (warn_cxx_compat
> +	      else if (warn_unterminated_string_initialization
>  		       && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
> -		warning_at (init_loc, OPT_Wc___compat,
> +		warning_at (init_loc, OPT_Wunterminated_string_initialization,
>  			    ("initializer-string for array of %qT "
> -			     "is too long for C++"), typ1);
> +			     "is too long"), typ1);
>  	      if (compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
>  		{
>  		  unsigned HOST_WIDE_INT size
> diff --git a/gcc/testsuite/gcc.dg/Wcxx-compat-14.c b/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
> index 23783711be6..6df0ee197cc 100644
> --- a/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
> +++ b/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
> @@ -2,5 +2,5 @@
>  /* { dg-options "-Wc++-compat" } */
>  
>  char a1[] = "a";
> -char a2[1] = "a";	/* { dg-warning "C\[+\]\[+\]" } */
> +char a2[1] = "a";	/* { dg-warning "initializer-string for array of 'char' is too long" } */
>  char a3[2] = "a";
> diff --git a/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c b/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
> new file mode 100644
> index 00000000000..13d5dbc6640
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wunterminated-string-initialization" } */
> +
> +char a1[] = "a";
> +char a2[1] = "a";	/* { dg-warning "initializer-string for array of 'char' is too long" } */
> +char a3[2] = "a";
> -- 
> 2.40.1
>
  

Patch

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44b9c862c14..e8f6b836836 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1407,6 +1407,10 @@  Wunsuffixed-float-constants
 C ObjC Var(warn_unsuffixed_float_constants) Warning
 Warn about unsuffixed float constants.
 
+Wunterminated-string-initialization
+C ObjC Var(warn_unterminated_string_initialization) Warning LangEnabledBy(C ObjC,Wextra || Wc++-compat)
+Warn about character arrays initialized as unterminated character sequences by a string literal.
+
 Wunused
 C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; documented in common.opt
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e55e887da14..7df9de819ed 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -8399,11 +8399,11 @@  digest_init (location_t init_loc, tree type, tree init, tree origtype,
 		pedwarn_init (init_loc, 0,
 			      ("initializer-string for array of %qT "
 			       "is too long"), typ1);
-	      else if (warn_cxx_compat
+	      else if (warn_unterminated_string_initialization
 		       && compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
-		warning_at (init_loc, OPT_Wc___compat,
+		warning_at (init_loc, OPT_Wunterminated_string_initialization,
 			    ("initializer-string for array of %qT "
-			     "is too long for C++"), typ1);
+			     "is too long"), typ1);
 	      if (compare_tree_int (TYPE_SIZE_UNIT (type), len) < 0)
 		{
 		  unsigned HOST_WIDE_INT size
diff --git a/gcc/testsuite/gcc.dg/Wcxx-compat-14.c b/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
index 23783711be6..6df0ee197cc 100644
--- a/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
+++ b/gcc/testsuite/gcc.dg/Wcxx-compat-14.c
@@ -2,5 +2,5 @@ 
 /* { dg-options "-Wc++-compat" } */
 
 char a1[] = "a";
-char a2[1] = "a";	/* { dg-warning "C\[+\]\[+\]" } */
+char a2[1] = "a";	/* { dg-warning "initializer-string for array of 'char' is too long" } */
 char a3[2] = "a";
diff --git a/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c b/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
new file mode 100644
index 00000000000..13d5dbc6640
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wunterminated-string-initialization" } */
+
+char a1[] = "a";
+char a2[1] = "a";	/* { dg-warning "initializer-string for array of 'char' is too long" } */
+char a3[2] = "a";