http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50610

             Bug #: 50610
           Summary: G++ 4.4.3: Incorrect code at -O2 (-fwrapv, SafeInt,
                    c++ templates, template class files)
    Classification: Unclassified
           Product: gcc
           Version: 4.4.3
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: other
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: noloa...@gmail.com


Created attachment 25407
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=25407
Test case for bad code generation at -O2

Attached is a test program which uses a secure vector. The secure vector 'has
a' standard vector, and attempts to do a few extra things to help ensure safe
use (such as check for pointer wrap and zeroization). In addition, the secure
vector uses LeBlanc's SafeInt class to check for wraps and overflows. (SafeInt
uses unsigned, so no undefined behavior should be present).

The test program incorrectly rejects a valid input:

$ g++ -g -O2 -fwrapv -I. TestMain.cpp SecureArray.cpp -o TestMain.exe
$ ./TestMain.exe
Array pointer wrap
$

TestMain is as follows:

  try
  {
    const int arr[] = { 1, 1, 1, 1 };
    SecureIntArray vv(arr, COUNTOF(arr));
    assert(vv.size() == 4);
  }
  catch(const std::exception& ex)
  {
    cerr << ex.what() << endl;
  }

The SecureIntArray ctor calls into a helper function:

  template <typename T>
  typename SecureArray<T>::SecureVector*
  SecureArray<T>::create_secure_array(const T* ptr, size_t cnt)
  {
    try
    {
      const size_t base = (size_t)ptr;
      SafeInt<size_t> si(cnt);
      si *= sizeof(T);
      si += base;
    }
    catch(const SafeIntException&)
    {
      throw InvalidArgumentException("Array pointer wrap");
    }

    return new SecureVector(ptr /*first*/, ptr+cnt /*last*/);
  }

*If* I manually check for overflow (ie, no SafeInt use), I get expected
results:
$ g++ -g -O2 -DSECURE_ARRAY_NO_SAFE_INT=1 -I. TestMain.cpp SecureArray.cpp -o
TestMain.exe
$ ./TestMain.exe
$ 

Defining SECURE_ARRAY_NO_SAFE_INT uses the following rather than SafeInt
objects:

    const size_t b = (size_t)ptr;
    size_t p = cnt * sizeof(T) + b;
    if(!(p >= b))
      throw InvalidArgumentException("Array pointer wrap");

Finally, the issue is not present on other versions of GCC. Other versions
include 4.5 from F14 and 4.6 from F15.

I was not able to reduce the test program to something smaller (though I
tried). For example, I know the following will not help the problem: removing
namespaces, removing throws, removing explicit template instantiations, moving
bodies into the header, and a few other items.

I do know that removing everything except the ctor, size(), max_size(), and
operator[] will fix it, but it does not help with a minimum test case.

Reply via email to