C strcpy() - evil?

前端 未结 17 1308
梦毁少年i
梦毁少年i 2020-12-23 10:50

Some people seem to think that C\'s strcpy() function is bad or evil. While I admit that it\'s usually better to use strncpy() in order to avoid bu

17条回答
  •  时光说笑
    2020-12-23 10:59

    I personally am of the mindset that if the code can be proven to be valid—and done so quickly—it is perfectly acceptable. That is, if the code is simple and thus obviously correct, then it is fine.

    However, your assumption seems to be that while your function is executing, no other thread will modify the string pointed to by s1. What happens if this function is interrupted after successful memory allocation (and thus the call to strlen), the string grows, and bam you have a buffer overflow condition since strcpy copies to the NULL byte.

    The following might be better:

    char *
    strdup(const char *s1) {
      int s1_len = strlen(s1);
      char *s2 = malloc(s1_len+1);
      if(s2 == NULL) {
        return NULL;
      }
    
      strncpy(s2, s1, s1_len);
      return s2;
    }
    

    Now, the string can grow through no fault of your own and you're safe. The result will not be a dup, but it won't be any crazy overflows, either.

    The probability of the code you provided actually being a bug is pretty low (pretty close to non-existent, if not non-existent, if you are working in an environment that has no support for threading whatsoever). It's just something to think about.

    ETA: Here is a slightly better implementation:

    char *
    strdup(const char *s1, int *retnum) {
      int s1_len = strlen(s1);
      char *s2 = malloc(s1_len+1);
      if(s2 == NULL) {
        return NULL;
      }
    
      strncpy(s2, s1, s1_len);
      retnum = s1_len;
      return s2;
    }
    

    There the number of characters is being returned. You can also:

    char *
    strdup(const char *s1) {
      int s1_len = strlen(s1);
      char *s2 = malloc(s1_len+1);
      if(s2 == NULL) {
        return NULL;
      }
    
      strncpy(s2, s1, s1_len);
      s2[s1_len+1] = '\0';
      return s2;
    }
    

    Which will terminate it with a NUL byte. Either way is better than the one that I quickly put together originally.

提交回复
热议问题