【问题标题】:Mutex assert in boost regex constructor互斥断言在 boost regex 构造函数中
【发布时间】:2012-10-14 22:51:53
【问题描述】:

我正在为 Arm 使用 boost 1.47,使用 Code Sourcery C++ 编译器 (4.5.1),从面向 Ubuntu 的 Windows 7 交叉编译。

当我们编译调试版本(即启用断言)时,会触发断言:

pthread_mutex_lock.c:62: __pthread_mutex_lock: Assertion 'mutex->__data.__owner == 0' failed.

在发布模式下编译,断言没有被触发,程序工作正常(据我们所知)。

这是在 Ubuntu 10.x Arm 板下发生的。

因此,pthread_mutex_lock 似乎认为互斥锁是由与当前线程不同的线程设置的。此时在我的程序中,我们仍然是单线程的,通过在 main 中打印出 pthread_self 并且就在调用正则表达式构造函数之前进行验证。也就是说,它不应该使断言失败。

下面是触发问题的sn-p代码。

// Set connection server address and port from a URL
bool MyHttpsXmlClient::set_server_url(const std::string& server_url)
{
#ifdef BOOST_HAS_THREADS
cout <<"Boost has threads" << endl;
#else
cout <<"WARNING: boost does not support threads" << endl;
#endif
#ifdef PTHREAD_MUTEX_INITIALIZER
    cout << "pthread mutex initializer" << endl;
#endif
{
        pthread_t id = pthread_self();
        printf("regex: Current threadid: %d\n",id);
}
const boost::regex e("^((http|https)://)?([^:]*)(:([0-9]*))?"); // 2: service, 3: host, 5: port // <-- dies in here

我已确认设置了 BOOST_HAS_THREADS 和 PTHREAD_MUTEX_INITIALIZER。

我尝试通过 boost 来跟踪调试器,但它是模板代码,并且很难跟踪程序集,但我们基本上死在 do_assign (大概是 basic_regex.hpp 中的第 380 行)

basic_regex& assign(const charT* p1,
                      const charT* p2,
                      flag_type f = regex_constants::normal)
{
  return do_assign(p1, p2, f);
}

模板代码是:

// out of line members;
// these are the only members that mutate the basic_regex object,
// and are designed to provide the strong exception guarentee
// (in the event of a throw, the state of the object remains unchanged).
//
template <class charT, class traits>
basic_regex<charT, traits>& basic_regex<charT, traits>::do_assign(const charT* p1,
                    const charT* p2,
                    flag_type f)
{
   shared_ptr<re_detail::basic_regex_implementation<charT, traits> > temp;
   if(!m_pimpl.get())
   {
      temp = shared_ptr<re_detail::basic_regex_implementation<charT, traits> >(new re_detail::basic_regex_implementation<charT, traits>());
   }
   else
   {
      temp = shared_ptr<re_detail::basic_regex_implementation<charT, traits> >(new re_detail::basic_regex_implementation<charT, traits>(m_pimpl->m_ptraits));
   }
   temp->assign(p1, p2, f);
   temp.swap(m_pimpl);
   return *this;
}

我不确定哪个组件实际上在使用互斥锁——有人知道吗?

在调试器中,我可以检索变量 mutex 的地址,然后检查 (mutex-&gt;__data.__owner)。我从编译器头文件 bits/pthreadtypes.h 中得到了偏移量,它显示:

/* Data structures for mutex handling.  The structure of the attribute
   type is not exposed on purpose.  */
typedef union
{
  struct __pthread_mutex_s
  {
    int __lock;
    unsigned int __count;
    int __owner;
    /* KIND must stay at this position in the structure to maintain
       binary compatibility.  */
    int __kind;
    unsigned int __nusers;
    __extension__ union
    {
      int __spins;
      __pthread_slist_t __list;
    };
  } __data;
  char __size[__SIZEOF_PTHREAD_MUTEX_T];
  long int __align;

我使用这些偏移量来检查内存中的数据。这些值没有意义: 例如,__data.__lock 字段(一个 int)是 0xb086b580。 __count(无符号整数)是 0x6078af00,__owner(整数)是 0x6078af00。

这让我觉得这个互斥锁的初始化没有被执行。要么它要么完全损坏,但我倾向于错过初始化,因为当我与调试提升库链接时,没有断言。

现在,我假设正在查询的任何互斥体都是一些用于使正则表达式线程安全的全局/静态,并且不知何故它没有被初始化。

  • 有没有人遇到过类似的情况? Ubuntu 是否需要一些额外的步骤来确保互斥体初始化?
  • 我的实现假设是否正确?
  • 如果正确,谁能指出这个互斥锁的声明位置以及初始化的位置
  • 对进一步的调试步骤有什么建议吗?我在想我可能必须以某种方式下载源代码并在那里进行跟踪重建(希望 StackOverflow 能在我到达这一点之前帮助我)

【问题讨论】:

  • 如果我不得不猜测,互斥锁在共享指针实现中。您是否有可能使用“valgrind”之类的东西来查看是否存在损坏底层数据的内存损坏?
  • 你能用更简单的 RE 解决问题吗?有一个非常短的程序和相同的 RE?有一个简短的程序和一个简短的 RE?当错误发生时,你的堆栈是什么样子的?它是植根于 main 还是在那之前?
  • valgrind 是个好主意,但在使用它之前,您能否尝试使用 pthread_mutex_init 显式初始化互斥锁?
  • 另外,正如 Yakk 所暗示的,你能写一个出现同样问题的简单程序吗?
  • 见帖子的第一行:Arm 的 boost 1.47

标签: c++ regex linux boost initialization


【解决方案1】:

在像 boost 这样经过充分测试的知名库中何时出现真正特殊的运行时崩溃时,首先要检查的事情之一是是否存在头文件/库配置不匹配。恕我直言,将 _DEBUG 或 NDEBUG 放在标题中,尤其是在结构中以影响其二进制布局的方式,是一种反模式。理想情况下,无论我们定义 _DEBUG、DEBUG、Debug、Debug、NDEBUG 还是其他任何东西,我们都应该能够使用相同的 .lib(以便我们可以根据是否要进行调试来选择 .lib符号与否,而不是它是否匹配标题定义)。不幸的是,情况并非总是如此。

【讨论】:

  • 是的,这确实是问题所在。我正在构建启用调试的源代码,它利用各种定义,如 DEBUG,但链接到非调试库。我(错误地)假设调试库和非调试库之间的唯一区别是代码没有优化并且有调试信息。这个假设是如此根深蒂固,我从未想过在问题的原始发布中包含我的链接或编译行。但是,boost 中的结构布局似乎在调试和非调试版本之间发生了变化。
  • 我不知道这是否是真正的罪魁祸首,但在 boost/xpressive/detail/core/regex_impl.hpp 我看到 struct regex_impl 有一个整数字段 static int instances#ifdef BOOST_XPRESSIVE_DEBUG_CYCLE_TEST.
【解决方案2】:

我使用这些偏移量来检查内存中的数据。这些值没有意义: 例如,__data.__lock 字段(一个 int)是 0xb086b580。 __count(一个无符号 > int)是 0x6078af00,__owner(一个 int)是 0x6078af00。

这听起来像是代码的不同部分对各种结构的大小有不同的看法。需要检查的一些事项:

  • 是否有任何#define 扩大了数据结构,但在整个代码库中设置不一致? (在 Windows 上,_SECURE_SCL 因此类错误而臭名昭著)
  • 你们做结构包装吗?如果您在标头中的任何位置设置 #pragma pack 并忘记在标头末尾取消设置,则此后包含的任何数据结构都将具有与程序中其他位置不同的布局。

【讨论】:

  • 没有编译指示包等。顺便说一句,由于锁(我怀疑是静态文件范围)在 boost 代码中,我假设我的代码不会做任何事情来重新排列这个锁
  • 原来是这个问题,但是在 boost 的代码中,不是我的。
猜你喜欢
  • 2010-11-09
  • 2017-11-21
  • 1970-01-01
  • 2017-08-18
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多