Linux: 6 साल और 360 से ज़्यादा पैच के बाद `strncpy` API हटाई गई
(phoronix.com/news)- Linux 7.2 में kernel के अंदर strncpy API के सभी उपयोग समाप्त हो गए, और लंबे समय से deprecated string copy interface को आखिरकार हटा दिया गया
strncpy()तय किए गए byte count तक copy करता है, लेकिन NUL termination का इसका व्यवहार सहज नहीं है, इसलिए यह kernel में वर्षों तक bugs का कारण बना रहा- destination buffer को बेवजह 0 से भरने वाली इसकी प्रकृति ने performance issues भी पैदा किए, और इसे पूरी तरह हटाने में लगभग 6 साल और 362 commits लगे
- शुक्रवार के merge में API के मुख्य implementation के साथ आखिरी per-CPU architecture-specific implementation भी हटा दिया गया
- अब kernel code को उपयोग के हिसाब से
strscpy(),strscpy_pad(),strtomem_pad(),memcpy_and_pad(),memcpy()जैसे alternative functions चुनने होंगे
Linux 7.2 में हटाई गई strncpy
- Linux 7.2 ने kernel से लंबे समय से deprecated
strncpyAPI को आखिरकार हटा दिया - 6 साल तक चली cleanup प्रक्रिया के बाद kernel के अंदर
strncpyinterface इस्तेमाल करने वाला कोई code अब नहीं बचा - यह बदलाव सिर्फ function replacement नहीं, बल्कि पूरे kernel में पुरानी string copy practices को हटाने जैसा काम है
हटाने तक लगे काम का पैमाना
strncpyको हटाने में लगभग 362 commits लगे- यह काम kernel के अंदर
strncpyके उपयोग को चरणबद्ध तरीके से खत्म करने के रूप में आगे बढ़ा - Linux 7.2 में यह cleanup प्रक्रिया अपने पूर्ण बिंदु तक पहुंच गई
kernel में strncpy समस्या क्यों था
strncpyको Linux kernel में वर्षों तक लगातार bug का कारण माना गया- खास तौर पर इसके दो व्यवहार समस्या बने
- NUL termination का अर्थ और व्यवहार सहज नहीं था, इसलिए developers के लिए गलती करना आसान था
- destination buffer को बार-बार 0 से pad करने से बेवजह performance cost पैदा होती थी
वास्तविक removal merge
- शुक्रवार को हुए merge में
strncpyAPI को हटा दिया गया - उसी merge में आखिरी per-CPU architecture-specific
strncpyimplementation भी खत्म हो गया
kernel code में इस्तेमाल होने वाले alternative APIs
strncpyकी जगह copy target और termination condition के हिसाब से function चुनना होगाstrscpy(): NUL-terminated destination के लिएstrscpy_pad(): NUL-terminated destination में 0 padding चाहिए तोstrtomem_pad(): non-NUL-terminated fixed-width fields के लिएmemcpy_and_pad(): explicit padding वाली bounded copy के लिएmemcpy(): length पता होने पर memory copy के लिए
1 टिप्पणियां
Hacker News की राय
पहले लोग मज़ाक उड़ाते थे कि दुनिया के सबसे बेहतरीन C developers में गिने जाने वाले Linux kernel developers को stringbuffer या stringview type बनाना नहीं आता, लेकिन उस समय इस विषय पर आज जैसी सहमति नहीं थी, इसलिए कुछ हद तक यह समझ में आता है
सही दिशा पहले से देख लेने वाले व्यक्ति Dennis Ritchie थे, और उन्होंने 1990 में C के लिए fat pointer type का प्रस्ताव दिया था। अगर वह C99 में शामिल हो जाता तो यह एकदम बेहतरीन addition होता; अगर committee ने उसे शामिल किया होता तो दुनिया काफ़ी अलग हो सकती थी
2007 में Walter Bright का “C's greatest mistake” लेख आया, जिसने दूसरा मौका दिया, और उसमें मूलतः Ritchie जैसी ही slice/stringview वाली सोच को और साफ़ ढंग से समझाया गया, लेकिन वह भी C11 में शामिल नहीं हो पाया। अब C23 तक आ गए, फिर भी वह नहीं है, और बदले में _Generic और VLA मिले हैं, तो मानो खुशी से पार्टी ही कर लो
खोजते-खोजते इसी विषय पर एक Reddit पोस्ट भी दिखी, और उसमें bikeshedding वाली बहस काफ़ी मज़ेदार लगी: https://www.reddit.com/r/C_Programming/comments/90uq7c/cs_bi...
यह जानने की उत्सुकता है कि C array के pointer में decay होने वाला व्यवहार आखिर डिज़ाइन ही क्यों किया गया। एक व्याख्या यह मिलती है कि इसका मकसद B code को बहुत कम बदलाव के साथ C में compile होने लायक बनाना था; B में array declaration वास्तव में pointer और array दोनों को define करती थी, और उस pointer को array के पहले element की ओर initialize किया जाता था
अब बड़ी समस्या यह है कि C standard library अब भी K&R युग में अटकी हुई है, और C99 में जो language features आए थे, जैसे struct arguments या return values, उनका असर standard library API पर भी नहीं दिखता। अगर standard library में pointer/size pair वाले range structs और उनका उपयोग करने वाले नए string functions या update किए गए string functions ही आ जाएँ, तो काफ़ी सुधार हो सकता है
Linux kernel के अंदर का strncpy कई सालों तक “ज़िद्दी bug का स्रोत” माना गया, क्योंकि उसकी semantics सहज नहीं हैं, NUL termination का व्यवहार उलझाऊ है, और destination में बेवजह 0 भरने की performance समस्या भी है
जब भी मुझसे C code review करने को कहा जाता था, मैं strncpy को ढूँढता था, और लगभग हमेशा वहीं bug मिल जाता था
कुछ चीज़ें 40 साल से खटकती रही हैं। NUL-terminated strings, और अब तो I/O में UTF-8 न होने वाली strings भी उसी सूची में हैं
line ending को LF, CR, CRLF से संभालने की परंपरा भी वैसी ही है, और pipe या comma से fields अलग करने का तरीका भी। अगर GS, FS, RS जैसे साफ़-साफ़ ASCII characters का इस्तेमाल किया गया होता, तो line ending का encoding/decoding I/O की समस्या भर रह जाता, और HT/VT/CR/LF/FF सचमुच output से जुड़े code में ही रहते
comma-separated data में जो गंदी escaping की परेशानियाँ आती हैं, वे गायब हो गईं, और चीज़ें काफ़ी सरल हो गईं
Unicode standard कहता है कि CR, LF, CRLF और इन characters के अलावा vertical tab और form feed को भी line separators की तरह माना जाना चाहिए
LF, CR, CRLF जैसे line endings operating system conventions भी हैं, और बेहतर यही है कि programming languages सही line ending को “guess” करने की कोशिश न करें। यह जितनी समस्या हल करता है उससे ज़्यादा पैदा करता है, और फिर वही बात, यह ज़्यादातर Windows की समस्या है, इसलिए Microsoft को Windows को इस सदी में लाना चाहिए
आख़िरी बार जब मुझे bash में CSV files संभालनी पड़ीं, तो मैंने अंदरूनी तौर पर उन्हें RS और FS में बदलकर process किया
strncpy की जगह Linux kernel code में कहा गया है कि NUL-terminated destination के लिए strscpy(), 0 padding चाहिए तो strscpy_pad(), non-NUL-terminated fixed-width fields के लिए strtomem_pad(), explicit padding वाली bounded copy के लिए memcpy_and_pad(), और known-length memory copy के लिए memcpy() इस्तेमाल करो
यह किसी दुःस्वप्न जैसा लगता है, और समझ नहीं आता कि क्या इसे इतना जटिल होना ही चाहिए
code पढ़ते समय सिर्फ function selection से ही developer का intent साफ़ दिखे, यह मुझे ज़्यादा बेहतर लगता है
इसी तरह के उबाऊ repetitive काम में ही systems engineering का असली काम होता है
Linux kernel को पूरे process के दौरान उपयोगी बनाए रखते हुए उसे ज़्यादा reliable बनाने वाले ऐसे बड़े infrastructure projects महीनों में नहीं, बल्कि दशकों में चलते हैं
लेकिन यह कम स्पष्ट है कि क्या इस रफ़्तार से लंबे समय में वास्तव में meaningful progress बनाई जा सकती है। यह शिकायत कम, और core infrastructure के paradox जैसा ज़्यादा लगता है
यह एक शानदार और विनम्र बना देने वाला काम है। इतने सारे लोगों ने इसमें योगदान दिया, यह सचमुच हैरान करने वाली बात है
“शानदार नई features” को श्रेय मिलना आसान होता है, लेकिन kernel जैसी बुनियादी चीज़ों में खराब features को हटाना शायद उससे भी ज़्यादा महत्वपूर्ण हो सकता है
50 साल बाद जब लोग source code पढ़ना ही भूल जाएँगे, और Claude/Codex का कचरा चुपचाप जमा होता रहेगा और धरती की ज़्यादातर ऊर्जा जलाता रहेगा, तब शायद ऐसे काम “स्थापना युग” की दंतकथाओं की तरह याद किए जाएँगे
और वही अकेला व्यक्ति होता है जिसे Unix epoch का मतलब पता है
मुझे लगता है कि null-terminated string computing के इतिहास की सबसे बड़ी गलती थी। Pascal-style strings कहीं अधिक सुरक्षित थीं
यह अब भी 0 पर खत्म होने वाले character array की ओर इशारा करने वाला pointer है, लेकिन pointer जिस पहले byte की ओर इशारा करता है उसके ठीक पहले एक length field होती है। जब तक embedded NUL characters न हों, यह C strings के साथ compatible रहता है, और BSTR type functions length value का उपयोग कर सकती हैं
एक समय 16-bit भी ज़रूरत से ज़्यादा लगा होगा, और आज 32-bit बहुत छोटा लग सकता है। C को “strongly typed” भाषा कहा जाता है, लेकिन जहाँ यह सबसे ज़रूरी था वहाँ यह काफ़ी ढीली है
Pascal से जुड़ा code मैंने 30 साल से ज़्यादा समय से नहीं लिखा, लेकिन धुंधली-सी याद है कि तब भी उसकी string system इस्तेमाल करने में बहुत असुविधाजनक लगती थी
सिर्फ़ string data type न होने की वजह से जितनी तकलीफ़ और जुगाड़बाज़ी झेलनी पड़ती है, वह बहुत ज़्यादा है
strncpyके आसपास के code को भी उस type और उन functions का उपयोग करने लायक बड़े पैमाने पर refactor नहीं करना पड़ेगा?मुझे जिज्ञासा है कि
strncpyके उपयोग-स्थलों को दोबारा लिखने में ऐसी क्या कठिनाई थी कि इसमें पूरे 6 साल लग गएक्या इसके उपयोग इतने व्यापक थे, या फिर यह ऐसा लंबा काम था जिसमें जब भी वही file छुई जाती थी तभी उसे बदला जाता था, या कोई और कठिनाई थी—यह जानना चाहूँगा
मैंने Win32 apps में space-padded strings इस्तेमाल करने वाला code संभाला है। destination string को spaces से pad किया जाता था, लेकिन आख़िरी byte में फिर भी null terminator होता था
length, copy जैसी operations के लिए string functions के dedicated versions इस्तेमाल करने पड़ते थे। ऐसा क्यों था, पता नहीं, लेकिन codebase इतना पुराना था कि संभव है इसकी जड़ Pascal struct behavior में रही हो
varcharनहीं,charfields spaces से pad किए जाते हैं