Clang 未能检测到未定义的行为
Clang fails to detect undefined behavior
如何检测下面示例中的未定义行为?
#include <iostream>
#include <stream>
int main() {
std::cout << "Undefined: " << std::string().front() << std::endl;
return 0;
}
编译为 clang++ -fsanitize=address,undefined -g -Wall -Wextra main.cc
。
我在编译时或 运行 时的预期输出将是一个错误。根据 cplusplus.com,在空字符串上调用 front()
是未定义的行为。 实际输出是Undefined:
。
问题
- 我可以在编译时或 运行 时产生错误吗?如果不是,为什么编译器检测不到?
- 如果没有,有什么工具可以检测到吗?比如静态分析。
使用的版本:
$ clang++ --version
Apple LLVM version 9.0.0 (clang-900.0.37)
Target: x86_64-apple-darwin17.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
$ /usr/local/Cellar/gcc/7.2.0/bin/g++-7 --version
g++-7 (Homebrew GCC 7.2.0) 7.2.0
[Copyright Notice]
相关的相关问题:
- A C++ implementation that detects undefined behavior?(但我对这种特殊的未定义行为很感兴趣。)
将 Baum mit Augen 的 link 变成答案。
在使用 GCC 编译时添加标志 -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
。这同样不适用于 Clang。
这会在 std::basic_string
内启用运行时检查。
结果(为清楚起见添加了换行符):
$ /usr/local/Cellar/gcc/7.2.0/bin/g++-7 main.cc -g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
$ ./a.out
Undefined:
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.h:1077:
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::front()
[with _CharT = char; _Traits = std::char_traits<char>;
_Alloc = std::allocator<char>;
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference = char&]:
Assertion '!empty()' failed.
[1] 24143 abort ./a.out
标准容器并不总是可能出现编译时警告,但实现自由函数将允许进行额外的检查,可以选择使用编译器标志关闭这些检查。
#define NDEBUG
#include <iostream>
#include <string>
#include <cassert>
#include <stdexcept>
struct assert_on_failure
{
template<class ErrorMessage>
void check(bool condition, ErrorMessage&& msg) const
{
if (!condition)
assert(!msg);
}
};
struct throw_on_failure
{
template<class ErrorMessage>
void check(bool condition, ErrorMessage&& msg) const
{
if (!condition)
throw std::runtime_error(msg);
}
};
#ifdef NDEBUG
constexpr auto default_failure_policy = throw_on_failure{};
#else
constexpr auto default_failure_policy = assert_on_failure{};
#endif
template
<
class Container,
class FailurePolicy = std::add_lvalue_reference_t<decltype(default_failure_policy)>
>
decltype(auto) get_front(Container&& cont,
FailurePolicy&& policy = default_failure_policy)
{
policy.check(cont.size() > 0, "container is empty");
return cont.front();
}
int main() {
std::cout << "Undefined: " << get_front(std::string()) << std::endl;
return 0;
}
如何检测下面示例中的未定义行为?
#include <iostream>
#include <stream>
int main() {
std::cout << "Undefined: " << std::string().front() << std::endl;
return 0;
}
编译为 clang++ -fsanitize=address,undefined -g -Wall -Wextra main.cc
。
我在编译时或 运行 时的预期输出将是一个错误。根据 cplusplus.com,在空字符串上调用 front()
是未定义的行为。 实际输出是Undefined:
。
问题
- 我可以在编译时或 运行 时产生错误吗?如果不是,为什么编译器检测不到?
- 如果没有,有什么工具可以检测到吗?比如静态分析。
使用的版本:
$ clang++ --version
Apple LLVM version 9.0.0 (clang-900.0.37)
Target: x86_64-apple-darwin17.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
$ /usr/local/Cellar/gcc/7.2.0/bin/g++-7 --version
g++-7 (Homebrew GCC 7.2.0) 7.2.0
[Copyright Notice]
相关的相关问题:
- A C++ implementation that detects undefined behavior?(但我对这种特殊的未定义行为很感兴趣。)
将 Baum mit Augen 的 link 变成答案。
在使用 GCC 编译时添加标志 -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
。这同样不适用于 Clang。
这会在 std::basic_string
内启用运行时检查。
结果(为清楚起见添加了换行符):
$ /usr/local/Cellar/gcc/7.2.0/bin/g++-7 main.cc -g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
$ ./a.out
Undefined:
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.h:1077:
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::front()
[with _CharT = char; _Traits = std::char_traits<char>;
_Alloc = std::allocator<char>;
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference = char&]:
Assertion '!empty()' failed.
[1] 24143 abort ./a.out
标准容器并不总是可能出现编译时警告,但实现自由函数将允许进行额外的检查,可以选择使用编译器标志关闭这些检查。
#define NDEBUG
#include <iostream>
#include <string>
#include <cassert>
#include <stdexcept>
struct assert_on_failure
{
template<class ErrorMessage>
void check(bool condition, ErrorMessage&& msg) const
{
if (!condition)
assert(!msg);
}
};
struct throw_on_failure
{
template<class ErrorMessage>
void check(bool condition, ErrorMessage&& msg) const
{
if (!condition)
throw std::runtime_error(msg);
}
};
#ifdef NDEBUG
constexpr auto default_failure_policy = throw_on_failure{};
#else
constexpr auto default_failure_policy = assert_on_failure{};
#endif
template
<
class Container,
class FailurePolicy = std::add_lvalue_reference_t<decltype(default_failure_policy)>
>
decltype(auto) get_front(Container&& cont,
FailurePolicy&& policy = default_failure_policy)
{
policy.check(cont.size() > 0, "container is empty");
return cont.front();
}
int main() {
std::cout << "Undefined: " << get_front(std::string()) << std::endl;
return 0;
}