Fine-grained control of -fcheck-memory-usage with new no_check_memory_usage attribute.
authorKen Raeburn <raeburn@cygnus.com>
Sun, 11 Oct 1998 02:21:54 +0000 (02:21 +0000)
committerKen Raeburn <raeburn@gcc.gnu.org>
Sun, 11 Oct 1998 02:21:54 +0000 (02:21 +0000)
Fine-grained control of -fcheck-memory-usage with new no_check_memory_usage
attribute.  Misc minor bugfixes and tests for it too.

From-SVN: r22983

33 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/calls.c
gcc/config/alpha/alpha.c
gcc/config/clipper/clipper.c
gcc/config/m88k/m88k.c
gcc/config/pa/pa.c
gcc/config/sparc/sparc.c
gcc/expr.c
gcc/expr.h
gcc/extend.texi
gcc/function.c
gcc/function.h
gcc/invoke.texi
gcc/optabs.c
gcc/stmt.c
gcc/testsuite/gcc.c-torture/ChangeLog
gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/memcheck/template [new file with mode: 0644]
gcc/tree.h

index 5197ef3f3eed35bc735ef376cc02c6bf9157072a..b1c44a00b861ea9ee1c5d3b8a7d5d5e7359049d5 100644 (file)
@@ -1,3 +1,32 @@
+Sun Oct 11 05:03:41 1998  Ken Raeburn  <raeburn@cygnus.com>
+
+       * tree.h (DECL_NO_CHECK_MEMORY_USAGE): New macros.
+       (struct tree_decl): New fields no_check_memory_usage.
+       * c-common.c (enum attrs): Add A_NO_CHECK_MEMORY_USAGE.
+       (init_attributes): Register it as a new attribute.
+       (decl_attributes): Set flags on functions given that attribute.
+       * c-decl.c (duplicate_decls): Merge new attribute.
+       * expr.h (current_function_check_memory_usage): Declare new var.
+       * calls.c, expr.c, function.c, stmt.c, alpha.c, clipper.c, m88k.c,
+       pa.c, sparc.c: Replace uses of flag_check_memory_usage with
+       current_function_check_memory_usage.
+       * function.h: Add field to struct function.
+       * function.c (current_function_check_memory_usage): Define it.
+       (push_function_context_to, pop_function_context_from): Save and
+       restore it.
+       (expand_function_start): Set it, based on global flag and function
+       attribute.
+
+       * expr.c (expand_expr, case VAR_DECL): In memory-checking code, do
+       check non-automatic variables, to permit detection of writes to
+       read-only locations in embedded systems without memory management.
+       * calls.c (store_one_arg): Use ARGS_SIZE_RTX to get size of argument
+       when emitting chkr_set_right_libfunc call, even if the argument is
+       BLKmode or variable-sized; don't abort.
+
+       * optabs.c (init_optabs): Create Checker and __cyg_profile_*
+       symbols in Pmode, not VOIDmode.
+
 Sun Oct 11 01:03:05 1998  Zack Weinberg  <zack@rabi.phys.columbia.edu>
 
        * cppexp.c: When forcing unsigned comparisons, cast both sides
index 820473f836c30b1abd6a78a6609d7f33df838083..3157e1d0f7d4c92b69839078e329aebeca31cc92 100644 (file)
@@ -51,7 +51,7 @@ extern struct obstack permanent_obstack;
 int skip_evaluation;
 
 enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
-           A_NO_INSTRUMENT_FUNCTION,
+           A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
            A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
            A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS,
            A_INIT_PRIORITY};
@@ -394,6 +394,7 @@ init_attributes ()
   add_attribute (A_ALIAS, "alias", 1, 1, 1);
   add_attribute (A_INIT_PRIORITY, "init_priority", 0, 1, 0);
   add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
+  add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
 }
 \f
 /* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
@@ -889,6 +890,23 @@ decl_attributes (node, attributes, prefix_attributes)
            warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
          break;
 
+       case A_NO_CHECK_MEMORY_USAGE:
+         if (TREE_CODE (decl) != FUNCTION_DECL)
+           {
+             error_with_decl (decl,
+                              "`%s' attribute applies only to functions",
+                              IDENTIFIER_POINTER (name));
+           }
+         else if (DECL_INITIAL (decl))
+           {
+             error_with_decl (decl,
+                              "can't set `%s' attribute after definition",
+                              IDENTIFIER_POINTER (name));
+           }
+         else
+           DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
+         break;
+
        case A_INIT_PRIORITY:
          {
            tree initp_expr = (args ? TREE_VALUE (args): NULL_TREE);
index 99b4ad5ab523cea2fa502b6557035a43b5d8983e..399acb081481961e5551ae0d9a5fece575c2d9d5 100644 (file)
@@ -1938,6 +1938,8 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
 
          DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
            |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+         DECL_NO_CHECK_MEMORY_USAGE (newdecl)
+           |= DECL_NO_CHECK_MEMORY_USAGE (olddecl);
        }
 
       pop_obstacks ();
index 2bddc2a32a1d74f18774ca92a39a480c7773bb0d..c44617e6bb4d2c5f6e3c9235ef0a6c3798d24e9c 100644 (file)
@@ -595,7 +595,7 @@ expand_call (exp, target, ignore)
      if -fcheck-memory-usage, code which invokes functions (and thus
      damages some hard registers) can be inserted before using the value.
      So, target is always a pseudo-register in that case.  */
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     target = 0;
 
   /* See if we can find a DECL-node for the actual function.
@@ -1625,7 +1625,7 @@ expand_call (exp, target, ignore)
       pop_temp_slots ();       /* FUNEXP can't be BLKmode */
 
       /* Check the function is executable.  */
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_check_exec_libfunc, 1,
                           VOIDmode, 1,
                           funexp, ptr_mode);
@@ -1864,7 +1864,7 @@ expand_call (exp, target, ignore)
                                                NULL_RTX)));
 
       /* Mark the memory for the aggregate as write-only.  */
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_set_right_libfunc, 1,
                           VOIDmode, 3,
                           structure_value_addr, ptr_mode, 
@@ -3508,15 +3508,13 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
 
   if (arg->value == arg->stack)
     {
-      /* If the value is already in the stack slot, we are done.  */
-      if (flag_check_memory_usage && GET_CODE (arg->stack) == MEM)
+      /* If the value is already in the stack slot, we are done moving
+        data.  */
+      if (current_function_check_memory_usage && GET_CODE (arg->stack) == MEM)
        {
-         if (arg->mode == BLKmode)
-           abort ();
-
          emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                             XEXP (arg->stack, 0), ptr_mode, 
-                            GEN_INT (GET_MODE_SIZE (arg->mode)),
+                            ARGS_SIZE_RTX (arg->size),
                             TYPE_MODE (sizetype),
                             GEN_INT (MEMORY_USE_RW),
                             TYPE_MODE (integer_type_node));
index 5f738b599b2caf37d027680a6e2baa25c4013172..dca15802a8f6c4303acc5458729e1913622a6e2d 100644 (file)
@@ -2975,7 +2975,7 @@ alpha_builtin_saveregs (arglist)
       dest = change_address (block, ptr_mode, XEXP (block, 0));
       emit_move_insn (dest, addr);
 
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                           dest, ptr_mode,
                           GEN_INT (GET_MODE_SIZE (ptr_mode)),
@@ -2989,7 +2989,7 @@ alpha_builtin_saveregs (arglist)
                                            POINTER_SIZE/BITS_PER_UNIT));
       emit_move_insn (dest, argsize);
 
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                           dest, ptr_mode,
                           GEN_INT (GET_MODE_SIZE
index 4bee0e6aaa726a5d8c1d8f9945f0d4cbf30be3d3..d59d3f1671e13fb9f21badcb006debc5f86c5a4b 100644 (file)
@@ -438,7 +438,7 @@ clipper_builtin_saveregs (arglist)
                  scratch);
 
 
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     {
       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                         addr, ptr_mode,
index b1250e5e61b74a4cfce44385c62662055af41c3a..877ecf9b8fab9b8f575743d27fcf48ddb0b1286f 100644 (file)
@@ -2644,7 +2644,7 @@ m88k_builtin_saveregs (arglist)
                           UNITS_PER_WORD * (8 - fixed));
     }
 
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     {
       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                         block, ptr_mode,
index 41642041e32f8a7b86d3f3f45b9af252821757b6..91ada8e3aec7d9be79a3364fda3983e1428b2efe 100644 (file)
@@ -4391,7 +4391,7 @@ hppa_builtin_saveregs (arglist)
      last argument register store.  So we emit a blockage insn here.  */
   emit_insn (gen_blockage ());
 
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                       dest, ptr_mode,
                       GEN_INT (4 * UNITS_PER_WORD), TYPE_MODE (sizetype),
index ae207027b0fa0539b5971865978082e6d030f599..686350b8694b18ea4bf17dd8969b8d253d850cf7 100644 (file)
@@ -4279,7 +4279,7 @@ sparc_builtin_saveregs (arglist)
                     GEN_INT (STACK_POINTER_OFFSET
                              + UNITS_PER_WORD * first_reg));
 
-  if (flag_check_memory_usage
+  if (current_function_check_memory_usage
       && first_reg < NPARM_REGS (word_mode))
     emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                       address, ptr_mode,
index d2dcdf8c592fee06e58aad44d8631cf0fef2917e..53dce8fdb0e8c4a381dec4c0f8542985ca8549c7 100644 (file)
@@ -110,8 +110,8 @@ static rtx apply_args_value;
 static int can_handle_constant_p;
 
 /* Don't check memory usage, since code is being emitted to check a memory
-   usage.  Used when flag_check_memory_usage is true, to avoid infinite
-   recursion.  */
+   usage.  Used when current_function_check_memory_usage is true, to avoid
+   infinite recursion.  */
 static int in_check_memory_usage;
 
 /* This structure is used by move_by_pieces to describe the move to
@@ -2865,7 +2865,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
          move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
                          INTVAL (size) - used, align);
 
-         if (flag_check_memory_usage && ! in_check_memory_usage)
+         if (current_function_check_memory_usage && ! in_check_memory_usage)
            {
              rtx temp;
              
@@ -2922,7 +2922,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                                                                args_addr,
                                                                args_so_far),
                                                  skip));
-         if (flag_check_memory_usage && ! in_check_memory_usage)
+         if (current_function_check_memory_usage && ! in_check_memory_usage)
            {
              rtx target;
              
@@ -3122,7 +3122,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
 
       emit_move_insn (gen_rtx_MEM (mode, addr), x);
 
-      if (flag_check_memory_usage && ! in_check_memory_usage)
+      if (current_function_check_memory_usage && ! in_check_memory_usage)
        {
          in_check_memory_usage = 1;
          if (target == 0)
@@ -3290,7 +3290,7 @@ expand_assignment (to, from, want_value, suggest_reg)
        }
 
       /* Check the access.  */
-      if (flag_check_memory_usage && GET_CODE (to_rtx) == MEM)
+      if (current_function_check_memory_usage && GET_CODE (to_rtx) == MEM)
        {
          rtx to_addr;
          int size;
@@ -3416,7 +3416,7 @@ expand_assignment (to, from, want_value, suggest_reg)
                              EXPAND_MEMORY_USE_DONT);
 
       /* Copy the rights of the bitmap.  */
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
                           XEXP (to_rtx, 0), ptr_mode,
                           XEXP (from_rtx, 0), ptr_mode,
@@ -3638,7 +3638,7 @@ store_expr (exp, target, want_value)
     temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
                          temp, TREE_UNSIGNED (TREE_TYPE (exp)));
 
-  if (flag_check_memory_usage
+  if (current_function_check_memory_usage
       && GET_CODE (target) == MEM
       && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
     {
@@ -3742,7 +3742,7 @@ store_expr (exp, target, want_value)
              if (size != const0_rtx)
                {
                  /* Be sure we can write on ADDR.  */
-                 if (flag_check_memory_usage)
+                 if (current_function_check_memory_usage)
                    emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
                                       addr, ptr_mode,
                                       size, TYPE_MODE (sizetype),
@@ -5584,13 +5584,16 @@ expand_expr (exp, target, tmode, modifier)
          pop_obstacks ();
        }
 
-      /* Only check automatic variables.  Currently, function arguments are
-         not checked (this can be done at compile-time with prototypes).
-         Aggregates are not checked.  */
-      if (flag_check_memory_usage && code == VAR_DECL
+      /* Although static-storage variables start off initialized, according to
+        ANSI C, a memcpy could overwrite them with uninitialized values.  So
+        we check them too.  This also lets us check for read-only variables
+        accessed via a non-const declaration, in case it won't be detected
+        any other way (e.g., in an embedded system or OS kernel without
+        memory protection).
+
+        Aggregates are not checked here; they're handled elsewhere.  */
+      if (current_function_check_memory_usage && code == VAR_DECL
          && GET_CODE (DECL_RTL (exp)) == MEM
-         && DECL_CONTEXT (exp) != NULL_TREE
-         && ! TREE_STATIC (exp)
          && ! AGGREGATE_TYPE_P (TREE_TYPE (exp)))
        {
          enum memory_use_mode memory_usage;
@@ -6107,7 +6110,7 @@ expand_expr (exp, target, tmode, modifier)
        op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
        op0 = memory_address (mode, op0);
 
-       if (flag_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+       if (current_function_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp)))
          {
            enum memory_use_mode memory_usage;
            memory_usage = get_memory_usage_from_modifier (modifier);
@@ -6411,7 +6414,7 @@ expand_expr (exp, target, tmode, modifier)
          }
 
        /* Check the access.  */
-       if (flag_check_memory_usage && GET_CODE (op0) == MEM)
+       if (current_function_check_memory_usage && GET_CODE (op0) == MEM)
           {
            enum memory_use_mode memory_usage;
            memory_usage = get_memory_usage_from_modifier (modifier);
@@ -9163,7 +9166,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
            src_rtx = copy_to_mode_reg (Pmode, src_rtx);
 
          /* Check the string is readable and has an end.  */
-         if (flag_check_memory_usage)
+         if (current_function_check_memory_usage)
            emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2,
                               src_rtx, ptr_mode,
                               GEN_INT (MEMORY_USE_RO),
@@ -9256,7 +9259,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
 
          /* Just copy the rights of SRC to the rights of DEST.  */
-         if (flag_check_memory_usage)
+         if (current_function_check_memory_usage)
            emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
                               XEXP (dest_mem, 0), ptr_mode,
                               XEXP (src_mem, 0), ptr_mode,
@@ -9327,7 +9330,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          dest_mem = get_memory_rtx (dest);
           
          /* Just check DST is writable and mark it as readable.  */
-         if (flag_check_memory_usage)
+         if (current_function_check_memory_usage)
            emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
                               XEXP (dest_mem, 0), ptr_mode,
                               len_rtx, TYPE_MODE (sizetype),
@@ -9353,7 +9356,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        break;
 
       /* If we need to check memory accesses, call the library function.  */
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        break;
 
       if (arglist == 0
@@ -9409,7 +9412,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        break;
 
       /* If we need to check memory accesses, call the library function.  */
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        break;
 
       if (arglist == 0
@@ -10238,7 +10241,7 @@ expand_increment (exp, post, ignore)
 
   /* Increment however we can.  */
   op1 = expand_binop (mode, this_optab, value, op1,
-                     flag_check_memory_usage ? NULL_RTX : op0,
+                     current_function_check_memory_usage ? NULL_RTX : op0,
                      TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
   /* Make sure the value is stored into OP0.  */
   if (op1 != op0)
index 353e6fdfe46071ec983e4e230e9e0d0e3c11433e..b1665aa7de914ad225020c16cc05041ecd7a78ef 100644 (file)
@@ -91,6 +91,10 @@ extern int current_function_uses_pic_offset_table;
 /* The arg pointer hard register, or the pseudo into which it was copied.  */
 extern rtx current_function_internal_arg_pointer;
 
+/* This is nonzero if memory access checking be enabled in the current
+   function.  */
+extern int current_function_check_memory_usage;
+
 /* Nonzero means stack pops must not be deferred, and deferred stack
    pops must not be output.  It is nonzero inside a function call,
    inside a conditional expression, inside a statement expression,
index 45b31b823221dd37606c2d12f945408645d8f331..a2c278b001c990f9868a4dad64d1c32bc60d591c 100644 (file)
@@ -1518,6 +1518,19 @@ mangled name for the target must be used.
 
 Not all target machines support this attribute.
 
+@item no_check_memory_usage
+@cindex @code{no_check_memory_usage} function attribute
+If @samp{-fcheck-memory-usage} is given, calls to support routines will
+be generated before most memory accesses, to permit support code to
+record usage and detect uses of uninitialized or unallocated storage.
+Since the compiler cannot handle them properly, @code{asm} statements
+are not allowed.  Declaring a function with this attribute disables the
+memory checking code for that function, permitting the use of @code{asm}
+statements without requiring separate compilation with different
+options, and allowing you to write support routines of your own if you
+wish, without getting infinite recursion if they get compiled with this
+option.
+
 @item regparm (@var{number})
 @cindex functions that are passed arguments in registers on the 386
 On the Intel 386, the @code{regparm} attribute causes the compiler to
index 5ad113cfc9372cf28961bce14e30cb0fd77a5d8b..4645f5af7cc658f9cbad0bf3736a7979512d439c 100644 (file)
@@ -221,6 +221,9 @@ char *current_function_cannot_inline;
    generated.  */
 int current_function_instrument_entry_exit;
 
+/* Nonzero if memory access checking be enabled in the current function.  */
+int current_function_check_memory_usage;
+
 /* The FUNCTION_DECL for an inline function currently being expanded.  */
 tree inline_function_decl;
 
@@ -543,6 +546,7 @@ push_function_context_to (context)
   p->fixup_var_refs_queue = 0;
   p->epilogue_delay_list = current_function_epilogue_delay_list;
   p->args_info = current_function_args_info;
+  p->check_memory_usage = current_function_check_memory_usage;
   p->instrument_entry_exit = current_function_instrument_entry_exit;
 
   save_tree_status (p, context);
@@ -626,6 +630,7 @@ pop_function_context_from (context)
   current_function_epilogue_delay_list = p->epilogue_delay_list;
   reg_renumber = 0;
   current_function_args_info = p->args_info;
+  current_function_check_memory_usage = p->check_memory_usage;
   current_function_instrument_entry_exit = p->instrument_entry_exit;
 
   restore_tree_status (p, context);
@@ -1484,7 +1489,7 @@ put_var_into_stack (decl)
   else
     return;
   
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                       XEXP (reg, 0), ptr_mode,
                       GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
@@ -4364,7 +4369,7 @@ assign_parms (fndecl, second_time)
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
-             if (flag_check_memory_usage)
+             if (current_function_check_memory_usage)
                emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                                   XEXP (copy, 0), ptr_mode,
                                   GEN_INT (int_size_in_bytes (type)),
@@ -4529,7 +4534,7 @@ assign_parms (fndecl, second_time)
                emit_move_insn (validize_mem (stack_parm),
                                validize_mem (entry_parm));
            }
-         if (flag_check_memory_usage)
+         if (current_function_check_memory_usage)
            {
              push_to_sequence (conversion_insns);
              emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
@@ -5550,6 +5555,11 @@ expand_function_start (subr, parms_have_cleanups)
      valid operands of arithmetic insns.  */
   init_recog_no_volatile ();
 
+  /* Set this before generating any memory accesses.  */
+  current_function_check_memory_usage
+    = (flag_check_memory_usage
+       && ! DECL_NO_CHECK_MEMORY_USAGE (current_function_decl));
+
   current_function_instrument_entry_exit
     = (flag_instrument_function_entry_exit
        && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
index 06e90dc88aa34b759d7a097090b52922059e1c6f..014ed135b74401eeadb48f74e9d775f5cd3e340d 100644 (file)
@@ -151,6 +151,7 @@ struct function
   rtx saveregs_value;
   rtx apply_args_value;
   rtx forced_labels;
+  int check_memory_usage;
 
   /* For emit-rtl.c.  */
   int reg_rtx_no;
index d0339e47699c31a9e74d058466cf969d746fc1c2..cf461987208a8d98f63dc2d7a7082c801926a24d 100644 (file)
@@ -5843,8 +5843,7 @@ the offsets of structure members won't agree with system libraries.
 @item -fcheck-memory-usage
 Generate extra code to check each memory access.  GNU CC will generate
 code that is suitable for a detector of bad memory accesses such as
-@file{Checker}.  If you specify this option, you can not use the
-@code{asm} or @code{__asm__} keywords.
+@file{Checker}.
 
 You must also specify this option when you compile functions you call that
 have side effects.  If you do not, you may get erroneous messages from
@@ -5859,6 +5858,24 @@ which are provided by the detector.  If you cannot find or build
 stubs for every function you call, you may have to specify
 @samp{-fcheck-memory-usage} without @samp{-fprefix-function-name}.
 
+If you specify this option, you can not use the @code{asm} or
+@code{__asm__} keywords in functions with memory checking enabled.  The
+compiler cannot understand what the @code{asm} statement will do, and
+therefore cannot generate the appropriate code, so it is rejected.
+However, the function attribute @code{no_check_memory_usage} will
+disable memory checking within a function, and @code{asm} statements can
+be put inside such functions.  Inline expansion of a non-checked
+function within a checked function is permitted; the inline function's
+memory accesses won't be checked, but the rest will.
+
+If you move your @code{asm} statements to non-checked inline functions,
+but they do access memory, you can add calls to the support code in your
+inline function, to indicate any reads, writes, or copies being done.
+These calls would be similar to those done in the stubs described above.
+
+@c FIXME: The support-routine interface is defined by the compiler and
+@c        should be documented!
+
 @item -fprefix-function-name
 Request GNU CC to add a prefix to the symbols generated for function names.
 GNU CC adds a prefix to the names of functions defined as well as
index 2157f3f87847a50bb45986f4524c59aa9f5a343e..2a321690dc4e8f9254d24de2ec26e44375795b6e 100644 (file)
@@ -4390,17 +4390,17 @@ init_optabs ()
   fixunstfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfti");
 
   /* For check-memory-usage.  */
-  chkr_check_addr_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_addr");
-  chkr_set_right_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_set_right");
-  chkr_copy_bitmap_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_copy_bitmap");
-  chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_exec");
-  chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_str");
+  chkr_check_addr_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_addr");
+  chkr_set_right_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_set_right");
+  chkr_copy_bitmap_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_copy_bitmap");
+  chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_exec");
+  chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_str");
 
   /* For function entry/exit instrumentation.  */
   profile_function_entry_libfunc
-    = gen_rtx_SYMBOL_REF (VOIDmode, "__cyg_profile_func_enter");
+    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_enter");
   profile_function_exit_libfunc
-    = gen_rtx_SYMBOL_REF (VOIDmode, "__cyg_profile_func_exit");
+    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_exit");
 
 #ifdef HAVE_conditional_trap
   init_traps ();
index 658c872fad46de66af8e2b545d541315bd053625..b28df90c48f38b80738a7b39ad3d6473b5baee97 100644 (file)
@@ -584,7 +584,7 @@ expand_computed_goto (exp)
 
   emit_queue ();
   /* Be sure the function is executable.  */
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     emit_library_call (chkr_check_exec_libfunc, 1,
                       VOIDmode, 1, x, ptr_mode);
 
@@ -1118,7 +1118,7 @@ void
 expand_asm (body)
      tree body;
 {
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     {
       error ("`asm' cannot be used with `-fcheck-memory-usage'");
       return;
@@ -1174,7 +1174,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   if (noutputs == 0)
     vol = 1;
 
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     {
       error ("`asm' cannot be used with `-fcheck-memory-usage'");
       return;
@@ -3291,7 +3291,7 @@ expand_decl (decl)
           && ! TREE_ADDRESSABLE (decl)
           && (DECL_REGISTER (decl) || ! obey_regdecls)
           /* if -fcheck-memory-usage, check all variables.  */
-          && ! flag_check_memory_usage)
+          && ! current_function_check_memory_usage)
     {
       /* Automatic variable that can go in a register.  */
       int unsignedp = TREE_UNSIGNED (type);
index 9b2d6badaa5e07e01463f684fd53ce7ce211ca75..14cd57461468af0889f330917690b17ca1455eb2 100644 (file)
@@ -1,3 +1,8 @@
+Sun Oct 11 05:04:28 1998  Ken Raeburn  <raeburn@cygnus.com>
+
+       * execute/memcheck: New directory of tests for
+       -fcheck-memory-usage.
+
 1998-10-06  Ken Raeburn  <raeburn@cygnus.com>
 
        * special/981006-1.c: New test.  Make sure gcc doesn't lose track
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c
new file mode 100644 (file)
index 0000000..43c5b39
--- /dev/null
@@ -0,0 +1,64 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+/* Test permissions of BLKmode arguments constructed purely on the
+   stack.
+
+   Maybe we can't guarantee that we'll always wind up with stack args,
+   but if we don't, they're in registers, and permissions should just
+   always yield success.  So while this test may not be effective on
+   all platforms, failure probably does indicate a real bug.
+
+   Note that because of the implementation, we do want to test BLKmode
+   arguments that live purely on the stack and are constructed there.
+   We want to test other situations of function arguments, of course,
+   but don't assume this case would be covered by using one monster
+   argument that is read from memory (including using constructor
+   syntax but constant values), or may live partially in registers.  */
+
+int expect_error = 0;
+
+/* Must be BLKmode.  Using only two fields gets TImode on Alpha.  */
+struct S {
+  unsigned long long ll;
+  long xx, yy;
+};
+
+unsigned long long x = 0x12345689ULL;
+#define I2     42
+
+/* Leading six arguments force X into stack on both Alpha and MIPS.  */
+
+static int first_time = 1;
+int foo (int a1, int a2, int a3, int a4, int a5, int a6, struct S s) {
+  if (a1 != 1 || a2 != 2 || a3 != 3 || a4 != 4 || a5 != 5 || a6 != 6)
+    abort ();
+  if (first_time)
+    {
+      if (s.ll != x || s.xx != I2 || s.yy != 0)
+       abort ();
+      first_time = 0;
+    }
+  else
+    {
+      if (s.ll != 0 || s.xx != 0 || s.yy != 0)
+       abort ();
+    }
+  return 0;
+}
+
+void test ()
+{
+  foo (1, 2, 3, 4, 5, 6, (struct S) { x, I2 });
+  foo (1, 2, 3, 4, 5, 6, (struct S) { 0 });
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&x, sizeof (x), ACCESS_RO);
+  mark_region (&first_time, sizeof (first_time), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c
new file mode 100644 (file)
index 0000000..9002a0b
--- /dev/null
@@ -0,0 +1,254 @@
+/* GNU C dependencies:
+   Checker support hooks
+   ISO C 9x array element initialization
+   void-pointer arithmetic */
+
+#include "driver.h"
+
+int verbose = 0;
+int debug = 0;
+int bad_accesses = 0;
+
+const char *const memory_use_strings[] = {
+#define INIT(x)                [x] = #x
+  INIT (MEMORY_USE_BAD),
+  INIT (MEMORY_USE_DONT),
+  INIT (MEMORY_USE_RO),
+  INIT (MEMORY_USE_RW),
+  INIT (MEMORY_USE_TW),
+  INIT (MEMORY_USE_WO),
+#undef INIT
+};
+
+/* This won't be used for any really huge test cases, so a simple
+   linked list is adequate.  We won't even worry about overlapping
+   regions; the matching entry that comes up first wins.  */
+const char *const access_mode_strings[] = {
+  "none", "ro", "wo", "rw",
+};
+struct access_node {
+  struct access_node *next;
+  const void *addr;
+  size_t sz;
+  enum access_mode mode;
+};
+
+static struct access_node *access_list;
+
+void mark_region (const void *addr, size_t sz, enum access_mode mode)
+{
+  struct access_node *a;
+  if (debug)
+    printf ("mark_region (%p, %ld, %s)\n", addr, (long) sz,
+           access_mode_strings[mode]);
+  a = malloc (sizeof (struct access_node));
+  a->next = access_list;
+  a->addr = addr;
+  a->sz = sz;
+  a->mode = mode;
+  access_list = a;
+}
+
+void report_bad_access (void *, size_t, enum memory_use_mode) NOCHECK;
+void report_bad_access (void *addr, size_t sz, enum memory_use_mode mode)
+{
+  if (++bad_accesses > 100)
+    bad_accesses = 100;
+  if (verbose)
+    {
+      static char x[100];
+      const char *mode_str;
+      if (mode >= 0
+         && mode < sizeof (memory_use_strings) / sizeof (*memory_use_strings)
+         && memory_use_strings[mode] != 0)
+       mode_str = memory_use_strings[mode];
+      else
+       {
+         sprintf (x, "<bad mode %d>", mode);
+         mode_str = x;
+       }
+      printf ("bad access (%p, %ld, %s)\n", addr, (long) sz, mode_str);
+    }
+}
+
+int verify1 (void *, size_t, enum access_mode, struct access_node *) NOCHECK;
+int verify1 (void *addr, size_t sz, enum access_mode mode,
+            struct access_node *a)
+{
+  while (a && (addr + sz <= a->addr || addr >= a->addr + a->sz))
+    a = a->next;
+  if (a == 0)
+    return 0;
+
+  if (debug)
+    printf ("verify1 (%p, %ld, %s)\n", addr, (long) sz,
+           access_mode_strings[mode]);
+
+  if (mode & ~a->mode)
+    return 0;
+
+  if (addr < a->addr)
+    if (verify1 (a, a->addr - addr, mode, a->next) == 0)
+      return 0;
+  if (addr + sz > a->addr + a->sz)
+    if (verify1 (a->addr + a->sz, (addr + sz) - (a->addr + a->sz), mode, a->next) == 0)
+      return 0;
+
+  /* All regions okay.  */
+  return 1;
+}
+
+int verify_range_permission (void *, size_t, enum access_mode) NOCHECK;
+
+int verify_range_permission (void *addr, size_t sz, enum access_mode mode)
+{
+  if (debug)
+    printf ("verify_range_permission (%p, %ld, %s)\n", addr, (long) sz,
+           access_mode_strings[mode]);
+  return verify1 (addr, sz, mode, access_list);
+}
+
+void chkr_check_addr (void *, size_t, int) NOCHECK;
+
+void chkr_check_addr (void *addr, size_t sz, int mode)
+{
+  switch (mode)
+    {
+    case MEMORY_USE_BAD:
+    case MEMORY_USE_DONT:
+    default:
+      report_bad_access (addr, sz, mode);
+      return;
+    case MEMORY_USE_RO:
+      /* verify range readable */
+      if (!verify_range_permission (addr, sz, ACCESS_RO))
+       report_bad_access (addr, sz, mode);
+      return;
+    case MEMORY_USE_WO:
+      /* verify writeable, set writeable and readable */
+      if (!verify_range_permission (addr, sz, ACCESS_WO))
+       report_bad_access (addr, sz, mode);
+      mark_region (addr, sz, ACCESS_RW);
+      return;
+    case MEMORY_USE_RW:
+      /* verify readable and writeable, no change */
+      if (!verify_range_permission (addr, sz, ACCESS_RW))
+       report_bad_access (addr, sz, mode);
+      return;
+    case MEMORY_USE_TW:
+      /* verify writeable, no change */
+      if (!verify_range_permission (addr, sz, ACCESS_WO))
+       report_bad_access (addr, sz, mode);
+      return;
+    }
+  /* All branches should return.  */
+  abort ();
+}
+
+void copy1 (void *, void *, size_t, struct access_node *) NOCHECK;
+void copy1 (void *dest, void *src, size_t sz, struct access_node *a)
+{
+  while (a && (src + sz <= a->addr || src >= a->addr + a->sz))
+    a = a->next;
+  if (a == 0)
+    {
+      report_bad_access (src, sz, MEMORY_USE_RO);
+      return;
+    }
+
+  if (debug)
+    printf ("copy1 (%p, %p, %ld)\n", dest, src, (long) sz);
+
+  {
+    void *start, *end;
+    start = src;
+    if (start < a->addr)
+      start = a->addr;
+    end = src + sz;
+    if (end > a->addr + a->sz)
+      end = a->addr + a->sz;
+    mark_region (dest + (start - src), end - start, a->mode);
+  }
+
+  if (src < a->addr)
+    copy1 (dest, src, a->addr - src, a->next);
+  if (src + sz > a->addr + a->sz)
+    copy1 (dest + (a->addr + a->sz - src), a->addr + a->sz,
+          (src + sz) - (a->addr + a->sz), a->next);
+}
+
+void chkr_copy_bitmap (void *, void *, size_t) NOCHECK;
+void chkr_copy_bitmap (void *dest, void *src, size_t sz)
+{
+  if (verify_range_permission (dest, sz, MEMORY_USE_WO) == 0)
+    report_bad_access (dest, sz, MEMORY_USE_WO);
+  copy1 (dest, src, sz, access_list);
+}
+
+void chkr_set_right (void *, size_t, enum access_mode) NOCHECK;
+void chkr_set_right (void *addr, size_t sz, enum access_mode mode)
+{
+  mark_region (addr, sz, mode);
+}
+
+int main () NOCHECK;
+int main ()
+{
+  setup ();
+  test ();
+  bad_accesses = !!bad_accesses; /* get 0 or 1 */
+  /* Return 0 if got expected results, 1 otherwise.  */
+  return !(bad_accesses == expect_error);
+}
+
+struct malloc_node {
+  struct malloc_node *next;
+  void *addr;
+  size_t sz;
+  unsigned is_free : 1;
+};
+static struct malloc_node *malloc_list;
+
+void *c_malloc (size_t sz)
+{
+  void *p;
+  struct malloc_node *m;
+  if (sz == 0)
+    return 0;
+  p = malloc (sz);
+  if (p == 0)
+    {
+      if (verbose)
+       printf ("malloc(%ld) failed\n", (long) sz);
+      exit (1);
+    }
+  m = malloc (sizeof (struct malloc_node));
+  if (m == 0)
+    {
+      if (verbose)
+       printf ("malloc(%ld) failed\n", (long) sizeof (struct malloc_node));
+      exit (1);
+    }
+  mark_region (p, sz, ACCESS_WO);
+  m->addr = p;
+  m->sz = sz;
+  m->is_free = 0;
+  m->next = malloc_list;
+  malloc_list = m;
+  return p;
+}
+
+void c_free (void *p)
+{
+  struct malloc_node *m;
+  if (p == 0)
+    return;
+  for (m = malloc_list; m; m = m->next)
+    if (m->addr == p)
+      break;
+  if (m == 0 || m->is_free)
+    /* Test is broken.  */
+    abort ();
+  m->is_free = 1;
+  free (p);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h b/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h
new file mode 100644 (file)
index 0000000..d8d22d2
--- /dev/null
@@ -0,0 +1,28 @@
+/* GNU C dependencies:
+   Checker support hooks
+   ISO C 9x array element initialization
+   void-pointer arithmetic */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void *malloc (size_t);
+extern int printf (const char *, ...);
+
+/* This comes from gcc internals.  Should be exported.  */
+enum memory_use_mode {MEMORY_USE_BAD = 0, MEMORY_USE_RO = 1,
+                     MEMORY_USE_WO = 2, MEMORY_USE_RW = 3,
+                     MEMORY_USE_TW = 6, MEMORY_USE_DONT = 99};
+
+enum access_mode {
+  ACCESS_NONE = 0, ACCESS_RO = 1, ACCESS_WO = 2, ACCESS_RW = 3
+};
+
+#define NOCHECK __attribute__ ((no_check_memory_usage))
+
+void mark_region (const void *, size_t, enum access_mode) NOCHECK;
+void setup () NOCHECK;
+void test ();
+extern int expect_error;
+
+void *c_malloc (size_t) NOCHECK;
+void c_free (void *) NOCHECK;
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp b/gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp
new file mode 100644 (file)
index 0000000..7fb756b
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (C) 1991, 92-93, 95, 97, 1998 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gcc@prep.ai.mit.edu
+
+# This file was written by Rob Savoye. (rob@cygnus.com)
+# Modified and maintained by Jeffrey Wheat (cassidy@cygnus.com)
+
+#
+# These tests come from Torbjorn Granlund (tege@cygnus.com)
+# C torture test suite.
+#
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# load support procs
+load_lib c-torture.exp
+
+#
+# main test loop
+#
+
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*.c]]
+set idx [lsearch $tests */driver.c]
+if $idx>=0 {
+    set tests [lreplace $tests $idx $idx]
+} else {
+    error "list can't find driver.c in $srcdir/$subdir"
+}
+gcc_target_compile $srcdir/$subdir/driver.c driver.o object {additional_flags=-w additional_flags=-g}
+foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+       continue
+    }
+
+    c-torture-execute $src "-fcheck-memory-usage driver.o"
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c
new file mode 100644 (file)
index 0000000..03b6acc
--- /dev/null
@@ -0,0 +1,27 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup ();   -- NOCHECK */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+int *ip;
+
+void test ()
+{
+  ip = c_malloc (sizeof (int));
+  *ip = 42;
+  t2 ();
+}
+
+int t2 ()
+{
+  return *ip;
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&ip, sizeof (ip), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c
new file mode 100644 (file)
index 0000000..d386eb7
--- /dev/null
@@ -0,0 +1,26 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+int *ip;
+
+void test ()
+{
+  ip = c_malloc (sizeof (int));
+  t2 ();
+}
+
+int t2 ()
+{
+  return *ip;
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&ip, sizeof (ip), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c
new file mode 100644 (file)
index 0000000..5b6333d
--- /dev/null
@@ -0,0 +1,25 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+int *ip;
+
+void test ()
+{
+  ip = c_malloc (sizeof (int));
+  t2 (ip);
+}
+
+int t2 (int *ip)
+{
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&ip, sizeof (ip), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c
new file mode 100644 (file)
index 0000000..25010a0
--- /dev/null
@@ -0,0 +1,34 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+struct s {
+  char c;
+  int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+  sp = c_malloc (sizeof (struct s));
+  sp->c = 0;
+  sp->a = 12;
+  sp->b = 47;
+  foo (sp);
+}
+
+int foo (struct s *sp)
+{
+  return sp->c + sp->a + sp->b;
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c
new file mode 100644 (file)
index 0000000..c3bbf64
--- /dev/null
@@ -0,0 +1,33 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+struct s {
+  char c;
+  int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+  sp = c_malloc (sizeof (struct s));
+  sp->c = 0;
+  sp->b = 47;
+  foo (sp);
+}
+
+int foo (struct s *sp)
+{
+  return sp->c + sp->a + sp->b;
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c
new file mode 100644 (file)
index 0000000..652d33d
--- /dev/null
@@ -0,0 +1,39 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+struct s {
+  char c;
+  int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+  sp = c_malloc (sizeof (struct s) * 2);
+  sp->c = 0;
+  sp->b = 47;
+  cp (sp);
+  foo (sp);
+}
+
+int foo (struct s *sp)
+{
+  return sp[1].c + sp[1].a + sp[1].b;
+}
+
+int cp (struct s *sp)
+{
+  sp[1] = sp[0];
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c
new file mode 100644 (file)
index 0000000..a7c6f51
--- /dev/null
@@ -0,0 +1,40 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+struct s {
+  char c;
+  int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+  sp = c_malloc (sizeof (struct s) * 2);
+  sp->c = 0;
+  sp->a = 13;
+  sp->b = 47;
+  cp (sp);
+  foo (sp);
+}
+
+int foo (struct s *sp)
+{
+  return sp[1].c + sp[1].a + sp[1].b;
+}
+
+int cp (struct s *sp)
+{
+  sp[1] = sp[0];
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c
new file mode 100644 (file)
index 0000000..01c1672
--- /dev/null
@@ -0,0 +1,41 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+typedef struct {
+  short a;
+  char b;
+} S1;
+typedef struct {
+  struct { int x; S1 *s1p; } *p;
+} S2;
+
+S1 *s1;
+S2 *s2;
+
+void test ()
+{
+  s1 = c_malloc (sizeof (S1));
+  s2 = c_malloc (sizeof (S2));
+  s2->p = c_malloc (sizeof (*s2->p));
+  s2->p->s1p = s1;
+  s1->a = 47;
+  s1->b = 3;
+  foo ();
+}
+
+int foo ()
+{
+  return s2->p->s1p->b;
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&s1, sizeof (s1), ACCESS_RW);
+  mark_region (&s2, sizeof (s2), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c
new file mode 100644 (file)
index 0000000..f32ca01
--- /dev/null
@@ -0,0 +1,40 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+typedef struct {
+  short a;
+  char b;
+} S1;
+typedef struct {
+  struct { int x; S1 *s1p; } *p;
+} S2;
+
+S1 *s1;
+S2 *s2;
+
+void test ()
+{
+  s1 = c_malloc (sizeof (S1));
+  s2 = c_malloc (sizeof (S2));
+  s2->p = c_malloc (sizeof (*s2->p));
+  s2->p->s1p = s1;
+  s1->a = 47;
+  foo ();
+}
+
+int foo ()
+{
+  return s2->p->s1p->b;
+}
+
+void setup () /* NOCHECK */
+{
+  mark_region (&s1, sizeof (s1), ACCESS_RW);
+  mark_region (&s2, sizeof (s2), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/template b/gcc/testsuite/gcc.c-torture/execute/memcheck/template
new file mode 100644 (file)
index 0000000..37ebb13
--- /dev/null
@@ -0,0 +1,16 @@
+/* Must define:
+   int expect_error;
+   void test ();
+   void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = ;
+
+void test ()
+{
+}
+
+void setup () /* NOCHECK */
+{
+}
index cd9fdbb163ecf740d3f9d0f75cfcf3af3f27998f..8bd8df3368f4f0794bea9cfddf952a2b643e76f6 100644 (file)
@@ -1226,6 +1226,10 @@ struct tree_type
    be instrumented with calls to support routines.  */
 #define DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(NODE) ((NODE)->decl.no_instrument_function_entry_exit)
 
+/* Used in FUNCTION_DECLs to indicate that in this function,
+   check-memory-usage should be disabled.  */
+#define DECL_NO_CHECK_MEMORY_USAGE(NODE) ((NODE)->decl.no_check_memory_usage)
+
 /* Additional flags for language-specific uses.  */
 #define DECL_LANG_FLAG_0(NODE) (DECL_CHECK (NODE)->decl.lang_flag_0)
 #define DECL_LANG_FLAG_1(NODE) (DECL_CHECK (NODE)->decl.lang_flag_1)
@@ -1282,6 +1286,7 @@ struct tree_decl
 
   unsigned non_addr_const_p : 1;
   unsigned no_instrument_function_entry_exit : 1;
+  unsigned no_check_memory_usage : 1;
 
   /* For a FUNCTION_DECL, if inline, this is the size of frame needed.
      If built-in, this is the code for which built-in function.