This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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]

[PATCH] Fix collate::do_tranform


Hi,

while trying to understand more of some problems recently reported for collate tests
(see also my previous message) I came to the conclusion that the current do_transform
is /s/e/r/i/o/u/s/l/y broken!
Here it is, for your convenience:

 template<typename _CharT>
    typename collate<_CharT>::string_type
    collate<_CharT>::
    do_transform(const _CharT* __lo, const _CharT* __hi) const
    {
      size_t __len = __hi - __lo;
      _CharT* __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len));
      size_t __res = _M_transform_helper(__c, __lo, __len);
      if (__res >= __len)
        {
          // Try to increment size of translated string.
          size_t __len2 = __len * 2;
          _CharT* __c2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) *
__len2));
          __res = _M_transform_helper(__c2, __lo, __len);
          // XXX Throw exception if still indeterminate?
        }
      return string_type(__c);
    }

For one, as I understand glibc2.2.5 docs, there is no guarantee that __len * 2 chars
are sufficient, in the general case. More seriously, when __res >= __len, the call to
_M_transform_helper must be also adjusted to something like _M_transform_helper(__c2,
__lo, __len * 2). But there is more. In the current code, when __res >= __len, __c2
should be returned, *not* __c!

Gulp!

So, I rewrote it, closely following the detailed glibc2.2.5 docs, which comes
complete with an example of correct use of strxfrm:

 template<typename _CharT>
    typename collate<_CharT>::string_type
    collate<_CharT>::
    do_transform(const _CharT* __lo, const _CharT* __hi) const
    {
      size_t __len = (__hi - __lo) * 2;
      // First try a buffer perhaps big enough.
      _CharT* __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len));
      size_t __res = _M_transform_helper(__c, __lo, __len);
      // If the buffer was not large enough, try again with the correct size.
      if (__res >= __len)
        {
          _CharT* __c2 =
            static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * (__res + 1)));
          size_t __res2 = _M_transform_helper(__c2, __lo, __res + 1);
          return string_type(__c2);
        }
      return string_type(__c);
    }

On my system (i686-pc-linux-gnu, binutils2.11.2 -> no versioning) this fixes:

    XPASS: 22_locale/collate_members_char.cc execution test

down to 2 expected failures (yeah!):

                === libstdc++-v3 Summary ===

# of expected passes            358
# of unexpected failures        1
# of unexpected successes       23
# of expected failures          2

Is the patch OK for mainline and branch?

Ciao, Paolo.

///////////

2002-03-09  Paolo Carlini  <pcarlini@unitus.it>

        * include/bits/locale_facets.tcc (collate::do_transform):
        Rewrite to fix problems with long transformed strings.

*** locale_facets.tcc.~1.69.~ Sat Mar  9 03:01:30 2002
--- locale_facets.tcc Sat Mar  9 12:46:34 2002
*************** namespace std
*** 1854,1869 ****
      collate<_CharT>::
      do_transform(const _CharT* __lo, const _CharT* __hi) const
      {
!       size_t __len = __hi - __lo;
        _CharT* __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len));

        size_t __res = _M_transform_helper(__c, __lo, __len);
        if (__res >= __len)
   {
!    // Try to increment size of translated string.
!    size_t __len2 = __len * 2;
!    _CharT* __c2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len2));
!    __res = _M_transform_helper(__c2, __lo, __len);
!    // XXX Throw exception if still indeterminate?
   }
        return string_type(__c);
      }
--- 1854,1870 ----
      collate<_CharT>::
      do_transform(const _CharT* __lo, const _CharT* __hi) const
      {
!       size_t __len = (__hi - __lo) * 2;
!       // First try a buffer perhaps big enough.
        _CharT* __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len));

        size_t __res = _M_transform_helper(__c, __lo, __len);
+       // If the buffer was not large enough, try again with the correct size.
        if (__res >= __len)
   {
!    _CharT* __c2 =
!      static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * (__res + 1)));
!    size_t __res2 = _M_transform_helper(__c2, __lo, __res + 1);
!    return string_type(__c2);
   }
        return string_type(__c);
      }




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