4

我继承了一个大型 c++ 代码库,我的任务是避免代码库中可能发生的任何空指针异常。是否有可用的静态分析工具,我在想你已经成功使用的 lint。

你还注意什么?

4

6 回答 6

6

您可以从消除 NULL 的来源开始:

改变

if (error) {
    return NULL;
}

进入

if (error) {
    return DefaultObject; // Ex: an empty vector
}

如果返回默认对象不适用并且您的代码库已经使用异常,请执行

if (error) {
    throw BadThingHappenedException;
}

然后,在适当的地方添加处理。

如果您使用的是遗留代码,您可以制作一些包装函数/类:

ResultType *new_function() {
    ResultType *result = legacy_function();
    if (result) {
        return result;
    } else {
        throw BadThingHappenedException;
    }
}

新功能应该开始使用新功能并进行适当的异常处理。

我知道有些程序员就是不会遇到异常,包括像Joel这样的聪明人。但是,返回 NULL 最终发生的事情是,这个 NULL 会疯狂地传递,因为每个人都会认为处理它并默默返回不是他们的事。某些函数可能会返回错误代码,这很好,但调用者通常最终会返回另一个 NULL 以响应错误。然后,您会在每个函数中看到大量的 NULL 检查,无论该函数多么微不足道。而且,只需要一个不检查 NULL 来使程序崩溃的地方。异常迫使您仔细考虑错误并准确决定应该在哪里以及如何处理它。

似乎您只是在寻找简单的解决方案,例如静态分析工具(您应该始终使用)。更改指向引用的指针也是一个很好的解决方案。但是,C++ 具有 RAII 的优点,它消除了到处都有“try {} finally {}”的需要,所以我认为它值得你认真考虑。

于 2009-07-25T18:31:34.383 回答
2

如果您主要维护代码库,那么您可以做的最低工作量和最高回报之一就是开始将裸指针重构为引用计数指针

我还会看看像Purify这样的东西,它将检测你的代码以检测内存损坏。

于 2009-07-25T01:01:16.290 回答
2

首先,作为一个技术点,C++ 没有 NULL 指针异常。取消引用 NULL 指针具有未定义的行为,并且在大多数系统上会导致程序突然终止(“崩溃”)。

至于工具,我也推荐这个问题:

C++ 静态代码分析工具值得吗?

特别是关于 NULL 指针取消引用,请考虑 NULL 指针取消引用具有三个主要元素:

  1. 引入一个 NULL 指针。
  2. 该指针在程序中其他地方的流动。
  3. 该指针的取消引用。

静态分析工具的难点当然是第 2 步,而工具的区别在于它们可以准确(即,没有太多误报)跟踪的路径有多复杂。查看您想要捕获的一些特定错误示例可能会很有用,以便更好地建议哪种工具最有效。

免责声明:我为 Coverity 工作。

于 2009-07-28T01:57:13.420 回答
2

如果您不想更改任何代码,则必须使用一些工具(请参阅其他答案)。但是对于问题的一个特殊部分(在函数中放置一个指针来使用它)有一个很好的小 Makro-Definition 可以用来找到一些小错误:(在发布模式下没有时间开销并添加了一个可见的代码的条件)

    #ifdef  NDEBUG

    #define NotNull(X) X

    #else // in Debug-Mode

    template<typename T> class NotNull;

    template<typename T> // template specialization only for pointer-types
    class NotNull<T*> {
    public:
        NotNull(T* object)
        : _object(object) {
            assert(object);
        }

        operator T*() const {
            return _object;
        }

        T* operator->() const {
            return _object;
        }
    private:
        T *_object;
    };

    #define NotNull(X) NotNull<X>

    #endif // in Debug-Mode

您只需从此更改每个功能:

void increase(int* counter)  
{ .. } 

对此

void increase(NotNull(int*) counter)
{ .. }  

ps:首先在这里找到,可以进一步调整

于 2009-11-19T15:22:47.757 回答
1

这些可能是有趣的:

有哪些开源 C++ 静态分析工具可用?

Windows上的C++静态代码分析工具

C++ 静态代码分析工具值得吗?

我还会考虑使用动态运行时工具,例如Valgrind(免费)

于 2009-07-25T00:58:51.737 回答
1

一个附带问题,避免这些的目的是因为他们不希望客户看到崩溃吗?在许多情况下,空指针是应立即处理的意外情况,但它们常常像烫手山芋一样通过系统。

我曾经在一个代码库上工作,习惯是在进入函数时首先检查任何空指针,如果是,则返回。这样做的问题是,虽然该工具没有崩溃,但它最终默默地生成了坏数据。并且尝试调试这些问题很困难,因为在结果变得无法容忍或最终不得不表现出来之前,可能已经通过许多函数非法传递了很长时间的空指针。

理想情况下,您至少在开发期间需要正确的断言,因此请考虑使用宏来隐藏或重新定义生产构建的断言

于 2009-07-25T01:21:21.917 回答