The attached test case ICEs (segfault) both on the asan branch and on the trunk with Dodji's patches:

fail31.ii: In static member function 'static std::size_t std::char_traits<char>::length(const char_type*)':
fail31.ii:13:19: internal compiler error: Segmentation fault
     static size_t length (const char_type * __s)
                   ^
0xae02ef crash_signal
        /projects/tob/gcc-git/gcc/gcc/toplev.c:334
0xaf031d gsi_next
        /projects/tob/gcc-git/gcc/gcc/gimple.h:5072
0xaf031d transform_statements
        /projects/tob/gcc-git/gcc/gcc/asan.c:1357
0xaf031d asan_instrument
        /projects/tob/gcc-git/gcc/gcc/asan.c:1556



The problem is in asa.c's transform_statements:

  FOR_EACH_BB (bb)
    {
      if (bb->index >= saved_last_basic_block) continue;
      for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
        {
          gimple s = gsi_stmt (i);

          if (gimple_assign_single_p (s))
            instrument_assignment (&i);
          else if (is_gimple_call (s))
            maybe_instrument_call (&i);
    }


Here, "gsi_end_p(i)" is the check "i->ptr == NULL" and gsi_next(&i) is "i->ptr = i->ptr->gsbase.next;"

Thus, it looks fine at a glance. However, the problem is that the gsi_end_p check is done before the loop body while "gsi_next" is called after the loop body. That's fine unless "i" is modified in between, which happens in

instrument_strlen_call (gimple_stmt_iterator *iter)
...
  gimple_stmt_iterator gsi = *iter;
...
  *iter = gsi;
}

After the call, iter->ptr == NULL.


Is the patch okay for the ASAN branch?*

Tobias

* I still have to do an all-language bootstrap and regtesting, though the latter is probably pointless as there is currently not a single -fasan test case.
--- gcc/asan.c.orig	2012-11-09 21:26:26.000000000 +0100
+++ gcc/asan.c	2012-11-09 21:26:00.000000000 +0100
@@ -1362,6 +1362,8 @@ transform_statements (void)
 	    instrument_assignment (&i);
 	  else if (is_gimple_call (s))
 	    maybe_instrument_call (&i);
+	  if (gsi_end_p (i))
+	    break;
         }
     }
 }
namespace std
{
  template < typename _Alloc > class allocator;
  template < class _CharT > struct char_traits;
    template < typename _CharT, typename _Traits =
    char_traits < _CharT >, typename _Alloc =
    allocator < _CharT > >class basic_string;
  typedef basic_string < char >string;
  typedef long unsigned int size_t;
    template <> struct char_traits <char >
  {
    typedef char char_type;
    static size_t length (const char_type * __s)
    {
      return __builtin_strlen (__s);
    }
  };
  namespace __gnu_cxx
  {
    template < typename _Tp > class new_allocator
    {
    public:
      typedef size_t size_type;
        template < typename _Tp1 > struct rebind
      {
        typedef new_allocator < _Tp1 > other;
      };
    };
  }
template < typename _Tp > class allocator:public __gnu_cxx::new_allocator <
    _Tp >
  {
  };
  template < typename _CharT, typename _Traits, typename _Alloc >
    class basic_string
  {
    typedef typename _Alloc::template rebind <
      _CharT >::other _CharT_alloc_type;
    typedef _Traits traits_type;
    typedef typename _CharT_alloc_type::size_type size_type;
  public:
    basic_string & operator= (const _CharT * __s)
    {
      return this->assign (__s, traits_type::length (__s));
    }
    basic_string & assign (const _CharT * __s, size_type __n);
  };

  class Regex
  {
    std::string sub (std::string * Error);
  };

  std::string Regex::sub (std::string * Error)
  {
    *Error = "";
  }
}

Reply via email to