1 पॉइंट द्वारा GN⁺ 3 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • 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 strncpy API को आखिरकार हटा दिया
  • 6 साल तक चली cleanup प्रक्रिया के बाद kernel के अंदर strncpy interface इस्तेमाल करने वाला कोई 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 में strncpy API को हटा दिया गया
  • उसी merge में आखिरी per-CPU architecture-specific strncpy implementation भी खत्म हो गया

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 टिप्पणियां

 
GN⁺ 3 시간 전
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 मिले हैं, तो मानो खुशी से पार्टी ही कर लो

    • Walter Bright का 2007 का लेख यहाँ है: https://digitalmars.com/articles/C-biggest-mistake.html
      खोजते-खोजते इसी विषय पर एक 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 किया जाता था
    • VLA को C11 में optional feature के स्तर पर नीचे कर दिया गया था, और मुझे लगता है कि यह अच्छी बात थी
      अब बड़ी समस्या यह है कि 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 ही आ जाएँ, तो काफ़ी सुधार हो सकता है
    • Ritchie के प्रस्ताव का लिंक: https://web.archive.org/web/20150611114358/https://www.bell-...
    • टीमवर्क में यही पैटर्न सबसे ज़्यादा खलता है। समाधान A, B, C हैं, हर एक के अपने फायदे-नुकसान हैं, 2 हफ़्ते तक चर्चा होती है, और आख़िर में कुछ भी नहीं चुना जाता
    • इससे बस WG14 की प्राथमिकताएँ कहाँ हैं, यही पता चलता है
  • 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 में ही रहते

    • मैंने ASCII के field/record separator characters से framed data को convert करने वाला एक project किया था, और उसे संभालना वाकई बहुत आसान था
      comma-separated data में जो गंदी escaping की परेशानियाँ आती हैं, वे गायब हो गईं, और चीज़ें काफ़ी सरल हो गईं
    • Unicode में अब और भी विकल्प हैं। EBCDIC से आया हुआ NL Next line, और Unicode के अपने LS Line separator, PS Paragraph separator मौजूद हैं
      Unicode standard कहता है कि CR, LF, CRLF और इन characters के अलावा vertical tab और form feed को भी line separators की तरह माना जाना चाहिए
    • standard input/output में UTF-8 एकदम सही काम करता है। बेशक, यह तब है जब आप international text encoding के मामले में 90 के दशक की शुरुआत में अटके Windows की बात नहीं कर रहे हों
      LF, CR, CRLF जैसे line endings operating system conventions भी हैं, और बेहतर यही है कि programming languages सही line ending को “guess” करने की कोशिश न करें। यह जितनी समस्या हल करता है उससे ज़्यादा पैदा करता है, और फिर वही बात, यह ज़्यादातर Windows की समस्या है, इसलिए Microsoft को Windows को इस सदी में लाना चाहिए
    • LF सबसे ज़्यादा समझदारी भरा लगता है, लेकिन text files के लिए दोनों में से कुछ भी चलेगा। असली समस्या यह है कि CSV text नहीं है
      आख़िरी बार जब मुझे bash में CSV files संभालनी पड़ीं, तो मैंने अंदरूनी तौर पर उन्हें RS और FS में बदलकर process किया
    • मेरी राय में बस हर जगह UTF-8 इस्तेमाल करना चाहिए
  • 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() इस्तेमाल करो
    यह किसी दुःस्वप्न जैसा लगता है, और समझ नहीं आता कि क्या इसे इतना जटिल होना ही चाहिए

    • वजह performance है। इन सबको संभालने वाला कोई safe universal function अंदरूनी branching की वजह से अनिवार्य रूप से धीमा होगा, और कौन-सा function चुना गया है, उसमें developer का इरादा भी झलकता है
      code पढ़ते समय सिर्फ function selection से ही developer का intent साफ़ दिखे, यह मुझे ज़्यादा बेहतर लगता है
    • strncpy को सही तरीके से इस्तेमाल करना तो शुरू से ही हमेशा जटिल था
    • कम-से-कम इनके नाम तो थोड़े बेहतर रखे जा सकते थे
  • इसी तरह के उबाऊ repetitive काम में ही systems engineering का असली काम होता है
    Linux kernel को पूरे process के दौरान उपयोगी बनाए रखते हुए उसे ज़्यादा reliable बनाने वाले ऐसे बड़े infrastructure projects महीनों में नहीं, बल्कि दशकों में चलते हैं

    • यह समझ में आता है कि यह दशकों का काम क्यों बन जाता है। users और dependencies की long tail सच में बहुत लंबी होती है
      लेकिन यह कम स्पष्ट है कि क्या इस रफ़्तार से लंबे समय में वास्तव में meaningful progress बनाई जा सकती है। यह शिकायत कम, और core infrastructure के paradox जैसा ज़्यादा लगता है
  • यह एक शानदार और विनम्र बना देने वाला काम है। इतने सारे लोगों ने इसमें योगदान दिया, यह सचमुच हैरान करने वाली बात है
    “शानदार नई features” को श्रेय मिलना आसान होता है, लेकिन kernel जैसी बुनियादी चीज़ों में खराब features को हटाना शायद उससे भी ज़्यादा महत्वपूर्ण हो सकता है
    50 साल बाद जब लोग source code पढ़ना ही भूल जाएँगे, और Claude/Codex का कचरा चुपचाप जमा होता रहेगा और धरती की ज़्यादातर ऊर्जा जलाता रहेगा, तब शायद ऐसे काम “स्थापना युग” की दंतकथाओं की तरह याद किए जाएँगे

    • इससे Vernor Vinge की Deepness in the Sky याद आती है। उसमें एक व्यक्ति software archaeology के ज़रिए एक spaceship की maintenance करता है
      और वही अकेला व्यक्ति होता है जिसे Unix epoch का मतलब पता है
    • मुझे नहीं लगता कि 50 साल बाद सब लोग source code समझना भूल जाएँगे। चीज़ें कैसे काम करती हैं यह जानने की इंसानी इच्छा तब भी बनी रहेगी
    • AI द्वारा बनाया गया खिचड़ी code उससे बहुत पहले ही संभाल से बाहर हो जाएगा, ऐसा लगता है
  • मुझे लगता है कि null-terminated string computing के इतिहास की सबसे बड़ी गलती थी। Pascal-style strings कहीं अधिक सुरक्षित थीं

    • Visual Basic, और बाद में COM द्वारा अपनाया गया BSTR, जैसे बीच के रास्ते भी हैं
      यह अब भी 0 पर खत्म होने वाले character array की ओर इशारा करने वाला pointer है, लेकिन pointer जिस पहले byte की ओर इशारा करता है उसके ठीक पहले एक length field होती है। जब तक embedded NUL characters न हों, यह C strings के साथ compatible रहता है, और BSTR type functions length value का उपयोग कर सकती हैं
    • कुछ हद तक सहमत हूँ, लेकिन size field के data type को लेकर भी बहस होती। अगर variable-length न होता तो और भी ज़्यादा, और अगर variable-length होता तो दूसरी समस्याएँ आतीं
      एक समय 16-bit भी ज़रूरत से ज़्यादा लगा होगा, और आज 32-bit बहुत छोटा लग सकता है। C को “strongly typed” भाषा कहा जाता है, लेकिन जहाँ यह सबसे ज़रूरी था वहाँ यह काफ़ी ढीली है
    • null-terminated strings ने बेहद उपयोगी software की एक विशाल दुनिया की नींव रखी। इसे computing की सबसे बड़ी गलती कहना थोड़ा बढ़ा-चढ़ाकर कहना है
      Pascal से जुड़ा code मैंने 30 साल से ज़्यादा समय से नहीं लिखा, लेकिन धुंधली-सी याद है कि तब भी उसकी string system इस्तेमाल करने में बहुत असुविधाजनक लगती थी
    • क्या 255 characters सबके लिए काफ़ी नहीं होने चाहिए थे?
    • यह newline-terminated lines जितना ही बुरा है
  • सिर्फ़ string data type न होने की वजह से जितनी तकलीफ़ और जुगाड़बाज़ी झेलनी पड़ती है, वह बहुत ज़्यादा है

    • सही कहें तो समस्या सिर्फ़ string data type न होने की नहीं, बल्कि C में string data type न होने की कमी को घुमाकर संभालने की वजह से होने वाली तकलीफ़ और जुगाड़बाज़ी की है
    • यहाँ strong typing लाने का कौन-सा तरीका संभव हो सकता है? क्या 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 में रही हो

    • हो सकता है यह SQL database के char fields से आने वाले strings की वजह से रहा हो। varchar नहीं, char fields spaces से pad किए जाते हैं
    • मुझे लगता है इस behavior की जड़ Pascal नहीं बल्कि COBOL होगी
    • यह भी हो सकता है कि string size बदलने पर reallocation रोकने के लिए ऐसा किया गया हो, या फिर CPU cache line alignment की वजह से