This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[PATCH] Fix collate::do_tranform
- From: Paolo Carlini <pcarlini at unitus dot it>
- To: libstdc++ at gcc dot gnu dot org
- Cc: bkoz at redhat dot com
- Date: Sat, 09 Mar 2002 14:10:50 +0100
- Subject: [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);
}