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 = "";
}
}