【问题标题】:Heap overflow inside custom sort function自定义排序函数中的堆溢出
【发布时间】:2018-10-10 16:38:58
【问题描述】:

您好,我在处理对整数数组进行 lex 排序的简单程序时遇到了困难

(此处为完整程序:https://pastebin.com/UMqEP62n

在足够大的整数向量上运行排序会导致随机数出现在数组中,然后取决于导致段错误的数据。

sort(nums.begin(), nums.end(), lex_compare);

比较函数:

bool lex_compare(const int &a, const int &b) {
    int ap = a, bp = b;
    vector<int> da, db;

    if (ap == 0) da.insert(da.begin(), ap%10);
    while (ap > 0) {
        da.insert(da.begin(), ap%10);
        ap /= 10;
    }
    if (bp == 0) db.insert(db.begin(), bp%10);
    while (bp > 0) {
        db.insert(db.begin(), bp%10);
        bp /= 10;
    }
    size_t size;
    if (da.size() < db.size()) {
        size = da.size();
    } else {
        size = db.size();
    }

    for (size_t i = 0; i < size; ++i)
        if (da[i] > db[i])
            return true;
        else if (da[i] < db[i])
            return false;
        else
            continue;

    if (da.size() > db.size())
        return false;
    else
        return true;
}

基本上,当数组太长时,由于堆缓冲区溢出,内存损坏就会出现。使用地址消毒器编译时显示:

==4097==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6140000001d0 at pc 0x00010aa396fe bp 0x7ffee51c5c50 sp 0x7ffee51c5c48
READ of size 4 at 0x6140000001d0 thread T0
#0 0x10aa396fd in lex_compare(int const&, int const&) main.cpp:8  

这实际上是 lex_compare 函数的第一行:

int ap = a, bp = b;

我无法找出导致这种行为的错误类型?是因为比较功能的大小吗?还是我有一些明显的内存读取错误?我使用 clang 4.2.1,但其他平台也会导致相同的行为,所以我认为排序功能存在根本性问题。

【问题讨论】:

  • 代表为 375,此时您应该知道不应使用“pastebin”链接。
  • + 用于重现此“堆缓冲区溢出”的输入丢失。
  • 为什么有这么多复杂的代码而不是 return std::to_string(a) &lt; std::to_string(b); ?并通过 const 引用传递 int 只是为了在第一行制作本地副本...
  • 这也可能被证明是有用的。 stackoverflow.com/questions/18291620/…
  • 根据我之前的经验,“比较器堆溢出”错误中的可能问题几乎总是比较器代码中的错误。比较器中不正确或遗漏的条件会导致重复调用比较器以对数组进行排序,但该数组永远不会完成,从而导致内存泄漏。

标签: c++ sorting


【解决方案1】:

您的问题是您违反了传递给std::sort 的比较函数必须遵循的compare requirement

比较要求要求 If comp(a,b)==true then comp(b,a)==false 但您的比较函数不这样做。例如,如果 a = 0b = 0comp(a, b) 会将您带到

if (da.size() > db.size())
    return false;
else
    return true;

你比较功能的一部分。由于大小相等,它返回true。当我们翻转它并评估 comp(b, a) 时,我们会到达同一个块,并会再次返回 true

a == b 时你需要返回false 而你不这样做。

【讨论】:

  • 感谢我不知道的帮助!
  • @Mazeryt 为了确认给出的答案,如果您在 Visual Studio 中运行 pastebin 链接中的代码,您会收到一个断言错误,即比较函数无效。 NathanOliver 提到的关于翻转值并再次进行测试的测试正是 Visual C++ 调试运行时所做的,以验证您没有虚假的比较函数。
  • @PaulMcKenzie 这个功能有名字吗?我不是在 VS 中运行,而只是使用 clang,所以很好奇 clang 是否也能捕捉到这个?
  • @Mazeryt 它是 MSVC 标准库实现的调试版本的一部分。他们添加了很多这样的“实用程序”来帮助编码人员在调试构建中更快地发现问题。我不确定 gcc 或 clang 是否会这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
  • 1970-01-01
  • 2020-08-20
  • 2011-01-13
  • 1970-01-01
  • 2021-08-04
相关资源
最近更新 更多