0

I am iterating over my command line arguments and checking for matches with

if (!strncmp(argv[i], "-f", 3)) {}

Clang-Tidy warns me that the 3 is too large comparison length and might lead to a buffer overflow. In my understanding, that should be fine because I am comparing ['-','f','\0'] (that's 3 bytes) against whatever input I got. I specifically want to match only -f and not something like -foo (which would be ['-','f','o','o','\0']), therefor I deem it necessary to also compare that both strings are terminated at the same length (that's the way I learned in Uni). A comparison with just 2 bytes does not give this warning, the same works for another argument when comparing 5 (or 4 respectively) bytes. Having seen this warning on both arguments makes me believe the problem is with the string literal and not the passed argument, which could be shorter and would raise this warning in a way I could understand. The following example should reproduce this behavior:

#include <cstring>
int main(int argc, char** argv) {
    for (int i = 1; i < argc; ++i) {
        if (!strncmp(argv[i], "-f", 3)) {
        }
        if (!strncmp(argv[i], "-pre", 5)) {
        }
    }
}

Swapping the arguments of strncmp() does fix the warning, I however do not understand how this changes the logic of the code, as the result should just be the negative value of the original. Can someone more knowledgeable than me explain how this exactly this behavior comes to be? I could not find anything in the strncmp man-page that would reference something like this.

ZwergofPhoenix
  • 141
  • 1
  • 6
  • I think it is: https://clang.llvm.org/extra/clang-tidy/checks/bugprone/not-null-terminated-result.html It says " If the third argument is the first or the second argument’s `length + 1` it has to be truncated without the `+ 1` operation." In your case I don't think it is a problem, but what if you `const char minusf[2] = {'-', 'f'};` - then it would be a problem if you used that array instead of the literal `"-f"`. So I think the warning doesn't help you in this case. – Jerry Jeremiah Aug 30 '22 at 23:43
  • @JerryJeremiah That would then not compare the termination, right? And additionally, that should not be changed when swapping the first two arguments of `strncmp()`. I also should be guaranteed that both the literal and the argument are properly terminated, as far as I understand their behavior. – ZwergofPhoenix Aug 30 '22 at 23:56

1 Answers1

-1

The inputs to strncmp are possibly null terminated. So the logic to quit the search can't depend on hitting a null character, meaning it can run off the end of one of the inputs if you tell the function its longer than it actually is.

Taekahn
  • 1,592
  • 1
  • 13
  • 16
  • I believe I understand the logic you are describing, this however leaves the main question unanswered: How to match `-f` but not `-foo`, following your statement I could only check that a string starts with `-f` but could continue. Does comparing to `-f\0` work? Seems ugly and unnecessary, so how would someone prevent longer continuing strings to match? – ZwergofPhoenix Sep 04 '22 at 16:29
  • 1
    Well, my top shelf answer would be to use string_views. While it’s not good to rely on implementation details I believe the first thing it does is compare sizes, so even though you have to walk the string to create the string_view, you don’t then waste a second iteration on comparison unless they are the same length. However, If going over the same string twice sounds evil to you, and both string are guaranteed to be null terminated (seems to be the case) you can always just use strcmp. It’s what it was created to do after all. – Taekahn Sep 04 '22 at 18:48