diff mbox

[asan] Patch - fix an ICE in asan.c

Message ID 509D6965.5040405@net-b.de
State New
Headers show

Commit Message

Tobias Burnus Nov. 9, 2012, 8:36 p.m. UTC
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.
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 = "";
  }
}

Comments

Tobias Burnus Nov. 9, 2012, 10 p.m. UTC | #1
Tobias Burnus wrote:
> The attached test case ICEs (segfault) both on the asan branch and on
> the trunk with Dodji's patches:

I found another ICE - this time without a patch.

[That's with the patch, which I posted in this thread. Without, one 
seems to run into the problem I tried to fix with the patch.]

[As ASAN is not yet in the trunk, it is not yet suitable for a PR - but 
on the other hand, I am afraid that I loose it. Thus, I dump it here, 
which is also not the best place (sorry).]


The attached code generates (before ASAN):

StringSwitch<T, R>& StringSwitch ...
...
   <bb 2>:
   _2 = &this_1(D)->Str;
   _3 = StringRef::data (_2);
   memcmp (S_4(D), _3, 7);
   return;
}

And within this basic block, between "_3" and "memcpy", the generated 
ASAN code is added, which leads to an ICE and 10 times the message.


error: control flow in the middle of basic block 7


If one looks at the asan0 dump (after disabling this part of checking), 
one finds:

   _52 = _48 & _51;
   if (_52 != 0)
   _53 = (unsigned long) _22;

The "if" line looks odd as one would expect code of this form:

   if (_62 != 0)
     goto <bb 12>;
   else
     goto <bb 11>;

See attachments.

Tobias
extern "C"
{
  extern int memcmp (const void *__s1, const void *__s2,
		     long unsigned int __n) throw ();
}
struct StringRef
{
  const char *data () const { }
};
template < typename T, typename R = T > class StringSwitch
{
  StringRef Str;
  public:
     explicit StringSwitch (StringRef Str):Str (Str) { }
  template < unsigned N > StringSwitch & Case (const char (&S)[N])
  {
    memcmp (S, Str.data (), N - 1);
  }
  R Default () const { }
};

int getIt (StringRef Name)
{
  return StringSwitch < int > (Name)
    .Case ("unknown")
    .Default ();
}
;; Function const char* StringRef::data() const (_ZNK9StringRef4dataEv, funcdef_no=0, decl_uid=2200, cgraph_uid=0)

const char* StringRef::data() const (const struct StringRef * const this)
{
  <bb 2>:
  GIMPLE_NOP
  return;

}



;; Function int getIt(StringRef) (_Z5getIt9StringRef, funcdef_no=4, decl_uid=2230, cgraph_uid=1)

int getIt(StringRef) (struct StringRef Name)
{
  struct StringSwitch & D.2293;
  struct StringRef D.2292;
  struct StringRef D.2277;
  struct StringSwitch D.2278;
  int D.2291;
  struct StringSwitch & _1;
  int _2;

  <bb 2>:
  StringSwitch<int>::StringSwitch (&D.2278, D.2292);
  _1 = StringSwitch<int>::Case<8u> (&D.2278, "unknown");
  _2 = StringSwitch<int>::Default (_1);
  D.2278 ={v} {CLOBBER};

<L1>:
  return _2;

}



;; Function StringSwitch<T, R>::StringSwitch(StringRef) [with T = int; R = int] (_ZN12StringSwitchIiiEC2E9StringRef, funcdef_no=6, decl_uid=2249, cgraph_uid=3)

StringSwitch<T, R>::StringSwitch(StringRef) [with T = int; R = int] (struct StringSwitch * const this, struct StringRef Str)
{
  <bb 2>:
  return;

}



;; Function StringSwitch<T, R>& StringSwitch<T, R>::Case(const char (&)[N]) [with unsigned int N = 8u; T = int; R = int] (_ZN12StringSwitchIiiE4CaseILj8EEERS0_RAT__Kc, funcdef_no=8, decl_uid=2279, cgraph_uid=5)

StringSwitch<T, R>& StringSwitch<T, R>::Case(const char (&)[N]) [with unsigned int N = 8u; T = int; R = int] (struct StringSwitch * const this, const char[8] & S)
{
  const char * D.2297;
  struct StringRef * D.2296;
  struct StringRef * _2;
  const char * _3;
  unsigned long _5;
  unsigned long _6;
  unsigned long _7;
  signed char * _8;
  signed char _9;
  bool _10;
  unsigned long _11;
  signed char _12;
  bool _13;
  bool _14;
  long unsigned int _15;
  long unsigned int _16;
  const char[8] & _17;
  const char[8] & _18;
  unsigned long _19;
  unsigned long _20;
  unsigned long _21;
  signed char * _22;
  signed char _23;
  bool _24;
  unsigned long _25;
  signed char _26;
  bool _27;
  bool _28;
  unsigned long _29;
  unsigned long _30;
  unsigned long _31;
  signed char * _32;
  signed char _33;
  bool _34;
  unsigned long _35;
  signed char _36;
  bool _37;
  bool _38;
  long unsigned int _39;
  long unsigned int _40;
  const char * _41;
  const char * _42;
  unsigned long _43;
  unsigned long _44;
  unsigned long _45;
  signed char * _46;
  signed char _47;
  bool _48;
  unsigned long _49;
  signed char _50;
  bool _51;
  bool _52;
  unsigned long _53;
  unsigned long _54;
  unsigned long _55;
  signed char * _56;
  signed char _57;
  bool _58;
  unsigned long _59;
  signed char _60;
  bool _61;
  bool _62;

  <bb 2>:
  _2 = &this_1(D)->Str;
  _3 = StringRef::data (_2);
  _5 = (unsigned long) S_4(D);
  _6 = _5 >> 3;
  _7 = _6 + 17592186044416;
  _8 = (signed char *) _7;
  _9 = *_8;
  _10 = _9 != 0;
  _11 = _5 & 7;
  _12 = (signed char) _11;
  _13 = _12 >= _9;
  _14 = _10 & _13;
  if (_14 != 0)
    goto <bb 4>;
  else
    goto <bb 3>;

  <bb 4>:
  __asan_report_load1 (_5);

  <bb 3>:
  _29 = (unsigned long) _3;
  _30 = _29 >> 3;
  _31 = _30 + 17592186044416;
  _32 = (signed char *) _31;
  _33 = *_32;
  _34 = _33 != 0;
  _35 = _29 & 7;
  _36 = (signed char) _35;
  _37 = _36 >= _33;
  _38 = _34 & _37;
  if (_38 != 0)
    goto <bb 8>;
  else
    goto <bb 7>;

  <bb 8>:
  __asan_report_load1 (_29);

  <bb 7>:
  _39 = 7;
  _40 = _39 - 1;
  _41 = _3;
  _42 = _41 + _40;
  _43 = (unsigned long) _42;
  _44 = _43 >> 3;
  _45 = _44 + 17592186044416;
  _46 = (signed char *) _45;
  _47 = *_46;
  _48 = _47 != 0;
  _49 = _43 & 7;
  _50 = (signed char) _49;
  _51 = _50 >= _47;
  _52 = _48 & _51;
  if (_52 != 0)
  _53 = (unsigned long) _22;
  _54 = _53 >> 3;
  _55 = _54 + 17592186044416;
  _56 = (signed char *) _55;
  _57 = *_56;
  _58 = _57 != 0;
  _59 = _53 & 7;
  _60 = (signed char) _59;
  _61 = _60 >= _57;
  _62 = _58 & _61;
  if (_62 != 0)
    goto <bb 12>;
  else
    goto <bb 11>;

  <bb 12>:
  __asan_report_load1 (_53);

  <bb 11>:

  <bb 10>:
  __asan_report_load1 (_43);

  <bb 9>:
  _15 = 7;
  _16 = _15 - 1;
  _17 = S_4(D);
  _18 = _17 + _16;
  _19 = (unsigned long) _18;
  _20 = _19 >> 3;
  _21 = _20 + 17592186044416;
  _22 = (signed char *) _21;
  _23 = *_22;
  _24 = _23 != 0;
  _25 = _19 & 7;
  _26 = (signed char) _25;
  _27 = _26 >= _23;
  _28 = _24 & _27;
  if (_28 != 0)
    goto <bb 6>;
  else
    goto <bb 5>;

  <bb 6>:
  __asan_report_load1 (_19);

  <bb 5>:
  memcmp (S_4(D), _3, 7);
  return;

}
Dodji Seketeli Nov. 12, 2012, 11:51 a.m. UTC | #2
Tobias Burnus <burnus@net-b.de> writes:

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

Thank you for reporting this.

I believe the neqw series of patches I have juste posted address this
issue.

To ease the testing, you can check out an updated git tree with all
these patches cleanly stacked on top of trunk by doing:

    git clone -b asan-merge-assemble git://seketeli.net/~dodji/gcc.git

You can browse the patchset it via the web at: 

    http://seketeli.net/git/~dodji/gcc.git/log/?h=asan-merge-assemble

Cheers.
diff mbox

Patch

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