strncpy 安全嗎?

測試一下看看,Linux 環境下,這三個函數(strcpy, strncpy, snprintf)哪個比較安全。


🔥文章來源:wenfh2020.com

1. 測試代碼

數據拷貝,當目標內存很小,源數據很大時,從測試結果看:

  • snprintf 結果正常,達到預期。
  • strcpy 拷貝的數據打印出來有點問題,不知道是否正常。
  • strncpy 崩潰了。
// test.c
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    char test[2];
    const char* p = "hello world";

    printf("%s", "snprintf: ");
    snprintf(test, sizeof(test), "%s", p);
    printf("%s\n", test);

    printf("%s", "strcpy: ");
    strcpy(test, p);
    printf("%s\n", test);

    printf("%s", "strncpy: ");
    strncpy(test, p, sizeof(test));
    printf("%s\n", test);
}

# gcc -g test.c -o test && ./test
snprintf: h
strcpy: hello world
[1]    18785 segmentation fault (core dumped)  ./test

2. 看源碼,探究原因

  • strcpy

    從源碼看,字符串拷貝是尋找 ‘\0’ 結束符,從上面的測試場景看,這個函數是不安全的。

// https://github.com/torvalds/linux/blob/master/lib/string.c
char *strcpy(char *dest, const char *src) {
    char *tmp = dest;
    while ((*dest++ = *src++) != '\0')
        /* nothing */;
    return tmp;
}
  • strncpy

    從源碼看,字符串拷貝也是尋找 ‘\0’ 結束符,而且有數據大小限制。上面測試場景,數據拷貝是安全的,但是 printf 出問題了,因爲 printf 在打印字符串時,也是在找字符串的 ‘\0’ 結束符。而 strncpy 不會自動在字符串末尾填充 ‘\0’。

    關於 printf,詳細可以參考下我的帖子 printf 從現象到本質

// https://github.com/torvalds/linux/blob/master/lib/string.c
char *strncpy(char *dest, const char *src, size_t count) {
    char *tmp = dest;

    while (count) {
        if ((*tmp = *src) != 0)
            src++;
        tmp++;
        count--;
    }
    return dest;
}
  • sprintf

    代碼有點長,沒仔細看完,從測試場景上看,是正常的。。。(不嚴謹啊。_!)

// https://github.com/torvalds/linux/blob/master/lib/vsprintf.c
int snprintf(char *buf, size_t size, const char *fmt, ...) {
    va_list args;
    int i;

    va_start(args, fmt);
    i = vsnprintf(buf, size, fmt, args);
    va_end(args);

    return i;
}

int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) {
    ...
}

3. 總結

從測試結果看:

  • snprintf 比較安全。
  • strcpy 不安全。
  • strncpy 當目標內存很小時,拷貝完成後不會在末位填充 ‘\0’ ,拷貝操作後,目標字符串在使用中可能會有問題。

內存越界是 c/c++ 一個坑,有時候要解決這類型的偶發問題,只能看緣分。所以平時使用,須要形成良好的編碼習慣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章