[regex] Thread safety patch.
"John Maddock" <[email protected]>
| Newsgroups | gmane.comp.lib.boost.announce,gmane.comp.lib.boost.user |
|---|---|
| Message-ID | <01a801c6b54a$b99847d0$7ce81b52@fuji> |
With apologies to all concerned, and thanks to Aleksey Sanin for tracking down the problem, there is a const-correctness bug in Boost.Regex-1.33.x that strikes only in multithreaded programs on Unix platforms, if: * Multiple threads construct regexes concurrently, or * Multiple threads perform search and replace operations concurrently. There are two possible fixes: * Apply the attached patch (this has just gone into cvs along with an updated test case that detects the issue). Or, * define BOOST_REGEX_USE_C_LOCALE in boost/user.hpp and rebuild everything. Regards, John Maddock. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost-announce
regex-thread.diff
(application/octet-stream, 7.5 KB)
Index: boost/regex/pending/object_cache.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/regex/pending/object_cache.hpp,v
retrieving revision 1.7
diff -u -b -r1.7 object_cache.hpp
--- boost/regex/pending/object_cache.hpp 30 Nov 2005 13:56:54 -0000 1.7
+++ boost/regex/pending/object_cache.hpp 29 Jul 2006 15:42:38 -0000
@@ -35,16 +35,16 @@
class object_cache
{
public:
- typedef std::pair< ::boost::shared_ptr<Object>, Key const*> value_type;
+ typedef std::pair< ::boost::shared_ptr<Object const>, Key const*> value_type;
typedef std::list<value_type> list_type;
typedef typename list_type::iterator list_iterator;
typedef std::map<Key, list_iterator> map_type;
typedef typename map_type::iterator map_iterator;
typedef typename list_type::size_type size_type;
- static boost::shared_ptr<Object> get(const Key& k, size_type max_cache_size);
+ static boost::shared_ptr<Object const> get(const Key& k, size_type max_cache_size);
private:
- static boost::shared_ptr<Object> do_get(const Key& k, size_type max_cache_size);
+ static boost::shared_ptr<Object const> do_get(const Key& k, size_type max_cache_size);
struct data
{
@@ -58,7 +58,7 @@
};
template <class Key, class Object>
-boost::shared_ptr<Object> object_cache<Key, Object>::get(const Key& k, size_type max_cache_size)
+boost::shared_ptr<Object const> object_cache<Key, Object>::get(const Key& k, size_type max_cache_size)
{
#ifdef BOOST_HAS_THREADS
static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT;
@@ -80,7 +80,7 @@
}
template <class Key, class Object>
-boost::shared_ptr<Object> object_cache<Key, Object>::do_get(const Key& k, size_type max_cache_size)
+boost::shared_ptr<Object const> object_cache<Key, Object>::do_get(const Key& k, size_type max_cache_size)
{
typedef typename object_cache<Key, Object>::data object_data;
typedef typename map_type::size_type map_size_type;
@@ -115,7 +115,7 @@
// if we get here then the item is not in the cache,
// so create it:
//
- boost::shared_ptr<Object> result(new Object(k));
+ boost::shared_ptr<Object const> result(new Object(k));
//
// Add it to the list, and index it:
//
Index: boost/regex/v4/cpp_regex_traits.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/regex/v4/cpp_regex_traits.hpp,v
retrieving revision 1.16
diff -u -b -r1.16 cpp_regex_traits.hpp
--- boost/regex/v4/cpp_regex_traits.hpp 14 Sep 2005 12:20:07 -0000 1.16
+++ boost/regex/v4/cpp_regex_traits.hpp 29 Jul 2006 15:42:38 -0000
@@ -407,12 +407,12 @@
typedef charT char_type;
//cpp_regex_traits_implementation();
cpp_regex_traits_implementation(const std::locale& l)
- : cpp_regex_traits_char_layer<charT>(l), m_is(&m_sbuf)
+ : cpp_regex_traits_char_layer<charT>(l)
{
init();
}
cpp_regex_traits_implementation(const cpp_regex_traits_base<charT>& l)
- : cpp_regex_traits_char_layer<charT>(l), m_is(&m_sbuf)
+ : cpp_regex_traits_char_layer<charT>(l)
{
init();
}
@@ -439,8 +439,6 @@
string_type lookup_collatename(const charT* p1, const charT* p2) const;
string_type transform_primary(const charT* p1, const charT* p2) const;
string_type transform(const charT* p1, const charT* p2) const;
- re_detail::parser_buf<charT> m_sbuf; // buffer for parsing numbers.
- std::basic_istream<charT> m_is; // stream for parsing numbers.
private:
std::map<int, std::string> m_error_strings; // error messages indexed by numberic ID
std::map<string_type, char_class_type> m_custom_class_names; // character class names
@@ -816,7 +814,7 @@
template <class charT>
-inline boost::shared_ptr<cpp_regex_traits_implementation<charT> > create_cpp_regex_traits(const std::locale& l BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(charT))
+inline boost::shared_ptr<const cpp_regex_traits_implementation<charT> > create_cpp_regex_traits(const std::locale& l BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(charT))
{
cpp_regex_traits_base<charT> key(l);
return ::boost::object_cache<cpp_regex_traits_base<charT>, cpp_regex_traits_implementation<charT> >::get(key, 5);
@@ -954,7 +952,7 @@
static std::string get_catalog_name();
private:
- boost::shared_ptr<re_detail::cpp_regex_traits_implementation<charT> > m_pimpl;
+ boost::shared_ptr<const re_detail::cpp_regex_traits_implementation<charT> > m_pimpl;
//
// catalog name handler:
//
@@ -969,17 +967,21 @@
template <class charT>
int cpp_regex_traits<charT>::toi(const charT*& first, const charT* last, int radix)const
{
+ re_detail::parser_buf<charT> sbuf; // buffer for parsing numbers.
+ std::basic_istream<charT> is(&sbuf); // stream for parsing numbers.
+
// we do NOT want to parse any thousands separators inside the stream:
- last = std::find(first, last, BOOST_USE_FACET(std::numpunct<charT>, m_pimpl->m_is.getloc()).thousands_sep());
- m_pimpl->m_sbuf.pubsetbuf(const_cast<charT*>(static_cast<const charT*>(first)), static_cast<std::streamsize>(last-first));
- m_pimpl->m_is.clear();
- if(std::abs(radix) == 16) m_pimpl->m_is >> std::hex;
- else if(std::abs(radix) == 8) m_pimpl->m_is >> std::oct;
- else m_pimpl->m_is >> std::dec;
+ last = std::find(first, last, BOOST_USE_FACET(std::numpunct<charT>, is.getloc()).thousands_sep());
+
+ sbuf.pubsetbuf(const_cast<charT*>(static_cast<const charT*>(first)), static_cast<std::streamsize>(last-first));
+ is.clear();
+ if(std::abs(radix) == 16) is >> std::hex;
+ else if(std::abs(radix) == 8) is >> std::oct;
+ else is >> std::dec;
int val;
- if(m_pimpl->m_is >> val)
+ if(is >> val)
{
- first = first + ((last - first) - m_pimpl->m_sbuf.in_avail());
+ first = first + ((last - first) - sbuf.in_avail());
return val;
}
else
Index: boost/regex/v4/w32_regex_traits.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/regex/v4/w32_regex_traits.hpp,v
retrieving revision 1.9
diff -u -b -r1.9 w32_regex_traits.hpp
--- boost/regex/v4/w32_regex_traits.hpp 13 Dec 2005 17:24:28 -0000 1.9
+++ boost/regex/v4/w32_regex_traits.hpp 29 Jul 2006 15:42:39 -0000
@@ -166,7 +166,7 @@
{
return ::boost::re_detail::w32_tolower(c, this->m_locale);
}
- bool isctype(boost::uint32_t mask, charT c)
+ bool isctype(boost::uint32_t mask, charT c)const
{
return ::boost::re_detail::w32_is(this->m_locale, mask, c);
}
@@ -263,7 +263,7 @@
{
return m_lower_map[static_cast<unsigned char>(c)];
}
- bool isctype(boost::uint32_t mask, char c)
+ bool isctype(boost::uint32_t mask, char c)const
{
return m_type_map[static_cast<unsigned char>(c)] & mask;
}
@@ -540,7 +540,7 @@
template <class charT>
-boost::shared_ptr<w32_regex_traits_implementation<charT> > create_w32_regex_traits(::boost::re_detail::lcid_type l BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(charT))
+boost::shared_ptr<const w32_regex_traits_implementation<charT> > create_w32_regex_traits(::boost::re_detail::lcid_type l BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(charT))
{
// TODO: create a cache for previously constructed objects.
return boost::object_cache< ::boost::re_detail::lcid_type, w32_regex_traits_implementation<charT> >::get(l, 5);
@@ -654,7 +654,7 @@
static std::string get_catalog_name();
private:
- boost::shared_ptr<re_detail::w32_regex_traits_implementation<charT> > m_pimpl;
+ boost::shared_ptr<const re_detail::w32_regex_traits_implementation<charT> > m_pimpl;
//
// catalog name handler:
//