首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么促进分裂导致双重的自由或腐败问题?

为什么促进分裂导致双重的自由或腐败问题?
EN

Stack Overflow用户
提问于 2022-03-21 03:16:30
回答 1查看 160关注 0票数 1

我用C++开发了一个web服务器,这里有一个函数,它导致了一个核心问题,但我不知道为什么。

代码语言:javascript
复制
bool MyClass::hasFamilyAdminPermission(uint32_t uid) {
    ReadMutex mutex(&m_mtx); // this is read lock to lock m_familyOwner and m_familyAdmins
    if (uid == m_familyOwner) {
        return true;
    }
    std::vector<std::string> fields;
    boost::split(fields, m_familyAdmins, boost::is_any_of(","));
    std::string uidStr = boost::lexical_cast<string>(uid);
    for (std::vector<std::string>::iterator itor = fields.begin(); itor != fields.end(); ++itor) {
        if (uidStr == *itor) {
            return true;
        }
    }
    return false;
}

在执行gdb ./myServer coredump_file之后,我得到了如下输出:

代码语言:javascript
复制
warning: Unexpected size of section `.reg-xstate/8717' in core file.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./myServer'.
Program terminated with signal SIGABRT, Aborted.

warning: Unexpected size of section `.reg-xstate/8717' in core file.
#0  0x00007f627b2c5428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[Current thread is 1 (Thread 0x7f62277fe700 (LWP 8717))]
(gdb) where
#0  0x00007f627b2c5428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007f627b2c702a in __GI_abort () at abort.c:89
#2  0x00007f627b3077ea in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7f627b420ed8 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f627b31037a in malloc_printerr (ar_ptr=<optimized out>, ptr=<optimized out>,
    str=0x7f627b420fa0 "double free or corruption (fasttop)", action=3) at malloc.c:5006
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3867
#5  0x00007f627b31453c in __GI___libc_free (mem=<optimized out>) at malloc.c:2968
#6  0x00007f627be650b4 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x000000000046acc1 in boost::as_literal<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (r=...)
    at /usr/local/include/boost/range/as_literal.hpp:102
#8  boost::algorithm::iter_split<std::vector<std::string, std::allocator<std::string> >, std::string, boost::algorithm::detail::token_finderF<boost::algorithm::detail::is_any_ofF<char> > > (Result=..., Input="604679400,1430691907,2792989999",
    Finder=<error reading variable: DWARF-2 expression error: DW_OP_reg operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>) at /usr/local/include/boost/algorithm/string/iter_find.hpp:153
#9  0x0000000000464c17 in boost::algorithm::split<std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::string, boost::algorithm::detail::is_any_ofF<char> > (eCompress=<optimized out>, Pred=..., Input=..., Result=...) at /usr/local/include/boost/algorithm/string/split.hpp:149
#10 server::myServer::MyClass::hasFamilyAdminPermission (this=0x7f621c066dd0, uid=<optimized out>) at MyClass.cpp:202
#11 0x0000000000435678 in server::myServer::ServerAPI::onSetMicDataReq (this=0x7fff6da7e750, uid=1430691907, req=0x7f621c094200)
    at ServerAPI.cpp:2291

因此,似乎是boost::split引起了核团。

在gdb中,我所做的如下:

代码语言:javascript
复制
(gdb) frame 10
#10 server::myServer::MyClass::hasFamilyAdminPermission (this=0x7f621c066dd0, uid=<optimized out>) at MyClass.cpp:202
202     MyClass.cpp: No such file or directory.
(gdb) print fields
$1 = std::vector of length 0, capacity 0

现在,fields是一个空向量。

代码语言:javascript
复制
(gdb) frame 8
#8  boost::algorithm::iter_split<std::vector<std::string, std::allocator<std::string> >, std::string, boost::algorithm::detail::token_finderF<boost::algorithm::detail::is_any_ofF<char> > > (Result=..., Input="604679400,1430691907,2792989999",
    Finder=<error reading variable: DWARF-2 expression error: DW_OP_reg operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>) at /usr/local/include/boost/algorithm/string/iter_find.hpp:153
153     /usr/local/include/boost/algorithm/string/iter_find.hpp: No such file or directory.

在这里,输入是"604679400,1430691907,2792989999",它看起来很好。

然而,当我执行info loclas (我仍然在框架8)时,我遇到了一个分段错误。

代码语言:javascript
复制
(gdb) info locals
Tmp = std::vector of length 1891892, capacity 1891893 = {<error reading variable Tmp (Cannot access memory at address 0x0)>
itBegin = {<boost::iterator_adaptor<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::use_default, boost::use_default>, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::use_default, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::use_default>> = {<boost::iterator_facade<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::use_default, boost::use_default>, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::forward_traversal_tag, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long>> = {<No data fields>},
    m_iterator = {<boost::iterator_facade<boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const, boost::forward_traversal_tag, boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, long>> = {<No data fields>}, <boost::algorithm::detail::find_iterator_base<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
        m_Finder = {<boost::function_base> = {vtable = 0x89bd9dd2, functor = {obj_ptr = 0x7f627b31453c <__GI___libc_free+76>, type = {
                type = 0x7f627b31453c <__GI___libc_free+76>, const_qualified = false, volatile_qualified = false},
              func_ptr = 0x7f627b31453c <__GI___libc_free+76>, bound_memfunc_ptr = {
                memfunc_ptr = (void (boost::detail::function::X::*)(boost::detail::function::X * const,
    int)) 0x7f627b31453c <__GI___libc_free+76>, obj_ptr = 0xe8436c057b9e1300}, obj_ref = {obj_ptr = 0x7f627b31453c <__GI___libc_free+76>,
                is_const_qualified = false, is_volatile_qualified = false},
              data = 60 '<'}}, <std::binary_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>},
/usr/bin/sudo: line 11: 75240 Segmentation fault      (core dumped) ${SUDO} $@

我不知道是什么导致了核心,我也不知道为什么我会在执行info locals后出现分割错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-22 00:06:44

所以,boost::split不会崩溃。你在其他地方有未定义行为

无论如何,为什么您一直在通过字符串进行解析、分配字符串向量、与临时字符串等进行比较?你可以在整数域上这样做。

四个镜头。从一个简单的骨架开始:

代码语言:javascript
复制
#include <shared_mutex>
#include <string>

struct MyClass1 {
    MyClass1(uint32_t owner, std::string admins)
        : m_familyOwner(owner)
        , m_familyAdmins(std::move(admins)) {}

    bool hasFamilyAdminPermission(uint32_t uid) const;

  private:
    mutable std::shared_mutex m_mtx; // guards m_familyOwner and m_familyAdmins
    uint32_t                  m_familyOwner;
    std::string               m_familyAdmins;
};

1.比较Ints,没有拨款

我将使用助推精神X3:

代码语言:javascript
复制
#include <boost/spirit/home/x3.hpp>
bool MyClass1::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    if (uid == m_familyOwner)
        return true;

    bool matched = false;
    auto element = boost::spirit::x3::uint32;
    auto check   = [uid, &matched](auto& ctx) {
        if (_attr(ctx) == uid) {
            matched    = true;
            _pass(ctx) = false; // short circuit for perf
        }
    };

    parse(begin(m_familyAdmins), end(m_familyAdmins), element[check] % ',');
    return matched;
}

这仍然做了相当多的工作在锁下,但肯定从来没有分配。此外,它还可以提前退出,如果所有者的集合可能非常大,这会有所帮助。

2.比较案文,但不作分配

使用漂亮的正则表达式,您可以将数字匹配为常量字符串(或string视图)上的文本。这里的开销是正则表达式的分配。但可以说,这要简单得多:

代码语言:javascript
复制
#include <regex>
bool MyClass2::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    if (uid == m_familyOwner)
        return true;

    return regex_search(m_familyAdmins, std::regex("(^|,)" + std::to_string(uid) + "(,|$)"));
}

3.在建筑处分析一次

我们为什么要处理短信?我们可以把管理员安排在一组:

代码语言:javascript
复制
#include <set>
struct MyClass3 {
    MyClass3(uint32_t owner, std::string_view admins) : m_familyOwner(owner) {
        parse(admins.begin(), end(admins), boost::spirit::x3::uint32 % ',', m_familyAdmins);
    }
    bool hasFamilyAdminPermission(uint32_t uid) const;

  private:
    mutable std::shared_mutex m_mtx; // guards m_familyOwner and m_familyAdmins
    uint32_t                  m_familyOwner;
    std::set<uint32_t>        m_familyAdmins;
};

bool MyClass3::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    return uid == m_familyOwner || m_familyAdmins.contains(uid);
}

这就更简单了但是,set中存在一些可以优化的开销。

4.分析一次,无分配,速度

std::set有正确的语义。但是,对于小集合来说,遗憾的是没有引用的局部性,以及相对较高的节点分配开销。我们可以将其替换为:

代码语言:javascript
复制
boost::container::flat_set< //
    uint32_t,               //
    std::less<>,            //
    boost::container::small_vector<uint32_t, 10>>
    m_familyAdmins;

这使得设置<= 10元素根本不分配,并且查找从连续存储中获益。但是,按照这种速度--除非您想处理重复的条目--您可能会保持线性搜索和存储:

代码语言:javascript
复制
boost::container::small_vector<uint32_t, 10>
    m_familyAdmins;

联合演示

显示所有微妙的边缘情况。请注意,仅使用X3解析器

  • 对逗号分隔的字符串执行输入验证将非常容易。
  • 将很容易可靠地比较不同格式的uid编号。

我偷偷地输入了一个数字,它的前导为0 (089而不是89),这只是为了用std::regex方法来突出这个问题。注意,您的原始代码也有相同的问题。

住在Coliru/编译器资源管理器

代码语言:javascript
复制
#include <shared_mutex>
#include <string>

struct MyClass1 {
    MyClass1(uint32_t owner, std::string admins)
        : m_familyOwner(owner)
        , m_familyAdmins(std::move(admins)) {}

    bool hasFamilyAdminPermission(uint32_t uid) const;

    private:
    mutable std::shared_mutex m_mtx; // guards m_familyOwner and m_familyAdmins
    uint32_t                  m_familyOwner;
    std::string               m_familyAdmins;
};

#include <boost/spirit/home/x3.hpp>
bool MyClass1::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    if (uid == m_familyOwner)
        return true;

    bool matched = false;
    auto element = boost::spirit::x3::uint32;
    auto check   = [uid, &matched](auto& ctx) {
        if (_attr(ctx) == uid) {
            matched    = true;
            _pass(ctx) = false; // short circuit for perf
        }
    };

    parse(begin(m_familyAdmins), end(m_familyAdmins), element[check] % ',');
    return matched;
}

struct MyClass2 {
    MyClass2(uint32_t owner, std::string admins)
        : m_familyOwner(owner)
        , m_familyAdmins(std::move(admins)) {}
    bool hasFamilyAdminPermission(uint32_t uid) const;

    private:
    mutable std::shared_mutex m_mtx; // guards m_familyOwner and m_familyAdmins
    uint32_t                  m_familyOwner;
    std::string               m_familyAdmins;
};

#include <regex>
bool MyClass2::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    if (uid == m_familyOwner)
        return true;

    return std::regex_search(m_familyAdmins, std::regex("(^|,)" + std::to_string(uid) + "(,|$)"));
}

#include <set>
struct MyClass3 {
    MyClass3(uint32_t owner, std::string_view admins) : m_familyOwner(owner) {
        parse(admins.begin(), end(admins), boost::spirit::x3::uint32 % ',', m_familyAdmins);
    }
    bool hasFamilyAdminPermission(uint32_t uid) const;

    private:
    mutable std::shared_mutex m_mtx; // guards m_familyOwner and m_familyAdmins
    uint32_t                  m_familyOwner;
    std::set<uint32_t>        m_familyAdmins;
};

bool MyClass3::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    return uid == m_familyOwner || m_familyAdmins.contains(uid);
}

#include <boost/container/flat_set.hpp>
#include <boost/container/small_vector.hpp>
struct MyClass4 {
    MyClass4(uint32_t owner, std::string_view admins) : m_familyOwner(owner) {
        parse(admins.begin(), end(admins), boost::spirit::x3::uint32 % ',', m_familyAdmins);
    }
    bool hasFamilyAdminPermission(uint32_t uid) const;

    private:
    mutable std::shared_mutex m_mtx; // guards m_familyOwner and m_familyAdmins
    uint32_t                  m_familyOwner;
#ifdef LINEAR_SEARCH
    // likely faster with small sets, anyways
    boost::container::small_vector<uint32_t, 10> m_familyAdmins;
#else
    boost::container::flat_set< //
        uint32_t,               //
        std::less<>,            //
        boost::container::small_vector<uint32_t, 10>>
            m_familyAdmins;
#endif
};

bool MyClass4::hasFamilyAdminPermission(uint32_t uid) const {
    std::shared_lock mutex(m_mtx);
    return uid == m_familyOwner ||
#ifndef LINEAR_SEARCH
        std::find(begin(m_familyAdmins), end(m_familyAdmins), uid) != end(m_familyAdmins);
#else
    m_familyAdmins.contains(uid);
#endif
}

#include <iostream>
int main() {
    MyClass1 const mc1{42, "21,377,34,233,55,089,144"};
    MyClass2 const mc2{42, "21,377,34,233,55,089,144"};
    MyClass3 const mc3{42, "21,377,34,233,55,089,144"};
    MyClass4 const mc4{42, "21,377,34,233,55,089,144"};

    std::cout << "uid\tdynamic\tregex\tset\tflat_set\n"
        << "\t(x3)\t-\t(x3)\t(x3)\n"
        << std::string(5 * 8, '-') << "\n";

    auto compare = [&](uint32_t uid) {
        std::cout << uid << "\t" << std::boolalpha
            << mc1.hasFamilyAdminPermission(uid) << "\t"
            << mc2.hasFamilyAdminPermission(uid) << "\t"
            << mc3.hasFamilyAdminPermission(uid) << "\t"
            << mc4.hasFamilyAdminPermission(uid) << "\n";
    };

    compare(42);
    // https://en.wikipedia.org/wiki/Fibonacci_number
    for (auto i = 3, j = 5; i < 800; std::tie(i, j) = std::tuple{j, i + j}) {
        compare(i);
    }
}

打印

代码语言:javascript
复制
id      dynamic regex   set     flat_set
        (x3)    -       (x3)    (x3)
----------------------------------------
42      true    true    true    true
3       false   false   false   false
5       false   false   false   false
8       false   false   false   false
13      false   false   false   false
21      true    true    true    true
34      true    true    true    true
55      true    true    true    true
89      true    false   true    true
144     true    true    true    true
233     true    true    true    true
377     true    true    true    true
610     false   false   false   false
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71552464

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档