Clang未能检测到未定义的行为

时间:2017-10-08 12:59:03

标签: c++ undefined-behavior clang++

如何在下面的示例中检测未定义的行为?

var todoApp = (function(){

    var todo = [];

    //cacheDOM
    var $el = $('#app');
    var $input = $el.find('input');
    var $button = $el.find('button');
    var $ul = $el.find('ul');
    var listItem = $el.find('#todo-item').html();
    var $del = $el.find('.del')

    // bindEvents
    $button.on('click', addTodo);
    $ul.on('click', '.del', deleteTodo);
    $ul.on('mouseenter mouseleave', '.del', hoverChange);
    //render call

    render();

    //function declarations

    function onHoverChange(e){
        var $elem = $(e.target).closest('li');
        $elem.toggleClass('delete');
    }
    function addTodo(e){
        var $elem = $(e.target).closest('li');
        todo.push($input.val());
        $input.val('');
        render();
    }
    function deleteTodo(e){
        var $elem = $(e.target).closest('li');
        var $rem = $ul.find('li').index($elem);
        todo.splice($rem, 1);
        render();
    }
    function render(){
        var data = {
            todo: todo
        }
        $ul.html(Mustache.to_html(listItem, data));
    }

})();

使用#include <iostream> #include <stream> int main() { std::cout << "Undefined: " << std::string().front() << std::endl; return 0; } 编译。

我在编译时或运行时的预期输出都是错误的。根据{{​​3}},对空字符串调用clang++ -fsanitize=address,undefined -g -Wall -Wextra main.cc是未定义的行为。 实际输出为front()

问题

  1. 我可以在编译或运行时产生错误吗?如果没有,为什么编译器不能检测到这个?
  2. 如果没有,是否有任何工具可以检测到这一点?例如,静态分析。
  3. 使用的版本:

    Undefined:

    相关的相关问题:

    • cplusplus.com(但我对这种特定的未定义行为感兴趣。)

2 个答案:

答案 0 :(得分:1)

将Baum mit Augen的链接转换为答案

使用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

答案 1 :(得分:1)

使用标准容器并不总是可以进行编译时警告,但实现自由函数将允许额外的检查,可以选择使用编译器标志关闭。

#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;
}