[ISan] Fix issue with constexpr. 84/158084/8
authorDenis Khalikov <d.khalikov@partner.samsung.com>
Mon, 30 Oct 2017 16:12:50 +0000 (19:12 +0300)
committerDenis Khalikov <d.khalikov@partner.samsung.com>
Thu, 9 Nov 2017 14:39:55 +0000 (17:39 +0300)
The semantic of the constexpr does not allow us
to convert POINTER type to INTERGER type inside constexpr.
All ISAN instrumentation should be folded, but it's
little bit tricky, in case we should convert INTEGER
type back to POINTER type, because INTEGER type could
not be assigned to POINTER type.
Another issue is that some actual value of PARM_DECL
could not be getting by "constexpr context" and
could not be folded.
So, just disable ISAN insrumentation and pointer
conversions for constexpr semantic. In this case we
can rely on current_function_decl while processing function,
but also should handle constexpr with pointers:
constexpr unsigned *pointer = ptr + index;

Change-Id: I68eb660438a1acd881207219c3d72045c445dcb7

gcc/c-family/c-common.c
gcc/cp/parser.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/isan/constexpr.C
gcc/toplev.c

index 22420bb..7068034 100644 (file)
@@ -157,6 +157,8 @@ machine_mode c_default_pointer_mode = VOIDmode;
 
 */
 
+extern bool processing_constexpr_decl;
+
 tree c_global_trees[CTI_MAX];
 \f
 /* Switches common to the C front ends.  */
@@ -4254,7 +4256,9 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
   /* The result is a pointer of the same type that is being added.  */
   tree result_type = TREE_TYPE (ptrop);
 
-  if (flag_sanitize & SANITIZE_UI_OVERFLOW)
+  if ((flag_sanitize & SANITIZE_UI_OVERFLOW)
+      && !((current_function_decl && DECL_LANG_FLAG_8 (current_function_decl))
+          || processing_constexpr_decl))
     {
       /* First, try to avoid FPs if INTOP is negative constant.  */
       if (tree_fits_shwi_p (intop))
@@ -4338,7 +4342,13 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
       intop = wide_int_to_tree (TREE_TYPE (intop), intop);
   }
 
-  if (flag_sanitize & SANITIZE_UI_OVERFLOW)
+  /* Doing this for constexpr will cause an error, even without ISAN
+     instrumentation:  ‘*(const char*)(((long unsigned int)ptr) +
+     ((long unsigned int)index))’ is not a constant expression. So, just disable
+     pointer convertion for constexpr.  */
+  if ((flag_sanitize & SANITIZE_UI_OVERFLOW)
+      && !((current_function_decl && DECL_LANG_FLAG_8 (current_function_decl))
+          || processing_constexpr_decl))
     {
       tree tmp = NULL_TREE;
       /* First, try to avoid FPs if INTOP is negative constant.  */
index bb2d371..b66b7e1 100644 (file)
@@ -266,6 +266,8 @@ static void cp_finalize_oacc_routine
 
 /* Variables.  */
 
+extern bool processing_constexpr_decl;
+
 /* The stream to which debugging output should be written.  */
 static FILE *cp_lexer_debug_stream;
 
@@ -18399,6 +18401,7 @@ cp_parser_init_declarator (cp_parser* parser,
   bool range_for_decl_p = false;
   bool saved_default_arg_ok_p = parser->default_arg_ok_p;
   location_t tmp_init_loc = UNKNOWN_LOCATION;
+  processing_constexpr_decl = false;
 
   /* Gather the attributes that were provided with the
      decl-specifiers.  */
@@ -18688,6 +18691,13 @@ cp_parser_init_declarator (cp_parser* parser,
             arguments.  So right here we only handle the latter.  */
          if (!member_p && processing_template_decl)
            start_lambda_scope (decl);
+
+         /* Save info about constexpr declaration, in case we have
+            constexpr unsigned *p = ptr + index, current_function_decl
+            does not work for us.  */
+         if (decl && DECL_DECLARED_CONSTEXPR_P (decl))
+           processing_constexpr_decl = true;
+
          initializer = cp_parser_initializer (parser,
                                               &is_direct_init,
                                               &is_non_constant_init);
index b5a9dd0..fdaba65 100644 (file)
@@ -5164,8 +5164,9 @@ cp_build_binary_op (location_t location,
     }
 
   if ((flag_sanitize & SANITIZE_UI_OVERFLOW)
-       && (doing_plus || doing_minus || doing_mul)
-       && !processing_template_decl)
+      && (doing_plus || doing_minus || doing_mul) && !processing_template_decl
+      && !(current_function_decl
+          && DECL_DECLARED_CONSTEXPR_P (current_function_decl)))
     {
       op0 = cp_save_expr (op0);
       op1 = cp_save_expr (op1);
index 4896396..76c5e62 100644 (file)
@@ -6,3 +6,24 @@
 constexpr int foo (int i) {
   return std::__lg (i);
 }
+
+constexpr const char *string = "string";
+
+constexpr unsigned int str2int(const char *str, int h = 0) {
+  return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
+}
+
+constexpr unsigned int arr[] = {1, 2, 3, 4, 5};
+
+constexpr unsigned int index = 1;
+
+class A
+{
+  static constexpr const unsigned int *ptr = arr + index;
+};
+
+int main ()
+{
+  constexpr unsigned int result_value = str2int (string);
+  A a;
+}
index 8979d26..3e0b54a 100644 (file)
@@ -101,6 +101,13 @@ static void compile_file (void);
 /* True if we don't need a backend (e.g. preprocessing only).  */
 static bool no_backend;
 
+/* True if processing constexpr declaration.
+   Could not be use to verify function declaration.
+   Only usable for constexpr pointer.
+   Example:
+   constexpr unsigned *pointer = ptr + index.  */
+bool processing_constexpr_decl = false;
+
 /* Length of line when printing switch values.  */
 #define MAX_LINE 75