Hi,

On Thu, Jun 30, 2011 at 10:01:58AM -0700, Delesley Hutchins wrote:
> This bug fixes a failure in annotalysis that is caused when gcc does
> not return the correct static type for the callee of a virtual method.
> 
> Bootstrapped and passed GCC regression testsuite on x86_64-unknown-linux-gnu.
> 
> Okay for branches/annotalysis and google/main?
> 
>   -DeLesley
> 
> 
> 2011-06-30   DeLesley Hutchins  <deles...@google.com>
>         * tree-threadsafe-analyze.c (handle_call_gs): Fixes case where
> the virtual
>         method callee has unknown type.
> 
> 
> Index: gcc/testsuite/g++.dg/thread-ann/thread_annot_lock-79.C
> ===================================================================
> --- gcc/testsuite/g++.dg/thread-ann/thread_annot_lock-79.C    (revision 0)
> +++ gcc/testsuite/g++.dg/thread-ann/thread_annot_lock-79.C    (revision 0)
> @@ -0,0 +1,54 @@
> +// Test virtual method calls in cases where the static type is unknown
> +// This is a "good" test case that should not incur any thread safety 
> warning.
> +// { dg-do compile }
> +// { dg-options "-Wthread-safety -O" }
> +
> +#include "thread_annot_common.h"
> +
> +class Foo {
> +public:
> +  Mutex m;
> +
> +  Foo();
> +  virtual ~Foo();
> +  virtual void doSomething() EXCLUSIVE_LOCKS_REQUIRED(m) = 0;
> +};
> +
> +
> +class FooDerived : public Foo {
> +public:
> +  FooDerived();
> +  virtual ~FooDerived();
> +  virtual void doSomething();
> +};
> +
> +
> +/**
> + * This is a test case for a bug wherein annotalysis would crash when
> analyzing
> + * a virtual method call.
> + *
> + * The following three functions represent cases where gcc loses the static
> + * type of foo in the expression foo->doSomething() when it drops down to
> + * gimple.  Annotalysis should technically issue a thread-safe
> warning in these
> + * cases, but because the type is missing, it should silently accept them
> + * instead.  See tree-threadsafe-analyze.c::handle_call_gs.
> + */
> +
> +// reinterpret_cast
> +void foo1(void* ptr)
> +{
> +  reinterpret_cast<Foo*>(ptr)->doSomething();
> +}
> +
> +// C-style cast
> +void foo2(int* buf)
> +{
> +  ((Foo*) buf)->doSomething();
> +}
> +
> +// new expression, with no local variable
> +void foo3()
> +{
> +  (new FooDerived)->doSomething();
> +}
> +
> Index: gcc/tree-threadsafe-analyze.c
> ===================================================================
> --- gcc/tree-threadsafe-analyze.c     (revision 175385)
> +++ gcc/tree-threadsafe-analyze.c     (working copy)
> @@ -2446,7 +2446,18 @@
>        if (TREE_CODE (callee) == OBJ_TYPE_REF)
>          {
>            tree objtype = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT 
> (callee)));
> -          fdecl = lang_hooks.get_virtual_function_decl (callee, objtype);
> +          /* Check to make sure objtype is a valid type.
> +           * OBJ_TYPE_REF_OBJECT does not always return the correct
> static type of the callee.
> +           * For example:  Given  foo(void* ptr) { ((Foo*)
> ptr)->doSomething(); }
> +           * objtype will be void, not Foo.  Whether or not this
> happens depends on the details
> +           * of how a particular call is lowered to GIMPLE, and there
> is no easy fix that works
> +           * in all cases.  For now, we simply rely on gcc's type
> information; if that information
> +           * is not accurate, then the analysis will be less precise.
> +           */
> +          if (TREE_CODE(objtype) == RECORD_TYPE)  /* if objtype is an
> object type... */
> +            {
> +              fdecl = lang_hooks.get_virtual_function_decl (callee, objtype);
> +            }
>          }
>      }

If you in some way rely on static types of those pointers, you may be
in for a number of unpleasant surprises, because these types do not
really have any meaning at all.  Just out of curiosity, I does your
analysis crash also on the testcase below (add the Mutex field if it
is necessary)?

Also, I have just very briefly glanced at the code in handle_call_gs
but still it seems to me that the code dealing with virtual calls
assumes virtual functions are never overridden...?

And pretty please, use -p diff option when creating patches to be
posted here.

Thanks,

Martin


namespace std {
  typedef __SIZE_TYPE__ size_t;
}
inline void* operator new(std::size_t, void* __p) throw() {
  return __p;
}
extern "C" void abort (void);

struct Foo {
public:
  char stuff[1024];
};

class Bar {
public:
  virtual int test (void) { return 1; }
};

Foo ft;
Foo *f = &ft;

int main()
{
  Bar *b;
  b = new (&f) Bar();
  return b->test();
}

Reply via email to