Fine-grained control of -fcheck-memory-usage with new no_check_memory_usage attribute.
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
This commit is contained in:
parent
e41887f1fc
commit
7d384cc0b3
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
@ -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 ();
|
||||
|
16
gcc/calls.c
16
gcc/calls.c
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
49
gcc/expr.c
49
gcc/expr.c
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
14
gcc/optabs.c
14
gcc/optabs.c
@ -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 ();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
64
gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c
Normal file
64
gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c
Normal file
@ -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);
|
||||
}
|
254
gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c
Normal file
254
gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c
Normal file
@ -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);
|
||||
}
|
28
gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h
Normal file
28
gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h
Normal file
@ -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;
|
54
gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp
Normal file
54
gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp
Normal file
@ -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"
|
||||
}
|
27
gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c
Normal file
27
gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c
Normal file
@ -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);
|
||||
}
|
26
gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c
Normal file
26
gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c
Normal file
@ -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);
|
||||
}
|
25
gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c
Normal file
25
gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c
Normal file
@ -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);
|
||||
}
|
34
gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c
Normal file
34
gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c
Normal file
@ -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);
|
||||
}
|
33
gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c
Normal file
33
gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c
Normal file
@ -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);
|
||||
}
|
39
gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c
Normal file
39
gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c
Normal file
@ -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);
|
||||
}
|
40
gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c
Normal file
40
gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c
Normal file
@ -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);
|
||||
}
|
41
gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c
Normal file
41
gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c
Normal file
@ -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);
|
||||
}
|
40
gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c
Normal file
40
gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c
Normal file
@ -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);
|
||||
}
|
16
gcc/testsuite/gcc.c-torture/execute/memcheck/template
Normal file
16
gcc/testsuite/gcc.c-torture/execute/memcheck/template
Normal file
@ -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 */
|
||||
{
|
||||
}
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user