18

Seems strncmp is usually recommended than strcmp, what are the advantages? I think it could be related to security. If this is the case, is it still applicable if one of the input string is known to be literal constant, like "LiteralString"?

UPDATE: I mean under the same user scenario where whole strings need to be compared, and strncmp can be used as below. I am wondering it makes sense or not.

strncmp(inputString, "LiternalString", strlen("LiternalString"));
Thomson
  • 20,586
  • 28
  • 90
  • 134
  • 2
    possible duplicate of [Why should you use strncpy instead of strcpy?](http://stackoverflow.com/questions/1258550/why-should-you-use-strncpy-instead-of-strcpy) – Spikatrix May 12 '15 at 12:47

8 Answers8

25

The problem with strcmp is that sometimes, if by mistake, arguments that are passed are not valid C-strings (meaning that p1 or p2 is not terminated with a null character i.e. not NULL-terminated String), then, strcmp continues comparing until it reaches non-accessible memory and crashes or sometimes results to an unexpected behaviour.

Using strncmp you can limit the search, so that it doesn't reach non-accessible memory.

But, from that, it should not be concluded that strcmp is insecure to use. Both the functions work well in the way they are intended to work. Programmer should read man page for that function before using it and must be sincere enough while passing parameters to such library functions.

You can also read THIS which contains an almost similar question.

Surajeet Bharati
  • 1,363
  • 1
  • 18
  • 36
  • My question now is: what is the value to set for n, to ensure i won't reach non- accessable memory, and still ensure to get any valid input. – dhein May 12 '15 at 12:23
  • 1
    `strcmp` function is to compare strings, it you pass buffers that are not strings, what semantics to you expect ? – chqrlie May 12 '15 at 12:26
  • @Zaibis, to set a value for `n`, one of the parameter must be a valid string whose `length` can be assigned to `n` as you did in the UPDATE part of your question. – Surajeet Bharati May 12 '15 at 12:31
  • "*until it reaches non-accessible memory and crashes.*" -- It might not crash. It is just Undefined Behavior – Spikatrix May 12 '15 at 12:36
  • @CoolGuy, That's cent percent true, it may result undefined behaviour instead of crashing – Surajeet Bharati May 12 '15 at 12:39
  • 1
    @chqrlie , Answerer has updated the answer. He/she meant to say not C-strings,i.e, not NUL-terminated strings – Spikatrix May 12 '15 at 12:41
  • 5
    The whole "if by mistake" idea is not convincing. `strncmp` is not a hardening function. It's semantically different from `strcmp` and has different uses. – R.. GitHub STOP HELPING ICE May 12 '15 at 13:12
  • @R.. , I have mentioned that. Its actually programmer's fault. Both the functions works well in the way they are intended to work – Surajeet Bharati May 12 '15 at 13:16
  • With this logic, most string functions from standard library, such as `strlen` can never be used because if "by mistake" the string arguments may not contain nul-terminator. – P.P Oct 24 '18 at 23:09
  • @P.P. I've never said that `strcmp` could never be used. Its just need proper arguments (supplying NULL-terminated strings) to get expected result. And yes this is true for all string functions from standard library, such as `strlen`. – Surajeet Bharati Oct 31 '18 at 12:14
17

strncmp does not have "advantages over strcmp"; rather they solve different problems. strcmp is for determining if two strings are equal (and if not, possibly how to order/sort them with respect to each other). strncmp is (mainly) for determining whether a string begins with a particular prefix. For example:

if (strncmp(str, "--option=", 9)==0)

will determine if str begins with "--option=". This cannot be achieved by strcmp without either modifying the string to be checked (which may not be a valid operation) or making a useless copy of it. It also cannot be achieved with memcmp unless you already know str points to an object at least 9 bytes in length; otherwise the call to memcmp would have undefined behavior.

There are other usage cases for strncmp too, such as working with non-C-string data.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
10

It all depends on your use-cases. Use strncmp if you only need to compare a fixed number of characters, use strcmp if you need to compare a whole string.

That's about it.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
5

... under the same user scenario where whole strings need to be compared, ...

 strncmp(inputString, "LiternalString", strlen("LiternalString"));

Consider the case where string inputString is longer than the string literal.

const char *inputString = "LiternalString_XYZ";
int cmp = strncmp(inputString, "LiternalString", strlen("LiternalString"));
printf("%d\n", cmp); // prints 0.

But OP wanted whole strings compared.

const char *inputString = "LiternalString_XYZ";
int cmp = strcmp(inputString, "LiternalString");
printf("%d\n", cmp); // prints non-zero.

Conclusion to OP's direct question

I am wondering it makes sense or not.

No. To compare whole strings, strncmp() fails to consistently provide the correct result. Use strcmp().


Further

strncmp(s1,s2,n) can limit the search, so that it doesn't reach non-accessible memory if n was properly computed - which was not done in OP's code and problematic to do right when the best n is different for s1 and s2.

The size limit n applies to both s1 and s2 thus making this function useful for comparing prefixes, but not `"safer".

In OP's case, there is no reason to limit the search due to "safety" on account of the string length of the string literal as string literals always contains a terminating null character.

If anything, n should have been based on some property of inputString.

Code like strncmp(s1, string_literal, strlen(s1)) is functionally incorrect as the compare misses the null character. A wee bit better is strncmp(s1, string_literal, strlen(s1)+1), but that is functionally the same as the simpler strcmp(s1, string_literal) with no reduction in "safety".


The below offer some improve "safety" in case foo() did not properly form strings, but can provide the wrong answer if N != M as above.

char s1[N];
foo(s1); // populate s1 somehow
int cmp = strncmp(s1, string_literal, sizeof s1);

char s1[N];
char s2[M];
foo(s1); // populate s1 somehow
foo(s2); // populate s2 somehow
int cmp = strncmp(s1, s2, min(sizeof s1, sizeof s2));

Yet in those cases, the problem is in foo(), not here.
For me, if foo() was so questionable, I'd use the following

s1[sizeof s1 - 1] = '\0';
s2[sizeof s2 - 1] = '\0';
int cmp = strcmp(s1, s2);

or detect that foo() did not form a string.

char s1[N];
foo(s1);
if (memchr(s1, '\0', sizeof s1) == NULL) Oops();

Moral of the story: strncmp() is not a "safer" version of strcmp(). It is a tool for a different job: comparing string prefixes.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

Just post an anti-strncmp use case here. Think about the following code.

#include <stdio.h>
#include <dirent.h>

int main()
{
    //I want to list all files under current folder, include hidden files.
    DIR *dir;
    struct dirent *dp;
    char * file_name;
    dir = opendir(".");
    while ((dp=readdir(dir)) != NULL) {
        printf("debug: %s\n", dp->d_name);
        if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") )
        //It doesn't work if you replace strcmp with strncmp here.
        //if ( !strncmp(dp->d_name, ".", 1) || !strncmp(dp->d_name, "..", 2) )  
        {
        } else {
            file_name = dp->d_name;
            printf("file_name: \"%s\"\n",file_name);
        }
    }
    closedir(dir);
    return 0;
}
user3099889
  • 11
  • 1
  • 2
1
int ret1, ret2;
char dev1[]  = { "ABC" };
char dev2[4] = { "ABC" };

dev2[3] = 'D';
ret1 = strncmp(dev1,dev2,strlen(dev1));  // # of characters
ret2 = strncmp(dev1,dev2,sizeof(dev1));  // # of characters plus '\0'

assume: dev1 is null terminated and dev2 is probably not. ret1 = 0 (false positive result), rather than ret2=-1 (valid result)

fazit: strncmp is not just a safer way for strcmp. depends on how you make use of it.

i´d use strcmp on strings, and strncmp on substring search.

-2

strcmp could lead to storage volation and segmentation fault in case where one of arguments is not null-terminated string. Take a look why you should use strncpy instead of strcpy. Consequences are unlikely to happen in strcmp, but issue is the same. strnxxx function family try to prevent reading/writing not acquired memory.

Disadvantage of using strn is extra compare and decrement operation on counter.

In few words: strncmp is safer then strcmp, but it is slower too.

Community
  • 1
  • 1
M.L.
  • 728
  • 4
  • 12
  • `strncmp` and `strcmp` have different semantics. Using one for the other is not a hardening method. `strncpy` is different from `strcpy` in ways most programmers are unaware of. To prevent buffer overflow by *limiting* the copy to the destination buffer, `strlcpy` is **much** better than *strncpy*. If your system does not have it, implementing your own version is recommended. – chqrlie May 13 '15 at 05:10
  • 1
    Strncmp only prevents an overrun if you know that only one of the strings might not be null-terminated and you know which of the two strings it is. And if you use strncmp as a replacement for strcmp, you might be opening yourself up to having a substring match come back true when you didn’t want that. – Robert Fisher Jan 29 '18 at 16:46
-3

I could see only one advantage, that strncmp will take slightly less time to execute than strcmp as we will always compare prefix of string to comapre rather than entire string.

I don't think that there is any security aspect involved in strcmp and strncmp algorithm. They are same except that in strncmp only first 'n' characters are compared.