This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Bug libstdc++/11584] ios::iword() fails to zero-initialize storage on failure


On Wed, Sep 17, 2003 at 11:45:29PM -0000, bkoz at gcc dot gnu dot org wrote:
> On closer examination, I don't think this is a bug. 

I don't agree. See below.

> For one thing:
> 
>     int i = std::ios::xalloc();
>     std::cout.iword (i) = 0xdeadbeef;
>     long l = std::cout.iword (i);
>     l == 0xdeadbeef;
> is valid, based on the fact that the index is the same (regardless of the
> replacement operator new). 

First note that iword must try to realloc the array if it is called
with an out of bounds index. This is what happens here and the case
where iword succeeds seems to be standard conforming.

But the bug report is about the case where iword _fails_ to extend the
array. 27.4.2.5[3] clearly states for this case:

| Returns: [...] On failure, a valid long& initialized to 0.

The comparions in the above testcase MUST be false in the case where
iword can't allocate enough memory. The reason is that both iword calls
fail and consequently both calls should return 0.

> If, instead:
> 
> void test01()
> {
>   bool test = true;
>   new_fails = 1;
> 
>   const int i = std::ios::xalloc();
>   std::cout.iword(i) = 0xdeadbeef;
>   long l1 = std::cout.iword(i);
>   VERIFY( l1 == 0xdeadbeef);

This is correct for the success case but false for the failure case.

> [ ... ]
>   // The reference returned may become invalid after another call to
>   // the object's iword member with a different index.  NB: Note the
>   // 'may': it's not required, and in this case should not be
>   // required, as the i size array is still allocated.
>   long l3 = std::cout.iword(i);
>   VERIFY( l3 == 0 || l3 == 0xdeadbeef);

Here we must have l3 == 0xdeadbeef iff iword succeeds. l3 == 0 is correct
iff iword fails!

Note that the term ``reference may become invalid'' above does NOT
mean that the value for a certain index may change. It only means that the
_location_ where that value is stored may change (do to realloc).

The bug is in the following code

   const int i = <very large value, e.g. 0x7FFFFF0>
   std::cout.iword (i) = 0xdeadbeef;
   std::cerr << "expected 0 got " << std::iword (i+1) << std::endl;
   assert (std::cout.iword (i) == 0 || !std::cout.badbit);

which outputs:

   expected 0 got -559038737
   Assertion failed: !std::cout.badbit || std::cout.iword (i) == 0 ...

instead of just

   expected 0 got 0 

The remaining problematic case is: What do we expect from this code:

   const int i = <very large value, e.g. 0x7FFFFF0>
   long & ref =  std::cout.iword (i);
   assert (std::cout.badbit);
   ref = 0xdeadbeef;
   std::cout.iword (i+1) = 0x12345678;
   std::cerr << "ref is " << ref << std::endl;

IMHO it is unreasonable to expect ref to have the value 0xdeadbeef. We
can justify this with the ``reference becomes invalid'' clause cited
above. However, invoking this clause is misleading and doesn't help in
this case, which is even worse:

   const int i = <very large value, e.g. 0x7FFFFF0>
   long & ref =  std::cout.iword (i);
   assert (std::cout.badbit);
   ref = 0xdeadbeef;
   long val = std::cout.iword (i); /* Reference does NOT become invalid */
   assert ((ref == 0xdeadbeef) && (val == 0));

IMHO given the words of the standard the assertion should hold.

  regards  Christian


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]