有关涉及字符串类的核心转储问题的帮助
我正在执行代码审查,以解决很少发生的实时环境问题。它在调试环境中不可重现,因此唯一的调查方法是从实时环境中通过代码分析进行核心转储。以下是情况摘要:
核心转储:
(gdb) bt
#0 in strlen () from /lib/libc.so.6
#1 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string$base () from libstdc++.so.6
#2 in CustomStr::CustomStr()
代码在 Std::String 类上有一个包装类,类似于:
class CustomStr: public string
{
//Some custom members here
};
This custom class has constructors:
CustomStr::CustomStr(const char *str):string(str)
{
//Some derived class inits
}
CustomStr::CustomStr(const CustomStr& str) : string(str.c_str())
{
//Some derived class inits
}
我认为这两个构造函数都有问题,如果传递指向 NULL 的指针,则相同的指针将传递给 String 构造函数,并且当它内部调用 strlen() 来确定未定义行为 (UB) 发生的长度。 我认为正确的实现方法是在调用字符串构造函数之前检查 NULL,例如:
CustomStr::CustomStr(const char *str)
{
if(str!= NULL)
string(str);
//Some derived class inits
}
CustomStr::CustomStr(const CustomStr& str)
{
if(str!= NULL)
string(str.c_str());
//Some derived class inits
}
我的问题是:
- 问题(我认为是)和建议的解决方案似乎是有效的案例吗?
- 字符串构造函数是否检查 NULL?我认为应该是因为它在内部调用 strlen() ,它将在 NULL 上显示 UB 。
- 除了 NULL 检查之外,如何检查是否传递了有效的 const char* ?(NOn NULL 终止 const char* 等)
I am performing a code review for resolving a rarely occuring live enviornment problem. It is not reproducible in debug enviornments and hence the only means of investigation is the core dump from live enviornment and through code analysis. Here is the summary of the situation:
The core dump:
(gdb) bt
#0 in strlen () from /lib/libc.so.6
#1 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string$base () from libstdc++.so.6
#2 in CustomStr::CustomStr()
The code has a wrapper class over the Std::String class, something like:
class CustomStr: public string
{
//Some custom members here
};
This custom class has constructors:
CustomStr::CustomStr(const char *str):string(str)
{
//Some derived class inits
}
CustomStr::CustomStr(const CustomStr& str) : string(str.c_str())
{
//Some derived class inits
}
I think both these constructors have a problem, if a pointer to NULL is passed on, the same will be passed to String constructor and when it internally calls strlen() to determine the length a Undefined Behavior(UB) will occur.
I think the correct way to implement will be to check for a NULL before calling the string constructor like:
CustomStr::CustomStr(const char *str)
{
if(str!= NULL)
string(str);
//Some derived class inits
}
CustomStr::CustomStr(const CustomStr& str)
{
if(str!= NULL)
string(str.c_str());
//Some derived class inits
}
The Questions I have are:
- Do the problem(which i think is) and the proposed solution seem a valid case?
- Does string constructor check for NULL? I think It should because internally it calls strlen() which will show UB on NULL.
- Apart from the NULL check How can one check if a valid const char* is being passed?(NOn NULL terminated const char* etc)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
const char* 的构造函数不检查空指针,由调用者检查是否需要。您必须知道参数是否可能为空。
另一个构造函数可以使用字符串的复制构造函数,而不是将 c_str() 传递给它。它既可以让您免于重新计算长度,也可以用于空字符串。
The constructor from a const char* does not check for a null pointer, it is up to the caller to check if needed. YOU must know if it is possible or not for the argment to be null.
The other constructor could use string's copy constructor, instead of passing c_str() to it. It both saves you from recalculation the length, and also works for an empty string.
C++ 标准要求传递给 std::string(const char*) 的指针不能是空指针(c++0x 草案 n3092 中的第 21.4.2 节)。因此字符串类本身不会检查该条件,并且传入 null 意味着您的代码不符合要求。
您修复的
CustomStr(const char*)
看起来不错,但CustomStr(const std::string&)
的修复则不然。引用不能为空。 (如果编译成功的话,我会感到惊讶。)现在有方法可以检查随机
char*
是否是“有效”(除了空检查之外)。The C++ standard requires that the pointer passed to
std::string(const char*)
not be a null pointer (§21.4.2 in c++0x draft n3092). So the string class itself will not check for that condition, and passing in a null means your code is not conforming.You fix for the
CustomStr(const char*)
looks ok, but the one forCustomStr(const std::string&)
is not. A reference cannot be null. (I'd be surprised if that compiled at all.)There is now way to check if a random
char*
is a "valid" except for the null check.对核心转储的进一步调查应该可以让您非常准确地了解导致崩溃的原因。特别是,到底抛出了什么异常?如果是访问冲突(又名段错误),那么转储还应该准确地告诉您正在访问哪个错误地址,这反过来又会告诉您问题是从 NULL 指针读取还是其他问题。
当然,指向 std::string 构造函数的 NULL 指针可能是您的问题,但您不应该仅仅假设 -- 核心转储的目的是消除此类猜测调试。
无论如何,是的,如果您从 NULL 指针构造它,
std::string
就会崩溃,因此您应该在将任何指针传递到字符串构造函数之前对它们进行 NULL 检查。 例如,将是一种简单的解决方法。
Further investigation of the core dump should give you a pretty exact picture of what's caused the crash. In particular, exactly what exception is being thrown? If it's an access violation (aka segfault), then the dump should also tell you precisely what faulty address is being accessed, which in turn will tell you whether your problem is a read from NULL pointer or something else.
It's certainly likely that a NULL pointer to the
std::string
consturctor could be your problem, but you shouldn't just assume that -- the purpose of a core dump is to take the guesswork out of such debugging.In any case, yes,
std::string
just blows up if you construct it from a NULL pointer, and so you ought to NULL-check any pointers before you pass them into the string constructor. eg,would be one simple workaround.
std::string(const char*) 的参数应该是指向 \0 终止字符串的指针。 NULL 不指向任何东西,当然也不是以 null 结尾的字符串。因此,传递 NULL 是违反前提条件的。
调试版本应该断言指针不为 NULL,因为
std::string
是一个将由新手使用的类。不应在运行时检查它,因为无论如何都没有有效的程序传递 NULL。与 C++ 中通常的情况一样,无法测试指针是否“有效”。如果强制采用一种机制来回答这个问题,C++ 将会带来严重的性能损失。
The argument to std::string(const char*) should be a pointer to a \0-terminated string. NULL doesn't point to anything, and certainly not a null-terminated string. Therefore, it's a precondition violation to pass NULL.
A debug build should assert that the pointer isn't NULL, because
std::string
is a class that will be used by novices. It should not be checked at runtime, as no valid program passes NULL anyway.As usual in C++, there's no way to test whether a pointer is "valid". C++ would incur significant performance penalties if a mechanism would be mandatory that could answer that question.
您不应该从标准库类派生,它们没有虚拟析构函数,它们并不意味着是基类。
也许这不是您遇到的问题,但知道这一点是件好事。不要这样做。
您可以将 std::string 作为包装类的组合。或者,正如我发现的那样,对于 std::string 类根本不使用任何包装器,这会导致更多问题而不是解决一些问题。
如果您需要一些特定的功能,例如“trim”等,您可以使用一些外部函数。
很高兴知道在 boost 库中存在很多字符串操作函数。
You should not derive from a standard library class, they have no virtual destructor, they are not meant to be base classes.
Maybe it's not the problem you have, but it's good to known. Don't do it.
You can have a std::string as a composition from your wrapper class. Or, as I have found, not use any wrapper at all for std::string class that leads to more problems rather than solving some.
You can maybe use some external functions if you need some specific features like "trim" etc..
It's good to known that in the boost library a lot of string manipulation function exist.