[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:
    //
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.