GCC 8 ने एक -Wstringop-truncation चेतावनी जोड़ी। https://gcc.gnu.org/bugzilla/show_bug.cgi?id= से 82944 :

बग 81117 के लिए r254630 के माध्यम से GCC 8.0 में जोड़ा गया -Wstringop-truncation चेतावनी विशेष रूप से strncpy फ़ंक्शन के संभावित अनपेक्षित उपयोगों को उजागर करने के लिए अभिप्रेत है जो स्रोत स्ट्रिंग से समाप्त होने वाले NUL चार्टर को काट देता है। अनुरोध में दिए गए इस तरह के दुरुपयोग का एक उदाहरण निम्नलिखित है:

char buf[2];

void test (const char* str)
{
  strncpy (buf, str, strlen (str));
}

मुझे इस कोड के साथ एक ही चेतावनी मिलती है।

strncpy(this->name, name, 32);

warning: 'char* strncpy(char*, const char*, size_t)' specified bound 32 equals destination size [-Wstringop-truncation`]

यह मानते हुए कि this->name char name[32] है और name एक char* है जिसकी लंबाई संभावित रूप से 32 से अधिक है। मैं name को this->name में कॉपी करना चाहूंगा। और अगर यह 32 से बड़ा है तो इसे काट दें। क्या size_t 32 के बजाय 31 होना चाहिए? मैं उलझन में हूं। this->name के लिए NUL-समाप्त होना अनिवार्य नहीं है।

31
JRR 6 मई 2018, 12:44

4 जवाब

सबसे बढ़िया उत्तर

यह संदेश आपको चेतावनी देने का प्रयास कर रहा है कि आप ठीक वही कर रहे हैं जो आप कर रहे हैं। बहुत बार, प्रोग्रामर का इरादा ऐसा नहीं होता है। यदि आप यही चाहते हैं (मतलब, आपका कोड उस मामले को सही ढंग से संभाल लेगा जहां वर्ण सरणी किसी भी शून्य वर्ण से समाप्त नहीं होगी), चेतावनी बंद करें।

यदि आप इसे विश्व स्तर पर बंद नहीं करना चाहते हैं या नहीं कर सकते हैं, तो आप इसे स्थानीय रूप से बंद कर सकते हैं जैसा कि @doron द्वारा बताया गया है:

#include <string.h>
char d[32];
void f(const char *s) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
    strncpy(d, s, 32);
#pragma GCC diagnostic pop
}
29
6 मई 2018, 14:14

यह नई जीसीसी चेतावनी कई परियोजनाओं में strncpy() को अधिकतर अनुपयोगी बनाती है: कोड समीक्षा कोड को स्वीकार नहीं करेगी, जो चेतावनियां उत्पन्न करती है। लेकिन अगर strncpy() का उपयोग केवल स्ट्रिंग्स के साथ किया जाता है, ताकि यह टर्मिनेटिंग जीरो बाइट लिख सके, फिर शुरुआत में डेस्टिनेशन बफर को शून्य कर दिया जाए और फिर सादा strcpy() वही काम हासिल कर ले।

वास्तव में, strncpy() उन कार्यों में से एक है, जिन्हें उन्होंने सी लाइब्रेरी में नहीं डाला था। इसके लिए वैध उपयोग के मामले हैं, निश्चित रूप से। लेकिन पुस्तकालय डिजाइनर निश्चित आकार के स्ट्रिंग जागरूक समकक्षों को मानक में strncpy() रखना भूल गए। सबसे महत्वपूर्ण ऐसे फ़ंक्शन, strnlen() और strndup(), को केवल 2008 में POSIX.1 में शामिल किया गया था, strncpy() बनने के दशकों बाद! और अभी भी कोई फ़ंक्शन नहीं है, जो एक strncpy() जेनरेट की गई फिक्स्ड-लेंथ स्ट्रिंग को सही सी सेमेन्टिक्स के साथ प्रीआलोकेटेड बफर में कॉपी करता है, यानी हमेशा 0-टर्मिनेशन बाइट लिखता है। ऐसा ही एक कार्य हो सकता है:

// Copy string "in" with at most "insz" chars to buffer "out", which
// is "outsz" bytes long. The output is always 0-terminated. Unlike
// strncpy(), strncpy_t() does not zero fill remaining space in the
// output buffer:
char* strncpy_t(char* out, size_t outsz, const char* in, size_t insz){
    assert(outsz > 0);
    while(--outsz > 0 && insz > 0 && *in) { *out++ = *in++; insz--; }
    *out = 0;
    return out;
}

मैं भ्रम से बचने के लिए strncpy_t() के लिए दो लंबाई के इनपुट का उपयोग करने की सलाह देता हूं: यदि केवल एक size तर्क था, तो यह स्पष्ट नहीं होगा, यदि यह आउटपुट बफर का आकार या अधिकतम लंबाई है इनपुट स्ट्रिंग (जो आमतौर पर एक कम होती है)।

6
Kai Petzke 4 अक्टूबर 2019, 17:02

strncpy का उपयोग करने के लिए बहुत कम उचित मामला है। यह काफी खतरनाक फंक्शन है। यदि स्रोत स्ट्रिंग की लंबाई (शून्य वर्ण के बिना) गंतव्य बफ़र आकार के बराबर है, तो strncpy गंतव्य बफ़र के अंत में शून्य वर्ण नहीं जोड़ेगा। तो गंतव्य बफर को समाप्त नहीं किया जाएगा।

हमें इस प्रकार का कोड Linux पर लिखना चाहिए:

lenSrc = strnlen(pSrc, destSize)
if (lenSrc < destSize)
    memcpy(pDest, pSrc, lenSrc + 1);
else {
    /* Handle error... */
}

आपके मामले में, यदि आप प्रतिलिपि पर स्रोत को छोटा करना चाहते हैं, लेकिन फिर भी एक शून्य समाप्त गंतव्य बफर चाहते हैं, तो आप इस प्रकार का कोड लिख सकते हैं:

destSize = 32

sizeCp = strnlen(pSrc, destSize - 1);
memcpy(pDest, pSrc, sizeCp);
pDest[sizeCp] = '\0';

संपादित करें: ओह... यदि यह अनिवार्य नहीं है कि NULL को समाप्त किया जाए, strncpy उपयोग करने के लिए सही कार्य है। और हाँ आपको इसे 32 के साथ कॉल करने की आवश्यकता है न कि 31 के साथ। मुझे लगता है कि आपको इस चेतावनी को अक्षम करके इसे अनदेखा करने की आवश्यकता है... ईमानदारी से कहूं तो मेरे पास इसका कोई अच्छा जवाब नहीं है...

संपादन2: strncpy फ़ंक्शन की नकल करने के लिए, आप यह कोड लिख सकते हैं:

destSize = 32

sizeCp = strnlen(pSrc, destSize - 1);
memcpy(pDest, pSrc, sizeCp + 1);
4
benjarobin 6 मई 2018, 13:53

मैंने पाया कि चेतावनी को दबाने का सबसे अच्छा तरीका अभिव्यक्ति को कोष्ठकों में रखना है इस gRPC पैच की तरह:

(strncpy(req->initial_request.name, lb_service_name,
         GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH));

#pragma डायग्नोस्टिक्स सप्रेशन सॉल्यूशन के साथ समस्या यह है कि #pragma स्वयं एक चेतावनी का कारण बनेगा जब कंपाइलर या तो प्रज्ञा या विशेष चेतावनी को नहीं पहचानता है; यह भी वर्बोज़ है।

0
mmx 1 जून 2019, 01:32