2011-05-14 69 views
25

strtok的哪些功能是不安全的(就緩衝區溢出而言),我需要注意什麼?爲什麼strtok()被認爲是不安全的?

對我來說有點奇怪的是在Visual C++中的strtok_s(這是「安全」)有一個額外的「上下文」參數,但它看起來在其他方面是相同的......是相同的,或者它實際上是不同的?

+1

也許是因爲strtok的兩個參數都是指向char的指針,所以strtok可能不會達到溢出任何本地緩衝區的任何終結符字符? – Heisenbug 2011-05-14 02:21:41

+0

@ 0verbose:嗯......但是對於所有的C字符串都不是這樣嗎? – Mehrdad 2011-05-14 02:22:58

+0

你可以看看實現:http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strtok.c?rev=1.6&content-type=text/x-cvsweb-markup 。我也看看。 – Heisenbug 2011-05-14 02:28:03

回答

23

this document的strtok_s部根據:

6.7.3.1的strtok_s起作用的strtok_s功能修復兩個問題 在strtok的功能:

  1. 一個新參數, s1max,可以防止strtok_s被存儲在 字符串之外。 (因爲 strtok_s存儲的字符串 被分成令牌既是 輸入和功能的輸出空字符到 的字符串。)
  2. 一個新參數,PTR,消除了靜態內部狀態 防止strtok的被重入 (子條款1.1.12)。 (在ISO/IEC 9899 功能wcstok和ISO/IEC 9945 (POSIX)函數strtok_r相同的解決這個問題 )
+0

+1我沒有看到該文檔,似乎正好解釋了答案。 :) – Mehrdad 2011-05-14 02:37:35

+1

請注意,這個'strtok_s()'的規範來自ISO/IEC 9899:2011附錄K(可選),其定義與['strtok_s()'](https:// msdn.microsoft.com/en-us/library/ftsafwz3.aspx)。 – 2017-09-30 21:20:45

11

沒有什麼不安全的。你只需要瞭解它是如何工作的以及如何使用它。編寫代碼和單元測試之後,只需花費幾分鐘的時間就可以使用valgrind重新運行單元測試,以確保您正在使用內存邊界進行操作。該手冊頁說明了一切:

BUGS

使用這些功能時一定要小心。如果你確實使用它們,請注意:

  • 這些函數修改它們的第一個參數。
  • 這些函數不能用於常量字符串。
  • 定界字符的標識丟失。
  • strtok()函數在解析時使用了一個靜態緩衝區,所以它不是線程安全的。如果這對您很重要,請使用strtok_r()
+0

我做了一個未成年人編輯關於'strtok_s' ......你碰巧知道它有什麼不同嗎? – Mehrdad 2011-05-14 02:25:23

+0

我不熟悉那個,但聽起來像strtok_r。如果你同時標記兩個或更多的字符串,那麼你需要其中的一個。如果你只處理一個,那麼就沒有必要使用它。 – Bob 2011-05-14 02:35:44

+0

啊好的,+1謝謝! – Mehrdad 2011-05-14 02:38:45

0

如果你沒有正確空結尾的字符串;你會以緩衝區溢出結束。另外請注意(這是我學到了很難的東西)strtok似乎並不關心內部字符串。 I.E.有「你好」/「世界」將解析「你好」/「世界」,而「你好/世界」將解析爲「你好世界」。請注意,它在/上分裂並且忽略它在括號內的事實。

4

strtok在Visual C++(但其他地方)中是安全的,因爲它使用線程本地存儲來保存其調用之間的狀態。在其他地方,全局變量用於保存strtok()狀態。

然而,即使在VC++中,strtok是線程安全的,它仍然有點奇怪 - 你不能同時在同一個線程的不同字符串中使用strtok()。例如,這將無法正常工作:

 token = strtok(string, seps); 
    while(token) 
    { 
     printf("token=%s\n", token) 
     token2 = strtok(string2, seps); 
     while(token2) 
     { 
      printf("token2=%s", token2); 
      token2 = strtok(NULL, seps); 
     } 
     token = strtok(NULL, seps); 
    } 

爲什麼它不會爲每個線程只有單一的國家可以被保存在線程本地存儲工作良好,在這裏人們會需要2個狀態的原因 - 第一個字符串和第二個字符串。所以雖然strtok在VC++中是線程安全的,但它不是可重入的。

什麼strtok_s(或其他地方的strtok_r)提供 - 一個明確的狀態,並且該strtok變爲可重入。

相關問題