summaryrefslogtreecommitdiff
path: root/gnu/egcs/gcc/cp/call.c
diff options
context:
space:
mode:
authorAnil Madhavapeddy <avsm@cvs.openbsd.org>2003-06-26 18:30:06 +0000
committerAnil Madhavapeddy <avsm@cvs.openbsd.org>2003-06-26 18:30:06 +0000
commit097c4e0439278c4083db561991d7649b4e51f88a (patch)
treef81a701df11bdc4d7f306b2feab12a1a5dad9063 /gnu/egcs/gcc/cp/call.c
parent8faf3234ea1153498f35f2241a038813bcd698dc (diff)
Introduce a simple static checker for making sure that the bounds
length passed to common functions such as strlcpy/strlcat match the real length of the buffer. It also checks to make sure that the bound length was not incorrectly derived from a sizeof(pointer) operation. Functions must be marked with the new attribute __bounded__, and warnings are turned on by -Wbounded. Specifying -Wformat also enables bounds checking for scanf(3) bounds to '%s' format variables. -Wall now turns on -Wbounded also. The checking is pretty limited right now to constant parameters, and the buffers must be statically declared, and not inside a record type. This simple checking still found hundreds of bugs around the ports tree though, and there have been no false positive warnings. 10x to niklas@, Richard Sharp and David Scott {rich,dave}@recoil.org for compiler advice. deraadt@ ok, miod@ tested on his collection of hardware You need to recompile gcc now if source upgrading in -current before doing a make world.
Diffstat (limited to 'gnu/egcs/gcc/cp/call.c')
-rw-r--r--gnu/egcs/gcc/cp/call.c142
1 files changed, 95 insertions, 47 deletions
diff --git a/gnu/egcs/gcc/cp/call.c b/gnu/egcs/gcc/cp/call.c
index 1dccabcf102..b0b73ca2cbb 100644
--- a/gnu/egcs/gcc/cp/call.c
+++ b/gnu/egcs/gcc/cp/call.c
@@ -599,29 +599,6 @@ build_method_call (instance, name, parms, basetype_path, flags)
return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
}
- /* This is the logic that magically deletes the second argument to
- operator delete, if it is not needed. */
- if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2)
- {
- tree save_last = TREE_CHAIN (parms);
-
- /* get rid of unneeded argument */
- TREE_CHAIN (parms) = NULL_TREE;
- if (build_method_call (instance, name, parms, basetype_path,
- (LOOKUP_SPECULATIVELY|flags) & ~LOOKUP_COMPLAIN))
- {
- /* If it finds a match, return it. */
- return build_method_call (instance, name, parms, basetype_path, flags);
- }
- /* If it doesn't work, two argument delete must work */
- TREE_CHAIN (parms) = save_last;
- }
- /* We already know whether it's needed or not for vec delete. */
- else if (name == ansi_opname[(int) VEC_DELETE_EXPR]
- && TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
- && ! TYPE_VEC_DELETE_TAKES_SIZE (TREE_TYPE (instance)))
- TREE_CHAIN (parms) = NULL_TREE;
-
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
if (parms)
@@ -1088,8 +1065,8 @@ add_function_candidate (candidates, fn, arglist, flags)
tree parmnode, argnode;
int viable = 1;
- /* The `this' and `in_chrg' arguments to constructors are not considered
- in overload resolution. */
+ /* The `this', `in_chrg', and `vlist' arguments to constructors are
+ not considered in overload resolution. */
if (DECL_CONSTRUCTOR_P (fn))
{
parmlist = TREE_CHAIN (parmlist);
@@ -1099,6 +1076,22 @@ add_function_candidate (candidates, fn, arglist, flags)
parmlist = TREE_CHAIN (parmlist);
arglist = TREE_CHAIN (arglist);
}
+ if ((flags & LOOKUP_HAS_VLIST)
+ && DECL_CONSTRUCTOR_FOR_PVBASE_P (fn))
+ {
+ parmlist = TREE_CHAIN (parmlist);
+ arglist = TREE_CHAIN (arglist);
+ }
+ else if (!(flags & LOOKUP_HAS_VLIST)
+ && !DECL_CONSTRUCTOR_FOR_PVBASE_P (fn))
+ /* Ok */;
+ else
+ {
+ /* The ctor expects a vlist and the arguments don't have
+ one, or vice versa, so fn is not even a candidate, since
+ the corresponding ctor would be the candidate. */
+ return candidates;
+ }
}
len = list_length (arglist);
@@ -2094,6 +2087,11 @@ build_user_type_conversion_1 (totype, expr, flags)
tree t = build_int_2 (0, 0);
TREE_TYPE (t) = build_pointer_type (totype);
args = build_scratch_list (NULL_TREE, expr);
+ if (TYPE_USES_PVBASES (totype) && !flag_vtable_thunks_compat)
+ {
+ args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args);
+ flags |= LOOKUP_HAS_VLIST;
+ }
if (TYPE_USES_VIRTUAL_BASECLASSES (totype))
args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
args = scratch_tree_cons (NULL_TREE, t, args);
@@ -2461,7 +2459,11 @@ build_object_call (obj, args)
return error_mark_node;
}
- if (DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR])
+ /* Since cand->fn will be a type, not a function, for a conversion
+ function, we must be careful not to unconditionally look at
+ DECL_NAME here. */
+ if (TREE_CODE (cand->fn) == FUNCTION_DECL
+ && DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR])
return build_over_call (cand, mem_args, LOOKUP_NORMAL);
obj = convert_like (TREE_VEC_ELT (cand->convs, 0), obj);
@@ -2776,9 +2778,19 @@ build_new_op (code, flags, arg1, arg2, arg3)
conv = TREE_OPERAND (conv, 0);
arg1 = convert_like (conv, arg1);
if (arg2)
- arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2);
+ {
+ conv = TREE_VEC_ELT (cand->convs, 1);
+ if (TREE_CODE (conv) == REF_BIND)
+ conv = TREE_OPERAND (conv, 0);
+ arg2 = convert_like (conv, arg2);
+ }
if (arg3)
- arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3);
+ {
+ conv = TREE_VEC_ELT (cand->convs, 2);
+ if (TREE_CODE (conv) == REF_BIND)
+ conv = TREE_OPERAND (conv, 0);
+ arg3 = convert_like (conv, arg3);
+ }
builtin:
switch (code)
@@ -3047,6 +3059,7 @@ convert_like (convs, expr)
= WRAPPER_PTR (TREE_OPERAND (convs, 1));
tree fn = cand->fn;
tree args;
+ int flags = LOOKUP_NORMAL;
if (DECL_CONSTRUCTOR_P (fn))
{
@@ -3054,13 +3067,19 @@ convert_like (convs, expr)
TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn));
args = build_scratch_list (NULL_TREE, expr);
+ if (TYPE_USES_PVBASES (DECL_CONTEXT (fn))
+ && !flag_vtable_thunks_compat)
+ {
+ args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args);
+ flags != LOOKUP_HAS_VLIST;
+ }
if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
args = scratch_tree_cons (NULL_TREE, t, args);
}
else
args = build_this (expr);
- expr = build_over_call (cand, args, LOOKUP_NORMAL);
+ expr = build_over_call (cand, args, flags);
/* If this is a constructor or a function returning an aggr type,
we need to build up a TARGET_EXPR. */
@@ -3269,6 +3288,13 @@ build_over_call (cand, args, flags)
arg = TREE_CHAIN (arg);
parm = TREE_CHAIN (parm);
}
+ if (flags & LOOKUP_HAS_VLIST)
+ {
+ converted_args = expr_tree_cons
+ (NULL_TREE, TREE_VALUE (arg), converted_args);
+ arg = TREE_CHAIN (arg);
+ parm = TREE_CHAIN (parm);
+ }
}
/* Bypass access control for 'this' parameter. */
else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
@@ -3365,6 +3391,10 @@ build_over_call (cand, args, flags)
check_function_format (DECL_NAME (fn), DECL_ASSEMBLER_NAME (fn),
converted_args);
+ if (warn_bounded && (DECL_NAME (fn) || DECL_ASSEMBLER_NAME (fn)))
+ check_function_bounds (DECL_NAME (fn), DECL_ASSEMBLER_NAME (fn),
+ converted_args);
+
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
@@ -3378,6 +3408,8 @@ build_over_call (cand, args, flags)
arg = TREE_CHAIN (converted_args);
if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
arg = TREE_CHAIN (arg);
+ if (flags & LOOKUP_HAS_VLIST)
+ arg = TREE_CHAIN (arg);
arg = TREE_VALUE (arg);
/* Pull out the real argument, disregarding const-correctness. */
@@ -3426,20 +3458,34 @@ build_over_call (cand, args, flags)
else if (! real_lvalue_p (arg)
|| TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
{
+ tree address;
tree to = stabilize_reference
(build_indirect_ref (TREE_VALUE (args), 0));
- /* Don't copy the padding byte; it might not have been allocated
- if to is a base subobject. */
- if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
- return build_unary_op
- (ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to),
- cp_convert (void_type_node, arg), to),
- 0);
-
- val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
+ /* If we're initializing an empty class, then we actually
+ have to use a MODIFY_EXPR rather than an INIT_EXPR. The
+ reason is that the dummy padding member in the target may
+ not actually be allocated if TO is a base class
+ subobject. Since we've set TYPE_NONCOPIED_PARTS on the
+ padding, a MODIFY_EXPR will preserve its value, which is
+ the right thing to do if it's not really padding at all.
+
+ It's not safe to just throw away the ARG if we're looking
+ at an empty class because the ARG might contain a
+ TARGET_EXPR which wants to be bound to TO. If it is not,
+ expand_expr will assign a dummy slot for the TARGET_EXPR,
+ and we will call a destructor for it, which is wrong,
+ because we will also destroy TO, but will never have
+ constructed it. */
+ val = build (is_empty_class (DECL_CLASS_CONTEXT (fn))
+ ? MODIFY_EXPR : INIT_EXPR,
+ DECL_CONTEXT (fn), to, arg);
TREE_SIDE_EFFECTS (val) = 1;
- return build_unary_op (ADDR_EXPR, val, 0);
+ address = build_unary_op (ADDR_EXPR, val, 0);
+ /* Avoid a warning about this expression, if the address is
+ never used. */
+ TREE_USED (address) = 1;
+ return address;
}
}
else if (DECL_NAME (fn) == ansi_opname[MODIFY_EXPR]
@@ -3451,12 +3497,6 @@ build_over_call (cand, args, flags)
arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0);
- /* Don't copy the padding byte; it might not have been allocated
- if to is a base subobject. */
- if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
- return build (COMPOUND_EXPR, TREE_TYPE (to),
- cp_convert (void_type_node, arg), to);
-
val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
TREE_SIDE_EFFECTS (val) = 1;
return val;
@@ -3545,6 +3585,8 @@ build_new_method_call (instance, name, args, basetype_path, flags)
remove it for error reporting. */
if (flags & LOOKUP_HAS_IN_CHARGE)
user_args = TREE_CHAIN (args);
+ if (flags & LOOKUP_HAS_VLIST)
+ user_args = TREE_CHAIN (user_args);
args = resolve_args (args);
@@ -3617,6 +3659,12 @@ build_new_method_call (instance, name, args, basetype_path, flags)
if (name == ctor_identifier && TYPE_USES_VIRTUAL_BASECLASSES (basetype)
&& ! (flags & LOOKUP_HAS_IN_CHARGE))
{
+ if (TYPE_USES_PVBASES(basetype)
+ && (!flag_vtable_thunks_compat || (name == dtor_identifier)))
+ {
+ args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args);
+ flags |= LOOKUP_HAS_VLIST;
+ }
flags |= LOOKUP_HAS_IN_CHARGE;
args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
}
@@ -4333,8 +4381,8 @@ joust (cand1, cand2, warn)
!= DECL_CONSTRUCTOR_P (cand2->fn))
/* Don't warn if the two conv ops convert to the same type... */
|| (! DECL_CONSTRUCTOR_P (cand1->fn)
- && ! same_type_p (TREE_TYPE (cand1->second_conv),
- TREE_TYPE (cand2->second_conv)))))
+ && ! same_type_p (TREE_TYPE (TREE_TYPE (cand1->fn)),
+ TREE_TYPE (TREE_TYPE (cand2->fn))))))
{
int comp = compare_ics (cand1->second_conv, cand2->second_conv);
if (comp != winner)