【问题标题】:Valgrind complains on string.append(string)Valgrind 抱怨 string.append(string)
【发布时间】:2012-04-12 05:47:57
【问题描述】:

我正在尝试将一个字符串附加到另一个字符串。我声明了两个全局字符串变量 -

string grid_filename = "grids/";
string rest;

然后我有一个获取命令行参数的函数。每当用户在命令行参数中输入文件名时,它应该存储在 rest 中,然后将 rest 附加到 grid_filename。

else if(strcmp(temp.substr(0,16).c_str(), "--grid-filename=") == 0) {
    rest = temp.substr(16,strlen(temp.c_str())-16);
    grid_filename.append(rest);   //line 74!
}

现在每当我运行我的代码时,valgrind 都会给我这个错误 -

==5602==  Address 0x45fdc30 is 0 bytes after a block of size 32 alloc'd
==5602==    at 0x402641D: operator new(unsigned int) (vg_replace_malloc.c:255)
==5602==    by 0x43039F7: std::string::_Rep::_S_create(unsigned int, unsigned int,     std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.14)
==5602==    by 0x4304C77: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.14)
==5602==    by 0x4304DA6: std::string::reserve(unsigned int) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.14)
==5602==    by 0x43053E9: std::string::append(std::string const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.14)
==5602==    by 0x804D5AE: get_command_line_args(int, char**) (main.cpp:74)
==5602==    by 0x804F138: main (main.cpp:244)

我打印出字符串的两个地址,但它们都不匹配 valgrind 所说的 0 字节。我在这里错过了什么?

我相信这会导致我的第二个错误,因为我将 grid_filename 传递给另一个通过 tcp 连接发送字符串的函数。 Valgrind 告诉我

==5660== Syscall param socketcall.send(msg) points to unaddressable byte(s)
==5660==    at 0x404A9B1: send (socket.S:64)
==5660==    by 0x804F7C8: main (main.cpp:364)

谁能给我解释一下问题是什么?任何帮助,将不胜感激。如果需要,我可以提供有关代码的更多信息。

【问题讨论】:

  • 您给出的第一条错误信息不完整。真正的错误消息必须在您粘贴的文本的正上方,关于读取或写入 0x45fdc30 的内容。然后,valgrind 打印您粘贴的消息,它会告诉您有关该地址的一些信息。
  • 我发布的第二条错误消息出现在我发布的第一条消息的正上方。我认为它们是分开的,所以我分别写了它们。整个消息应该以“Syscall param socketcall.send(msg) points to unaddressable byte(s)”开头,然后是“Address 0x45fdc30 is 0 bytes after a block of size 32 alloc'd”消息。
  • 好的,所以我们需要查看您的发送调用,因为显然它传递了一个无效指针,该指针恰好指向 由 grid_filename.append( )。
  • 您知道std::string 提供== 用于比较,length() 提供长度吗?
  • 如果您提供一个完整简短程序来演示错误,我们将能够更有效地帮助您。删除所有对问题没有影响的内容,然后在您的问题中发布该 short 程序。请参阅:sscce.org

标签: c++ string append valgrind


【解决方案1】:

关于您的第一个错误:我们在 valgrind 中有误报。检查documentation 以抑制这些,特别是如果它们没有指向您的代码(并且您已经检查它们实际上不会导致问题)

【讨论】:

    【解决方案2】:

    注意:这不是回应,这不是代码审查网站……但我真的不能盯着这个就走开。

    首先,工具箱中的一些真正有用的功能:

    // Some free functions (because there are too many string types)
    inline char const* c_str(std::string const& s) { return s.c_str(); }
    inline size_t size(std::string const& s) { return s.size(); }
    
    inline char const* c_str(char const* s) { return s; }
    inline size_t size(char const* s) { return std::strlen(s); }
    
    template <size_t N>
    char const* c_str(char const (&s)[N]) { return s; }
    template <size_t N>
    size_t size(char const (&s)[N]) { return N - 1; }
    
    // A helper function (lowest common denominator)
    inline bool beginsWith(char const* big, size_t const bigSize,
                           char const* small, size_t const smallSize)
    {
      if (bigSize < smallSize) { return false; }
      return std::memcmp(big, small, smallSize) == 0;
    }
    
    // The actual function, doing the adaptation from the various forms of string
    template <typename T, typename U>
    bool beginsWith(T& big, U& small) {
        return beginsWith(c_str(big), size(big), c_str(small), size(small));
    }
    
    // same with endsWith
    

    然后您可以非常有效地重写代码(无需额外的内存分配)并且还具有更高的可读性:

    static std::string const GridFilenameOpt = "--grid-filename=";
    
    // ...
    else if (beginsWith(temp, GridFilenameOpt)) {
        grid_filename.append(temp, GridFilenameOpt.size(), std::string::npos);
    }
    

    这对实际问题没有多大帮助,因为您没有显示产生错误的代码。

    【讨论】:

    • 如果你想要beginsWith,为什么不直接bool beginsWith(string const &amp;a, string const &amp;b) { return a.compare(0, b.length(), b);}
    • @JerryCoffin:我不喜欢仅仅为了进行比较而创建一个虚假的临时string 的想法。问题是枚举 C++ 的 3 种字符串类型(std::stringchar const* 加上可优化的char const (&amp;)[N])的所有组合很无聊,所以我倾向于将它们的接口统一为最低公分母(实际上......在home 我使用一个类似于llvm::StringRef 的类来实现这个统一)。
    • 上述函数不应为比较创建任何新字符串。它只是使用compare 成员函数,它允许您指定比较的起点和长度。它只为string 编写,但一般来说泛化basic_string 是微不足道的。同时,使用memcmp 本身就很受限制...
    • @JerryCoffin: beginsWith(temp, "--grid-filename=") 但是会创建一个临时的。
    猜你喜欢
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多