http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51772
Bug #: 51772
Summary: --enable-clocale=generic makes unsafe assumptions
about ctype_base::mask
Classification: Unclassified
Product: gcc
Version: 4.7.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
AssignedTo: [email protected]
ReportedBy: [email protected]
Blocks: 51018
config/locale/generic/ctype_members.cc initializes _M_bit like so:
for (size_t __i = 0; __i <= 15; ++__i)
{
_M_bit[__i] = static_cast<mask>(1 << __i);
_M_wmask[__i] = _M_convert_to_wmask(_M_bit[__i]);
}
This assumes that ctype_base::mask is at least 16 bits.
Each element of _M_bit has a single bit set, and is compared to the defined
mask constants in _M_convert_to_wmask:
ctype<wchar_t>::__wmask_type
ctype<wchar_t>::_M_convert_to_wmask(const mask __m) const throw()
{
__wmask_type __ret;
switch (__m)
{
// ...
case xdigit:
__ret = wctype("xdigit");
break;
case alnum:
__ret = wctype("alnum");
break;
case graph:
__ret = wctype("graph");
break;
default:
__ret = __wmask_type();
}
return __ret;
};
If any of the mask constants has more than one bit set it will never be
matched.
e.g. on NetBSD xdigit can never be matched for ctype<wchar_t> because
config/os/bsd/netbsd/ctype_base.h defines the following
typedef unsigned char mask;
static const mask xdigit = _N | _X;
As a result, this valid program aborts:
#include <locale>
#include <assert.h>
class gnu_ctype: public std::ctype<wchar_t> { };
int main()
{
gnu_ctype gctype;
assert(gctype.is(std::ctype_base::xdigit, L'a'));
}