एक अमान्य पॉइंटर बनाने वाले फ़ंक्शन संदर्भ को कास्टिंग करना?


9

मैं तीसरे पक्ष के कोड में एक त्रुटि को ट्रैक कर रहा हूं और मैंने इसे कुछ लाइनों के साथ संकुचित कर दिया है।

use libc::c_void;

pub unsafe fn foo() {}

fn main() {
    let ptr = &foo as *const _ as *const c_void;
    println!("{:x}", ptr as usize);
}

स्थिर 1.38.0 पर दौड़ा यह फ़ंक्शन पॉइंटर को प्रिंट करता है, लेकिन बीटा (1.39.0-beta.6) और रात में वापसी '1'। ( खेल का मैदान )

किस बात का _अनुमान लगाया जा रहा है और व्यवहार क्यों बदल गया है?

मुझे लगता है कि यह कास्ट करने का सही तरीका होगा foo as *const c_void, लेकिन यह मेरा कोड नहीं है।


मैं "यह क्यों बदल गया है" का जवाब नहीं दे सकता, लेकिन मैं आपसे सहमत हूं कि कोड को शुरू करने के लिए गलत है। fooपहले से ही एक फ़ंक्शन पॉइंटर है, इसलिए आपको इसका पता नहीं लगाना चाहिए। यह एक दोहरा संदर्भ बनाता है, प्रतीत होता है कि एक शून्य-आकार प्रकार (इस प्रकार जादू मूल्य 1)।
Shepmaster

यह आपके प्रश्न का सही उत्तर नहीं देता है, लेकिन आप शायद चाहते हैं:let ptr = foo as *const fn() as *const c_void;
पीटर हॉल

जवाबों:


3

यह उत्तर इस प्रश्न से प्रेरित बग रिपोर्ट के उत्तरों पर आधारित है ।

Rust में प्रत्येक फ़ंक्शन का अपना अलग फ़ंक्शन आइटम प्रकार होता है , जो प्रत्येक अन्य फ़ंक्शन के फ़ंक्शन आइटम प्रकार से अलग होता है। इस कारण से, फ़ंक्शन आइटम प्रकार का एक उदाहरण किसी भी जानकारी को संग्रहीत करने की आवश्यकता नहीं है - यह किस फ़ंक्शन को इंगित करता है, इसके प्रकार से स्पष्ट है। तो चर x में

let x = foo;

आकार का एक चर है।

फ़ंक्शन आइटम प्रकार जहाँ आवश्यक हो, सूचक प्रकारों को कार्य करने के लिए अंतर्निहित रूप से मोटे होते हैं । चर

let x: fn() = foo;

हस्ताक्षर के साथ किसी भी फ़ंक्शन के लिए एक जेनेरिक पॉइंटर है fn(), और इस प्रकार फ़ंक्शन को एक पॉइंटर को स्टोर करने की आवश्यकता होती है जो वास्तव में इंगित करता है, इसलिए xएक पॉइंटर का आकार है।

यदि आप किसी फ़ंक्शन &fooका पता लेते हैं, तो आप वास्तव में एक शून्य-आकार के अस्थायी मान का पता ले रहे हैं। रेपो के लिए प्रतिबद्ध होनेrust से पहले , शून्य-आकार के अस्थायी लोगों ने स्टैक पर आवंटन बनाने के लिए उपयोग किया था, और &fooउस आवंटन के पते को वापस कर दिया। चूंकि यह प्रतिबद्ध है, शून्य-आकार के प्रकार अब आवंटन नहीं बनाते हैं, और इसके बजाय जादू पते का उपयोग करते हैं। 1. यह रस्ट के विभिन्न संस्करणों के बीच अंतर को बताता है।


यह समझ में आता है, लेकिन मैं असंबद्ध हूं कि यह आम तौर पर वांछित व्यवहार है क्योंकि यह एक अनिश्चित धारणा पर बनाया गया है। सुरक्षित रस्ट कोड के भीतर, एक ZST के मूल्य को इंगित करने वालों को अलग करने का कोई कारण नहीं है - क्योंकि केवल एक संभवतः मूल्य है जो संकलन समय पर जाना जाता है। एक बार जैसे ही आप यहां Rust प्रकार प्रणाली के बाहर ZST मान का उपयोग करने की आवश्यकता होती है, यह टूट जाता है। यह संभावना केवल fnआइटम प्रकार और गैर-कैप्चरिंग क्लोजर को प्रभावित करती है और उन लोगों के लिए जो मेरे जवाब के अनुसार एक वर्कअराउंड है, लेकिन यह अभी भी काफी पैर-बंदूक है!
पीटर हॉल

ठीक है, मैंने गितुब मुद्दे पर नई प्रतिक्रियाओं को नहीं पढ़ा था। मुझे उस कोड के साथ सेगफॉल्ट मिल सकता है लेकिन, अगर कोड सेगफॉल्ट का कारण बन सकता है तो मुझे लगता है कि नया व्यवहार ठीक है।
पीटर हॉल

बहुत बढ़िया जवाब। @PeterHall मैं एक ही बात सोच रहा था, और मैं अभी भी इस विषय पर 100% नहीं हूं, लेकिन कम से कम अस्थायी और अन्य स्टैक चर के लिए, 0x1 पर सभी शून्य-आकार के मान रखने में कोई समस्या नहीं होनी चाहिए क्योंकि संकलक कोई नहीं बनाता है स्टैक लेआउट के बारे में गारंटी देता है, और आप वैसे भी ZSTs को संकेत की विशिष्टता की गारंटी नहीं दे सकते। यह, से कहते हैं कि अलग है एक कास्टिंग, *const i32के लिए *const c_voidमेरी समझ के लिए, अभी भी सूचक की पहचान को संरक्षित करने की गारंटी है, जो।
ट्रेंटक्ल

2

किस बात का _अनुमान लगाया जा रहा है और व्यवहार क्यों बदल गया है?

हर बार जब आप एक कच्चा पॉइंटर कास्ट करते हैं, तो आप केवल एक जानकारी (संदर्भ या कच्चे पॉइंटर; म्यूट प्रकार प्रकार) को बदल सकते हैं। इसलिए, यदि आप इस कास्ट करते हैं:

let ptr = &foo as *const _

चूँकि आप कच्चे पॉइंटर के संदर्भ से बदल गए हैं, इस प्रकार के लिए अनुमान लगाया गया अपरिवर्तित _ होना चाहिए और इसलिए यह प्रकार है foo, जो फ़ंक्शन के लिए कुछ अपरिहार्य प्रकार है foo

ऐसा करने के बजाय, आप सीधे एक फ़ंक्शन पॉइंटर में डाल सकते हैं, जो जंग सिंटैक्स में अभिव्यक्त होता है:

let ptr = foo as *const fn() as *const c_void;

क्योंकि यह क्यों बदल गया है, यह कहना मुश्किल है। यह रात के निर्माण में एक बग हो सकता है। यह इसकी रिपोर्ट करने योग्य है - भले ही यह बग नहीं है, आपको कंपाइलर टीम से वास्तव में क्या चल रहा है, इसके बारे में अच्छी व्याख्या मिलेगी!


1
धन्यवाद मैंने इसे github.com/rust-lang/rust/issues/65499
Maciej Goszczycki

@MaciejGoszczycki रिपोर्टिंग के लिए धन्यवाद! प्रतिक्रियाओं ने वास्तव में मेरे लिए स्पष्ट बातें कीं - मैं वहां प्रतिक्रियाओं के आधार पर उत्तर पोस्ट करूंगा।
स्वेन मार्नाच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.