public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer
@ 2016-06-02 23:22 Martin Sebor
  2016-06-09 18:35 ` [PING] " Martin Sebor
  0 siblings, 1 reply; 5+ messages in thread
From: Martin Sebor @ 2016-06-02 23:22 UTC (permalink / raw)
  To: Gcc Patch List, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 540 bytes --]

In a discussion of a patch in a this area (c/68120 and c++/70507)
Jakub noticed that the integer arithmetic built-ins with overflow
checking that expect a pointer to an integer as the last argument
silently (i.e., without a warning) accept a null pointer.  As the
test case in the bug referenced in in subject shows, such calls
then crash at runtime.

The attached patch follows the same approach used by other built
ins that take a pointer to an object (such as __built_strlen) to
issue a -Wnonnull warning for such invalid calls.

Martin

[-- Attachment #2: gcc-71392.diff --]
[-- Type: text/x-patch, Size: 15664 bytes --]

PR c/71392 - SEGV calling integer overflow built-ins with a null pointer

gcc/testsuite/ChangeLog:
2016-06-02  Martin Sebor  <msebor@redhat.com>

	PR c/71392
	* c-c++-common/builtin-arith-overflow-1.c: Add test cases.

gcc/ChangeLog:
2016-06-02  Martin Sebor  <msebor@redhat.com>

	PR c/71392
	* builtin-attrs.def (ATTR_NOTHROW_NONNULL_LEAF_LIST): New macro.
	* builtins.def (BUILT_IN_SADD_OVERFLOW, BUILT_IN_SADDL_OVERFLOW): Use it.
	(BUILT_IN_SADDLL_OVERFLOW, BUILT_IN_SSUB_OVERFLOW): Same.
	(BUILT_IN_SSUBL_OVERFLOW, BUILT_IN_SSUBLL_OVERFLOW): Same.
	(BUILT_IN_SMUL_OVERFLOW, BUILT_IN_SMULL_OVERFLOW): Same.
	(BUILT_IN_SMULLL_OVERFLOW, BUILT_IN_UADD_OVERFLOW): Same.
	(BUILT_IN_UADDL_OVERFLOW, BUILT_IN_UADDLL_OVERFLOW): Same.
	(BUILT_IN_USUB_OVERFLOW, BUILT_IN_USUBL_OVERFLOW): Same.
	(BUILT_IN_USUBLL_OVERFLOW, BUILT_IN_UMUL_OVERFLOW): Same.
	(BUILT_IN_UMULL_OVERFLOW, BUILT_IN_UMULLL_OVERFLOW):

diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
index 089817a..cefe121 100644
--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -165,6 +165,7 @@ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL, ATTR_NONNULL, ATTR_NULL, \
 /* Nothrow leaf functions whose pointer parameter(s) are all nonnull.  */
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_LEAF, ATTR_NONNULL, ATTR_NULL, \
 			ATTR_NOTHROW_LEAF_LIST)
+DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_LEAF_LIST, ATTR_LEAF, ATTR_NULL, ATTR_NOTHROW_NONNULL_LEAF)
 /* Nothrow functions whose first parameter is a nonnull pointer.  */
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_1, ATTR_NONNULL, ATTR_LIST_1, \
 			ATTR_NOTHROW_LIST)
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 2fc7f65..4df15e4 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -711,24 +711,24 @@ DEF_GCC_BUILTIN        (BUILT_IN_ADD_OVERFLOW, "add_overflow", BT_FN_BOOL_VAR, A
 DEF_GCC_BUILTIN        (BUILT_IN_SUB_OVERFLOW, "sub_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
 DEF_GCC_BUILTIN        (BUILT_IN_MUL_OVERFLOW, "mul_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
 /* Clang compatibility.  */
-DEF_GCC_BUILTIN        (BUILT_IN_SADD_OVERFLOW, "sadd_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SADDL_OVERFLOW, "saddl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SADDLL_OVERFLOW, "saddll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SSUB_OVERFLOW, "ssub_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SSUBL_OVERFLOW, "ssubl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SSUBLL_OVERFLOW, "ssubll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SMUL_OVERFLOW, "smul_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SMULL_OVERFLOW, "smull_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SMULLL_OVERFLOW, "smulll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UADD_OVERFLOW, "uadd_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UADDL_OVERFLOW, "uaddl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UADDLL_OVERFLOW, "uaddll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_USUB_OVERFLOW, "usub_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_USUBL_OVERFLOW, "usubl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_USUBLL_OVERFLOW, "usubll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UMUL_OVERFLOW, "umul_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADD_OVERFLOW, "sadd_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADDL_OVERFLOW, "saddl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADDLL_OVERFLOW, "saddll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUB_OVERFLOW, "ssub_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUBL_OVERFLOW, "ssubl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUBLL_OVERFLOW, "ssubll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMUL_OVERFLOW, "smul_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMULL_OVERFLOW, "smull_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMULLL_OVERFLOW, "smulll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADD_OVERFLOW, "uadd_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADDL_OVERFLOW, "uaddl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADDLL_OVERFLOW, "uaddll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUB_OVERFLOW, "usub_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUBL_OVERFLOW, "usubl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUBLL_OVERFLOW, "usubll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMUL_OVERFLOW, "umul_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
 
 /* Category: miscellaneous builtins.  */
 DEF_LIB_BUILTIN        (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
diff --git a/gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c b/gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c
index 69b5083..9ee787d 100644
--- a/gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c
+++ b/gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c
@@ -1,7 +1,14 @@
+/* Test exercising invalid calls to arithmetic overflow checking built-ins,
+   including PR c/71392 - SEGV calling integer overflow built-ins with a null
+   pointer, (issuing a warning for such invocations).  */
 /* { dg-do compile } */
+/* { dg-additional-options "-Wnonnull" }
+
+/* Verify that calls with fewer or more than 3 arguments to the generic
+   __builtin_op_overflow functions are rejected.  */
 
 int
-f1 (void)
+generic_0 (void)
 {
   int x = __builtin_add_overflow ();	/* { dg-error "not enough arguments to function" } */
   x += __builtin_sub_overflow ();	/* { dg-error "not enough arguments to function" } */
@@ -10,14 +17,178 @@ f1 (void)
 }
 
 int
-f2 (int a, int b, int *c, int d)
+generic_1 (int a)
+{
+  int x = __builtin_add_overflow (a);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow (a);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow (a);	/* { dg-error "not enough arguments to function" } */
+
+  /* Literal argument.  */
+  x += __builtin_add_overflow (1);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow (2);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow (3);	/* { dg-error "not enough arguments to function" } */
+  return x;
+}
+
+int
+generic_2 (int a, int b)
+{
+  int x = __builtin_add_overflow (a, b);/* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow (a, b);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow (a, b);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_add_overflow (a, 1);   /* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow (a, 2);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow (a, 3);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_add_overflow (4, b);   /* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow (5, b);	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow (6, b);	/* { dg-error "not enough arguments to function" } */
+  return x;
+}
+
+/* Verify that calls with the correct number of arguments to the generic
+   __builtin_op_overflow functions are accepted.  */
+
+int
+generic_3 (int a, int b, int c)
+{
+  int x = __builtin_add_overflow (a, b, &c);
+  x += __builtin_sub_overflow (a, b, &c);
+  x += __builtin_mul_overflow (a, b, &c);
+  x += __builtin_add_overflow (a, 1, &c);
+  x += __builtin_sub_overflow (a, 2, &c);
+  x += __builtin_mul_overflow (a, 3, &c);
+  x += __builtin_add_overflow (4, b, &c);
+  x += __builtin_sub_overflow (5, b, &c);
+  x += __builtin_mul_overflow (6, b, &c);
+  x += __builtin_add_overflow (7, 8, &c);
+  x += __builtin_sub_overflow (9, 10, &c);
+  x += __builtin_mul_overflow (11, 12, &c);
+
+  /* Verify that a null pointer to an integer is accepted without
+     warning as the last argument.  */
+  x += __builtin_add_overflow (a, b, (int *)0);
+  x += __builtin_sub_overflow (a, b, (int *)0);
+  x += __builtin_mul_overflow (a, b, (int *)0);
+  x += __builtin_add_overflow (a, 1, (int *)0);
+  x += __builtin_sub_overflow (a, 2, (int *)0);
+  x += __builtin_mul_overflow (a, 3, (int *)0);
+  x += __builtin_add_overflow (4, b, (int *)0);
+  x += __builtin_sub_overflow (5, b, (int *)0);
+  x += __builtin_mul_overflow (6, b, (int *)0);
+  x += __builtin_add_overflow (7, 8, (int *)0);
+  x += __builtin_sub_overflow (9, 10, (int *)0);
+  x += __builtin_mul_overflow (11, 12, (int *)0);
+
+  return x;
+}
+
+int
+generic_4 (int a, int b, int *c, int d)
 {
   int x = __builtin_add_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
-  x += __builtin_sub_overflow (a, b, c, d, d, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_sub_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
   x += __builtin_mul_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
   return x;
 }
 
+/* Verify that calls with fewer or more than 3 arguments to the type
+   specific forms of the __builtin_op_overflow functions are rejected.  */
+
+int
+generic_wrong_type (int a, int b)
+{
+  void *p = 0;
+  double d = 0;
+  int x = __builtin_add_overflow (a, b, p);   /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_sub_overflow (a, b, &p);     /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_mul_overflow (a, b, &d);     /* { dg-error "does not have pointer to integer type" } */
+
+  /* Also verify literal arguments.  */
+  x += __builtin_add_overflow (1, 1, p);   /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_sub_overflow (1, 1, &p);     /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_mul_overflow (1, 1, &d);     /* { dg-error "does not have pointer to integer type" } */
+  return x;
+}
+
+/* Verify that calls with fewer than 2 or more than 3 arguments to
+   the typed __builtin_op_overflow functions are rejected.  */
+int
+typed_0 (void)
+{
+  int x = __builtin_add_overflow ();	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow ();	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow ();	/* { dg-error "not enough arguments to function" } */
+  return x;
+}
+
+int
+typed_1 (int a)
+{
+  int x = __builtin_sadd_overflow (a);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_ssub_overflow (a);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_smul_overflow (a);	/* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+int
+typed_2 (int a, int b)
+{
+  int x = __builtin_sadd_overflow (a, b);  /* { dg-error "too few arguments to function" } */
+  x += __builtin_ssub_overflow (a, b);	   /* { dg-error "too few arguments to function" } */
+  x += __builtin_smul_overflow (a, b);	   /* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+/* Exercise PR c/71392 - SEGV calling integer overflow built-ins with
+   a null pointer.  Verify that calls with a null argument are diagnosed
+   with -Wnonnull.  */
+
+int
+typed_3_null (int a, int b)
+{
+  int x = 0;
+
+  x += __builtin_sadd_overflow (a, b, (int *)0); /* { dg-warning "null argument" } */
+  x += __builtin_uadd_overflow (a, b, (unsigned *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_saddl_overflow (a, b, (long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_uaddl_overflow (a, b, (unsigned long *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_saddll_overflow (a, b, (long long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_uaddll_overflow (a, b, (unsigned long long *)0); /* { dg-warning "null argument" } */
+
+
+  x += __builtin_ssub_overflow (a, b, (int *)0); /* { dg-warning "null argument" } */
+  x += __builtin_usub_overflow (a, b, (unsigned *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_ssubl_overflow (a, b, (long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_usubl_overflow (a, b, (unsigned long *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_ssubll_overflow (a, b, (long long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_usubll_overflow (a, b, (unsigned long long *)0); /* { dg-warning "null argument" } */
+
+
+  x += __builtin_smul_overflow (a, b, (int *)0); /* { dg-warning "null argument" } */
+  x += __builtin_umul_overflow (a, b, (unsigned *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_smull_overflow (a, b, (long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_umull_overflow (a, b, (unsigned long *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_smulll_overflow (a, b, (long long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_umulll_overflow (a, b, (unsigned long long *)0); /* { dg-warning "null argument" } */
+
+  return x;
+}
+
+int
+typed_4 (int a, int b, int *c, int d)
+{
+  int x = __builtin_sadd_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_ssub_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_smul_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  return x;
+}
+
 enum E { e0 = 0, e1 = 1 };
 
 #ifndef __cplusplus

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PING] [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer
  2016-06-02 23:22 [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer Martin Sebor
@ 2016-06-09 18:35 ` Martin Sebor
  2016-06-09 21:27   ` Jeff Law
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Martin Sebor @ 2016-06-09 18:35 UTC (permalink / raw)
  To: Gcc Patch List, Jakub Jelinek, Eric Botcazou, Richard Biener,
	Marek Polacek

[-- Attachment #1: Type: text/plain, Size: 1022 bytes --]

Attached is an updated version of the original patch described
below to annotate with the nonnull attribute the Built-In Functions
to Perform Arithmetic with Overflow Checking.

Since the machinery that's in place doesn't handle the attribute
on type-generic built-ins changes to the (handle_nonnull_attribute
function in Ada and LTO besides C were required so I CC the
maintainers for these areas.

Thanks
Martin

On 06/02/2016 05:22 PM, Martin Sebor wrote:
> In a discussion of a patch in a this area (c/68120 and c++/70507)
> Jakub noticed that the integer arithmetic built-ins with overflow
> checking that expect a pointer to an integer as the last argument
> silently (i.e., without a warning) accept a null pointer.  As the
> test case in the bug referenced in in subject shows, such calls
> then crash at runtime.
>
> The attached patch follows the same approach used by other built
> ins that take a pointer to an object (such as __built_strlen) to
> issue a -Wnonnull warning for such invalid calls.
>
> Martin


[-- Attachment #2: gcc-71392.diff --]
[-- Type: text/x-patch, Size: 21185 bytes --]

PR c/71392 - SEGV calling integer overflow built-ins with a null pointer

gcc/ChangeLog:

	PR c/71392
	* builtin-attrs.def (ATTR_NOTHROW_NONNULL_LEAF_LIST): New macro.
	(ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF): Same.
	* builtins.def (BUILT_IN_SADD_OVERFLOW, BUILT_IN_SADDL_OVERFLOW): Use
	them.
	(BUILT_IN_SADDLL_OVERFLOW, BUILT_IN_SSUB_OVERFLOW): Same.
	(BUILT_IN_SSUBL_OVERFLOW, BUILT_IN_SSUBLL_OVERFLOW): Same.
	(BUILT_IN_SMUL_OVERFLOW, BUILT_IN_SMULL_OVERFLOW): Same.
	(BUILT_IN_SMULLL_OVERFLOW, BUILT_IN_UADD_OVERFLOW): Same.
	(BUILT_IN_UADDL_OVERFLOW, BUILT_IN_UADDLL_OVERFLOW): Same.
	(BUILT_IN_USUB_OVERFLOW, BUILT_IN_USUBL_OVERFLOW): Same.
	(BUILT_IN_USUBLL_OVERFLOW, BUILT_IN_UMUL_OVERFLOW): Same.
	(BUILT_IN_UMULL_OVERFLOW, BUILT_IN_UMULLL_OVERFLOW):

gcc/ada/ChangeLog:

	PR c/71392
	* gcc/ada/gcc-interface/utils.c (handle_nonnull_attribute): Accept
	the nonnull attribute in type-generic builtins.

gcc/c-family/ChangeLog:

	PR c/71392
	* gcc/c-family/c-common.c (handle_nonnull_attribute): Accept
	the nonnull attribute in type-generic builtins.

gcc/lto/ChangeLog:

	PR c/71392
	* gcc/lto/lto-lang.c (handle_nonnull_attribute): Accept the nonnull
	attribute in type-generic builtins.

gcc/testsuite/ChangeLog:

	PR c/71392
	* c-c++-common/builtin-arith-overflow-1.c: Add test cases.

Index: gcc/ada/gcc-interface/utils.c
===================================================================
--- gcc/ada/gcc-interface/utils.c	(revision 237267)
+++ gcc/ada/gcc-interface/utils.c	(working copy)
@@ -5833,10 +5833,14 @@
 
   /* If no arguments are specified, all pointer arguments should be
      non-null.  Verify a full prototype is given so that the arguments
-     will have the correct types when we actually check them later.  */
+     will have the correct types when we actually check them later.
+     Avoid diagnosing type-generic built-ins since those have no
+     prototype.  */
   if (!args)
     {
-      if (!prototype_p (type))
+      if (!prototype_p (type)
+	  && TYPE_ATTRIBUTES (type)
+	  && !lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)))
 	{
 	  error ("nonnull attribute without arguments on a non-prototype");
 	  *no_add_attrs = true;
Index: gcc/builtin-attrs.def
===================================================================
--- gcc/builtin-attrs.def	(revision 237267)
+++ gcc/builtin-attrs.def	(working copy)
@@ -165,6 +165,7 @@
 /* Nothrow leaf functions whose pointer parameter(s) are all nonnull.  */
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_LEAF, ATTR_NONNULL, ATTR_NULL, \
 			ATTR_NOTHROW_LEAF_LIST)
+DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_LEAF_LIST, ATTR_LEAF, ATTR_NULL, ATTR_NOTHROW_NONNULL_LEAF)
 /* Nothrow functions whose first parameter is a nonnull pointer.  */
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_1, ATTR_NONNULL, ATTR_LIST_1, \
 			ATTR_NOTHROW_LIST)
@@ -183,6 +184,10 @@
 /* Nothrow leaf functions which are type-generic.  */
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_TYPEGENERIC_LEAF, ATTR_TYPEGENERIC, ATTR_NULL, \
 			ATTR_NOTHROW_LEAF_LIST)
+/* Nothrow nonnull leaf functions that are type-generic.  */
+DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF,
+		    ATTR_TYPEGENERIC, ATTR_NULL,
+		    ATTR_NOTHROW_NONNULL_LEAF)
 /* Nothrow const functions whose pointer parameter(s) are all nonnull.  */
 DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_NONNULL, ATTR_CONST, ATTR_NULL, \
 			ATTR_NOTHROW_NONNULL)
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def	(revision 237267)
+++ gcc/builtins.def	(working copy)
@@ -707,31 +707,31 @@
 DEF_C94_BUILTIN        (BUILT_IN_TOWUPPER, "towupper", BT_FN_WINT_WINT, ATTR_PURE_NOTHROW_LEAF_LIST)
 
 /* Category: integer overflow checking builtins.  */
-DEF_GCC_BUILTIN        (BUILT_IN_ADD_OVERFLOW, "add_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
-DEF_GCC_BUILTIN        (BUILT_IN_SUB_OVERFLOW, "sub_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
-DEF_GCC_BUILTIN        (BUILT_IN_MUL_OVERFLOW, "mul_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
+DEF_GCC_BUILTIN        (BUILT_IN_ADD_OVERFLOW, "add_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF)
+DEF_GCC_BUILTIN        (BUILT_IN_SUB_OVERFLOW, "sub_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF)
+DEF_GCC_BUILTIN        (BUILT_IN_MUL_OVERFLOW, "mul_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF)
 DEF_GCC_BUILTIN        (BUILT_IN_ADD_OVERFLOW_P, "add_overflow_p", BT_FN_BOOL_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
 DEF_GCC_BUILTIN        (BUILT_IN_SUB_OVERFLOW_P, "sub_overflow_p", BT_FN_BOOL_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
 DEF_GCC_BUILTIN        (BUILT_IN_MUL_OVERFLOW_P, "mul_overflow_p", BT_FN_BOOL_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
 /* Clang compatibility.  */
-DEF_GCC_BUILTIN        (BUILT_IN_SADD_OVERFLOW, "sadd_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SADDL_OVERFLOW, "saddl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SADDLL_OVERFLOW, "saddll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SSUB_OVERFLOW, "ssub_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SSUBL_OVERFLOW, "ssubl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SSUBLL_OVERFLOW, "ssubll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SMUL_OVERFLOW, "smul_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SMULL_OVERFLOW, "smull_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_SMULLL_OVERFLOW, "smulll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UADD_OVERFLOW, "uadd_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UADDL_OVERFLOW, "uaddl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UADDLL_OVERFLOW, "uaddll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_USUB_OVERFLOW, "usub_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_USUBL_OVERFLOW, "usubl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_USUBLL_OVERFLOW, "usubll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UMUL_OVERFLOW, "umul_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN        (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADD_OVERFLOW, "sadd_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADDL_OVERFLOW, "saddl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADDLL_OVERFLOW, "saddll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUB_OVERFLOW, "ssub_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUBL_OVERFLOW, "ssubl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUBLL_OVERFLOW, "ssubll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMUL_OVERFLOW, "smul_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMULL_OVERFLOW, "smull_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMULLL_OVERFLOW, "smulll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADD_OVERFLOW, "uadd_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADDL_OVERFLOW, "uaddl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADDLL_OVERFLOW, "uaddll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUB_OVERFLOW, "usub_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUBL_OVERFLOW, "usubl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUBLL_OVERFLOW, "usubll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMUL_OVERFLOW, "umul_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_NONNULL_LEAF_LIST)
 
 /* Category: miscellaneous builtins.  */
 DEF_LIB_BUILTIN        (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 237268)
+++ gcc/c-family/c-common.c	(working copy)
@@ -9040,10 +9040,14 @@
 
   /* If no arguments are specified, all pointer arguments should be
      non-null.  Verify a full prototype is given so that the arguments
-     will have the correct types when we actually check them later.  */
+     will have the correct types when we actually check them later.
+     Avoid diagnosing type-generic built-ins since those have no
+     prototype.  */
   if (!args)
     {
-      if (!prototype_p (type))
+      if (!prototype_p (type)
+	  && TYPE_ATTRIBUTES (type)
+	  && !lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)))
 	{
 	  error ("nonnull attribute without arguments on a non-prototype");
 	  *no_add_attrs = true;
Index: gcc/lto/lto-lang.c
===================================================================
--- gcc/lto/lto-lang.c	(revision 237267)
+++ gcc/lto/lto-lang.c	(working copy)
@@ -352,10 +352,14 @@
 
   /* If no arguments are specified, all pointer arguments should be
      non-null.  Verify a full prototype is given so that the arguments
-     will have the correct types when we actually check them later.  */
+     will have the correct types when we actually check them later.
+     Avoid diagnosing type-generic built-ins since those have no
+     prototype.  */
   if (!args)
     {
-      gcc_assert (prototype_p (type));
+      gcc_assert (prototype_p (type)
+		  || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)))
+
       return NULL_TREE;
     }
 
Index: gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c	(revision 237268)
+++ gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c	(working copy)
@@ -1,7 +1,18 @@
+/* Test exercising invalid calls to arithmetic overflow checking built-ins,
+   including PR c/71392 - SEGV calling integer overflow built-ins with a null
+   pointer, (issuing a warning for such invocations).  */
 /* { dg-do compile } */
+/* { dg-additional-options "-Wnonnull" }
 
+/* Verify that calls with fewer or more than 3 arguments to the generic
+   __builtin_op_overflow functions are rejected.  */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
 int
-f1 (void)
+generic_0 (void)
 {
   int x = __builtin_add_overflow ();	/* { dg-error "too few arguments to function" } */
   x += __builtin_sub_overflow ();	/* { dg-error "too few arguments to function" } */
@@ -13,6 +24,191 @@
 }
 
 int
+generic_1 (int a)
+{
+  int x = __builtin_add_overflow (a);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_sub_overflow (a);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_mul_overflow (a);	/* { dg-error "too few arguments to function" } */
+
+  /* Literal argument.  */
+  x += __builtin_add_overflow (1);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_sub_overflow (2);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_mul_overflow (3);	/* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+int
+generic_2 (int a, int b)
+{
+  int x = __builtin_add_overflow (a, b);/* { dg-error "too few arguments to function" } */
+  x += __builtin_sub_overflow (a, b);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_mul_overflow (a, b);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_add_overflow (a, 1);   /* { dg-error "too few arguments to function" } */
+  x += __builtin_sub_overflow (a, 2);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_mul_overflow (a, 3);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_add_overflow (4, b);   /* { dg-error "too few arguments to function" } */
+  x += __builtin_sub_overflow (5, b);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_mul_overflow (6, b);	/* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+/* Verify that calls with the correct number of arguments to the generic
+   __builtin_op_overflow functions are accepted.  */
+
+int
+generic_3 (int a, int b, int c)
+{
+  int x = __builtin_add_overflow (a, b, &c);
+  x += __builtin_sub_overflow (a, b, &c);
+  x += __builtin_mul_overflow (a, b, &c);
+  x += __builtin_add_overflow (a, 1, &c);
+  x += __builtin_sub_overflow (a, 2, &c);
+  x += __builtin_mul_overflow (a, 3, &c);
+  x += __builtin_add_overflow (4, b, &c);
+  x += __builtin_sub_overflow (5, b, &c);
+  x += __builtin_mul_overflow (6, b, &c);
+  x += __builtin_add_overflow (7, 8, &c);
+  x += __builtin_sub_overflow (9, 10, &c);
+  x += __builtin_mul_overflow (11, 12, &c);
+
+  /* Verify that a null pointer to an integer is diagnosed.  */
+
+  /* The following two are rejected due to c/71479 - error on
+     __builtin_add_overflow with bool or enum pointer as last argument.
+
+    x += __builtin_add_overflow (0, 0, (bool *)0);
+
+    enum E { e0 };
+    x += __builtin_add_overflow (0, 0, (enum E *)0);
+  */
+
+  x += __builtin_sub_overflow (0, 0, (char *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_add_overflow (0, 0, (short *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_add_overflow (a, b, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_sub_overflow (a, b, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_mul_overflow (a, b, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_add_overflow (a, 1, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_sub_overflow (a, 2, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_mul_overflow (a, 3, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_add_overflow (4, b, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_sub_overflow (5, b, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_mul_overflow (6, b, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_add_overflow (7, 8, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_sub_overflow (9, 10, (int *)0);   /* { dg-warning "null argument" } */
+  x += __builtin_mul_overflow (11, 12, (int *)0);   /* { dg-warning "null argument" } */
+
+  return x;
+}
+
+int
+generic_4 (int a, int b, int *c, int d)
+{
+  int x = __builtin_add_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_sub_overflow (a, b, c, d, d, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_sub_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_mul_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  return x;
+}
+
+/* Verify that calls with fewer or more than 3 arguments to the type
+   specific forms of the __builtin_op_overflow functions are rejected.  */
+
+int
+generic_wrong_type (int a, int b)
+{
+  void *p = 0;
+  double d = 0;
+  int x = __builtin_add_overflow (a, b, p);   /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_sub_overflow (a, b, &p);     /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_mul_overflow (a, b, &d);     /* { dg-error "does not have pointer to integer type" } */
+
+  /* Also verify literal arguments.  */
+  x += __builtin_add_overflow (1, 1, p);   /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_sub_overflow (1, 1, &p);     /* { dg-error "does not have pointer to integer type" } */
+  x += __builtin_mul_overflow (1, 1, &d);     /* { dg-error "does not have pointer to integer type" } */
+  return x;
+}
+
+/* Verify that calls with fewer than 2 or more than 3 arguments to
+   the typed __builtin_op_overflow functions are rejected.  */
+int
+typed_0 (void)
+{
+  int x = __builtin_add_overflow ();	/* { dg-error "too few arguments to function" } */
+  x += __builtin_sub_overflow ();	/* { dg-error "too few arguments to function" } */
+  x += __builtin_mul_overflow ();	/* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+int
+typed_1 (int a)
+{
+  int x = __builtin_sadd_overflow (a);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_ssub_overflow (a);	/* { dg-error "too few arguments to function" } */
+  x += __builtin_smul_overflow (a);	/* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+int
+typed_2 (int a, int b)
+{
+  int x = __builtin_sadd_overflow (a, b);  /* { dg-error "too few arguments to function" } */
+  x += __builtin_ssub_overflow (a, b);	   /* { dg-error "too few arguments to function" } */
+  x += __builtin_smul_overflow (a, b);	   /* { dg-error "too few arguments to function" } */
+  return x;
+}
+
+/* Exercise PR c/71392 - SEGV calling integer overflow built-ins with
+   a null pointer.  Verify that calls with a null argument are diagnosed
+   with -Wnonnull.  */
+
+int
+typed_3_null (int a, int b)
+{
+  int x = 0;
+
+  x += __builtin_sadd_overflow (a, b, (int *)0); /* { dg-warning "null argument" } */
+  x += __builtin_uadd_overflow (a, b, (unsigned *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_saddl_overflow (a, b, (long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_uaddl_overflow (a, b, (unsigned long *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_saddll_overflow (a, b, (long long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_uaddll_overflow (a, b, (unsigned long long *)0); /* { dg-warning "null argument" } */
+
+
+  x += __builtin_ssub_overflow (a, b, (int *)0); /* { dg-warning "null argument" } */
+  x += __builtin_usub_overflow (a, b, (unsigned *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_ssubl_overflow (a, b, (long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_usubl_overflow (a, b, (unsigned long *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_ssubll_overflow (a, b, (long long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_usubll_overflow (a, b, (unsigned long long *)0); /* { dg-warning "null argument" } */
+
+
+  x += __builtin_smul_overflow (a, b, (int *)0); /* { dg-warning "null argument" } */
+  x += __builtin_umul_overflow (a, b, (unsigned *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_smull_overflow (a, b, (long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_umull_overflow (a, b, (unsigned long *)0); /* { dg-warning "null argument" } */
+
+  x += __builtin_smulll_overflow (a, b, (long long *)0); /* { dg-warning "null argument" } */
+  x += __builtin_umulll_overflow (a, b, (unsigned long long *)0); /* { dg-warning "null argument" } */
+
+  return x;
+}
+
+int
+typed_4 (int a, int b, int *c, int d)
+{
+  int x = __builtin_sadd_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_ssub_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_smul_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  return x;
+}
+
+int
 f2 (int a, int b, int *c, int d)
 {
   int x = __builtin_add_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
@@ -27,10 +223,6 @@
 
 enum E { e0 = 0, e1 = 1 };
 
-#ifndef __cplusplus
-#define bool _Bool
-#endif
-
 int
 f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb, bool bb, int *c)
 {

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PING] [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer
  2016-06-09 18:35 ` [PING] " Martin Sebor
@ 2016-06-09 21:27   ` Jeff Law
  2016-06-10  7:03   ` Richard Biener
  2016-06-11  7:12   ` Eric Botcazou
  2 siblings, 0 replies; 5+ messages in thread
From: Jeff Law @ 2016-06-09 21:27 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Jakub Jelinek, Eric Botcazou,
	Richard Biener, Marek Polacek

On 06/09/2016 12:34 PM, Martin Sebor wrote:
> Attached is an updated version of the original patch described
> below to annotate with the nonnull attribute the Built-In Functions
> to Perform Arithmetic with Overflow Checking.
>
> Since the machinery that's in place doesn't handle the attribute
> on type-generic built-ins changes to the (handle_nonnull_attribute
> function in Ada and LTO besides C were required so I CC the
> maintainers for these areas.
>
> Thanks
> Martin
>
> On 06/02/2016 05:22 PM, Martin Sebor wrote:
>> In a discussion of a patch in a this area (c/68120 and c++/70507)
>> Jakub noticed that the integer arithmetic built-ins with overflow
>> checking that expect a pointer to an integer as the last argument
>> silently (i.e., without a warning) accept a null pointer.  As the
>> test case in the bug referenced in in subject shows, such calls
>> then crash at runtime.
>>
>> The attached patch follows the same approach used by other built
>> ins that take a pointer to an object (such as __built_strlen) to
>> issue a -Wnonnull warning for such invalid calls.
>>
>> Martin
>
>
> gcc-71392.diff
>
>
> PR c/71392 - SEGV calling integer overflow built-ins with a null pointer
>
> gcc/ChangeLog:
>
> 	PR c/71392
> 	* builtin-attrs.def (ATTR_NOTHROW_NONNULL_LEAF_LIST): New macro.
> 	(ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF): Same.
> 	* builtins.def (BUILT_IN_SADD_OVERFLOW, BUILT_IN_SADDL_OVERFLOW): Use
> 	them.
> 	(BUILT_IN_SADDLL_OVERFLOW, BUILT_IN_SSUB_OVERFLOW): Same.
> 	(BUILT_IN_SSUBL_OVERFLOW, BUILT_IN_SSUBLL_OVERFLOW): Same.
> 	(BUILT_IN_SMUL_OVERFLOW, BUILT_IN_SMULL_OVERFLOW): Same.
> 	(BUILT_IN_SMULLL_OVERFLOW, BUILT_IN_UADD_OVERFLOW): Same.
> 	(BUILT_IN_UADDL_OVERFLOW, BUILT_IN_UADDLL_OVERFLOW): Same.
> 	(BUILT_IN_USUB_OVERFLOW, BUILT_IN_USUBL_OVERFLOW): Same.
> 	(BUILT_IN_USUBLL_OVERFLOW, BUILT_IN_UMUL_OVERFLOW): Same.
> 	(BUILT_IN_UMULL_OVERFLOW, BUILT_IN_UMULLL_OVERFLOW):
>
> gcc/ada/ChangeLog:
>
> 	PR c/71392
> 	* gcc/ada/gcc-interface/utils.c (handle_nonnull_attribute): Accept
> 	the nonnull attribute in type-generic builtins.
>
> gcc/c-family/ChangeLog:
>
> 	PR c/71392
> 	* gcc/c-family/c-common.c (handle_nonnull_attribute): Accept
> 	the nonnull attribute in type-generic builtins.
>
> gcc/lto/ChangeLog:
>
> 	PR c/71392
> 	* gcc/lto/lto-lang.c (handle_nonnull_attribute): Accept the nonnull
> 	attribute in type-generic builtins.
>
> gcc/testsuite/ChangeLog:
>
> 	PR c/71392
> 	* c-c++-common/builtin-arith-overflow-1.c: Add test cases.
OK for the trunk.

THanks,
Jeff

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PING] [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer
  2016-06-09 18:35 ` [PING] " Martin Sebor
  2016-06-09 21:27   ` Jeff Law
@ 2016-06-10  7:03   ` Richard Biener
  2016-06-11  7:12   ` Eric Botcazou
  2 siblings, 0 replies; 5+ messages in thread
From: Richard Biener @ 2016-06-10  7:03 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Gcc Patch List, Jakub Jelinek, Eric Botcazou, Marek Polacek

On Thu, 9 Jun 2016, Martin Sebor wrote:

> Attached is an updated version of the original patch described
> below to annotate with the nonnull attribute the Built-In Functions
> to Perform Arithmetic with Overflow Checking.
> 
> Since the machinery that's in place doesn't handle the attribute
> on type-generic built-ins changes to the (handle_nonnull_attribute
> function in Ada and LTO besides C were required so I CC the
> maintainers for these areas.

The LTO bits are ok.

Richard.

> Thanks
> Martin
> 
> On 06/02/2016 05:22 PM, Martin Sebor wrote:
> > In a discussion of a patch in a this area (c/68120 and c++/70507)
> > Jakub noticed that the integer arithmetic built-ins with overflow
> > checking that expect a pointer to an integer as the last argument
> > silently (i.e., without a warning) accept a null pointer.  As the
> > test case in the bug referenced in in subject shows, such calls
> > then crash at runtime.
> > 
> > The attached patch follows the same approach used by other built
> > ins that take a pointer to an object (such as __built_strlen) to
> > issue a -Wnonnull warning for such invalid calls.
> > 
> > Martin
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PING] [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer
  2016-06-09 18:35 ` [PING] " Martin Sebor
  2016-06-09 21:27   ` Jeff Law
  2016-06-10  7:03   ` Richard Biener
@ 2016-06-11  7:12   ` Eric Botcazou
  2 siblings, 0 replies; 5+ messages in thread
From: Eric Botcazou @ 2016-06-11  7:12 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches, Jakub Jelinek, Richard Biener, Marek Polacek

> Attached is an updated version of the original patch described
> below to annotate with the nonnull attribute the Built-In Functions
> to Perform Arithmetic with Overflow Checking.

3 out of 5 ChangeLog entries are incorrect:

gcc/ada/ChangeLog:

	PR c/71392
	* gcc/ada/gcc-interface/utils.c (handle_nonnull_attribute): Accept
	the nonnull attribute in type-generic builtins.

gcc/c-family/ChangeLog:

	PR c/71392
	* gcc/c-family/c-common.c (handle_nonnull_attribute): Accept
	the nonnull attribute in type-generic builtins.

gcc/lto/ChangeLog:

	PR c/71392
	* gcc/lto/lto-lang.c (handle_nonnull_attribute): Accept the nonnull
	attribute in type-generic builtins.


Prefixes of files must always be relative to the ChangeLog's directory:

gcc/ada/ChangeLog:

	PR c/71392
	* gcc-interface/utils.c (handle_nonnull_attribute): ...

gcc/c-family/ChangeLog:

	PR c/71392
	* c-common.c (handle_nonnull_attribute):...

gcc/lto/ChangeLog:

	PR c/71392
	* lto-lang.c (handle_nonnull_attribute): ...


-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-06-11  7:12 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-02 23:22 [PATCH] c/71392 - SEGV calling integer overflow built-ins with a null pointer Martin Sebor
2016-06-09 18:35 ` [PING] " Martin Sebor
2016-06-09 21:27   ` Jeff Law
2016-06-10  7:03   ` Richard Biener
2016-06-11  7:12   ` Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).