How to raise warning if return value is disregarded?

后端 未结 8 934
北海茫月
北海茫月 2020-11-27 03:35

I\'d like to see all the places in my code (C++) which disregard return value of a function. How can I do it - with gcc or static code analysis tool?

Bad code exampl

相关标签:
8条回答
  • 2020-11-27 03:48

    A static analyzer will be your best bet here. We use Coverity here, but there are free tools available that you can use as well.

    If you need a quick-and-dirty solution and you have a Linux-style shell handy, you can try something like:

    grep -rn "function_name" * | grep -v "="
    

    That will find every line that references the specified function but does not contain an "=". You can get a lot of false positives (and potentially some false negatives) but if you don't have a static analyzer it's a decent place to start.

    0 讨论(0)
  • 2020-11-27 03:50

    For C++17 the answer to this question changes since we now have the [[nodiscard]] attribute. Covered in [dcl.attr.nodiscard]:

    The attribute-token nodiscard may be applied to the declarator-id in a function declaration or to the declaration of a class or enumeration. It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present.

    and

    [ Example:

    struct [[nodiscard]] error_info { /* ... */ };
    error_info enable_missile_safety_mode();
    void launch_missiles();
    void test_missiles() {
      enable_missile_safety_mode(); // warning encouraged
      launch_missiles();
    }
    error_info &foo();
    void f() { foo(); }             // warning not encouraged: not a nodiscard call, because neither
                                    // the (reference) return type nor the function is declared nodiscard
    

     — end example ]

    So modifying your example (see it live):

    [[nodiscard]] int f(int z) {
        return z + (z*2) + z/3 + z*z + 23;
    }
    
    
    int main()
    {
      int i = 7;
      f(i); // now we obtain a diagnostic
    
      return 1;
    }
    

    We now obtain a diagnostic with both gcc and clang e.g.

    warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
      f(i); // now we obtain a diagnostic
      ^ ~
    
    0 讨论(0)
  • 2020-11-27 03:53

    The classic 'lint' program used to be very voluble about functions that returned a value that was ignored. The trouble was, many of those warnings were unwanted - leading to excessive noise in the lint output (it was picking up bits of fluff that you wanted it to ignore). That's probably why GCC doesn't have a standard warning for it.

    The other issue - the flip side - is "how do you suppress the warning when you know you are ignoring the result but really don't care". The classic scenario for that is:

    if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
        signal(SIGHUP, sighandler);
    

    You care about the first result from signal(); you know that the second will be SIG_IGN (since you just set it to that). To get away from the warnings, I sometimes use some variant on:

    if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
        old = signal(SIGHUP, sighandler);
    

    This assigns to old both times. You can follow that with 'assert(old == SIG_IGN)'.

    0 讨论(0)
  • 2020-11-27 04:00

    a static analyzer will do the work for you, but if your code base is more then trivial prepare to be overwhelmed ;-)

    0 讨论(0)
  • 2020-11-27 04:02

    You want GCC's warn_unused_result attribute:

    #define WARN_UNUSED __attribute__((warn_unused_result))
    
    int WARN_UNUSED f(int z) {
        return z + (z*2) + z/3 + z*z + 23;
    }
    
    int main()
    {
      int i = 7;
      f(i); ///// <<----- here i disregard the return value
      return 1;
    }
    

    Trying to compile this code produces:

    $ gcc test.c
    test.c: In function `main':
    test.c:16: warning: ignoring return value of `f', declared with
    attribute warn_unused_result
    

    You can see this in use in the Linux kernel; they have a __must_check macro that does the same thing; looks like you need GCC 3.4 or greater for this to work. Then you will find that macro used in kernel header files:

    unsigned long __must_check copy_to_user(void __user *to,
                                            const void *from, unsigned long n);
    
    0 讨论(0)
  • 2020-11-27 04:02

    Any static analysis code (e.g. PC-Lint) should be able to tell you that. For PC-Lint, I know that this is the case.

    0 讨论(0)
提交回复
热议问题