बहु आयामी सरणी से गणना मूल्य स्वयं के बराबर क्यों नहीं है?


151

विचार करें:

using System;

public class Test
{
    enum State : sbyte { OK = 0, BUG = -1 }

    static void Main(string[] args)
    {
        var s = new State[1, 1];
        s[0, 0] = State.BUG;
        State a = s[0, 0];
        Console.WriteLine(a == s[0, 0]); // False
    }
}

इसे कैसे समझाया जा सकता है? यह x86 JIT में चलने पर Visual Studio 2015 में डीबग बनाता है। एक्स 64 जेआईटी में एक रिलीज बिल्ड या रनिंग सच के रूप में अपेक्षित है।

कमांड लाइन से पुन: उत्पन्न करने के लिए:

csc Test.cs /platform:x86 /debug

( /debug:pdbonly, /debug:portableऔर /debug:fullप्रजनन भी।)


2
ideone.com/li3EzY यह सच है। .net संस्करण, IDE, संकलक के बारे में अधिक जानकारी जोड़ें
बैक

1
मुझे भी। लेकिन परियोजना सेटिंग्स के साथ फ़िदा होने के बाद मुझे लगा कि "बिल्ड" टैब में "32 बिट" चेकबॉक्स को अनचेक करने से यह उद्देश्य के रूप में काम करता है - सच वापस लौट रहा है। तो, यह मेरे लिए एक WoW64 मुद्दे की तरह लग रहा है।
दिमित्री रोटे

2
ऐसा लगता है कि आपने ढांचे में एक बग को इंगित किया है।
फेबियन पेर्रोननेट

1
दिलचस्प है, के माध्यम से टूटी हुई कोड को चलाने ildasmऔर फिर ilasmइसे "ठीक" करता है ...
जॉन स्कीट

2
/debug=IMPLझंडा पत्तियों यह टूटा; /debug=OPTइसे "ठीक करता है"।
जॉन स्कीट

जवाबों:


163

आपको .NET 4 x86 के घबराने में एक कोड जेनरेशन बग मिला। यह एक बहुत ही असामान्य है, यह केवल तब विफल होता है जब कोड अनुकूलित नहीं होता है। मशीन कोड इस तरह दिखता है:

        State a = s[0, 0];
013F04A9  push        0                            ; index 2 = 0
013F04AB  mov         ecx,dword ptr [ebp-40h]      ; s[] reference
013F04AE  xor         edx,edx                      ; index 1 = 0
013F04B0  call        013F0058                     ; eax = s[0, 0]
013F04B5  mov         dword ptr [ebp-4Ch],eax      ; $temp1 = eax 
013F04B8  movsx       eax,byte ptr [ebp-4Ch]       ; convert sbyte to int
013F04BC  mov         dword ptr [ebp-44h],eax      ; a = s[0, 0]
        Console.WriteLine(a == s[0, 0]); // False
013F04BF  mov         eax,dword ptr [ebp-44h]      ; a
013F04C2  mov         dword ptr [ebp-50h],eax      ; $temp2 = a
013F04C5  push        0                            ; index 2 = 0
013F04C7  mov         ecx,dword ptr [ebp-40h]      ; s[] reference 
013F04CA  xor         edx,edx                      ; index 1 = 0
013F04CC  call        013F0058                     ; eax = s[0, 0]
013F04D1  mov         dword ptr [ebp-54h],eax      ; $temp3 = eax 
                                               ; <=== Bug here!
013F04D4  mov         eax,dword ptr [ebp-50h]      ; a == s[0, 0] 
013F04D7  cmp         eax,dword ptr [ebp-54h]  
013F04DA  sete        cl  
013F04DD  movzx       ecx,cl  
013F04E0  call        731C28F4  

बहुत सारे टेम्पोररी और कोड डुप्लीकेशन के साथ एक प्लोडिंग अफेयर, यह अडॉप्ट किए गए कोड के लिए सामान्य है। 013F04B8 पर निर्देश उल्लेखनीय है, यही वह जगह है जहां 32-बिट पूर्णांक से sbyte से आवश्यक रूपांतरण होता है। सरणी गेट्टर हेल्पर फ़ंक्शन स्टेट के बराबर 0x0000000FF लौटा दिया। बग, और मान को तुलना करने से पहले इसे -1 (0xFFFFFFFFFF) में बदलने की आवश्यकता है। MOVSX इंस्ट्रक्शन एक साइन एक्सटेन्शन इंस्ट्रक्शन है।

समान बात 013F04CC पर फिर से होती है, लेकिन इस बार एक ही रूपांतरण करने के लिए कोई MOVSX निर्देश नहीं है । जहां चिप्स नीचे गिरता है, सीएमपी निर्देश 0xFFFFFFFF की तुलना 0x000000FF से करता है और यह गलत है। तो यह चूक की एक त्रुटि है, कोड जेनरेटर MOVSX को फिर से वही रूपांतरण करने के लिए एमवायएसएक्स से बाहर निकलने में विफल रहा।

इस बग के बारे में विशेष रूप से असामान्य है कि यह सही ढंग से काम करता है जब आप अनुकूलक को सक्षम करते हैं, तो अब यह दोनों मामलों में MOVSX का उपयोग करना जानता है।

संभावित कारण यह है कि यह बग इतने लंबे समय के लिए अनिच्छुक हो गया था क्योंकि यह ईनम का आधार प्रकार है। काफी दुर्लभ है। बहु-आयामी सरणी का उपयोग करना महत्वपूर्ण है और साथ ही, संयोजन घातक है।

नहीं तो एक बहुत महत्वपूर्ण बग मैं कहूँगा। कितना व्यापक हो सकता है यह अनुमान लगाना कठिन है, मेरे पास परीक्षण करने के लिए केवल 4.6.1 x86 घबराना है। X64 और 3.5 x86 घबराना बहुत अलग कोड उत्पन्न करते हैं और इस बग से बचते हैं। अस्थायी रूप से चलते रहने का तरीका यह है कि Enum बेस टाइप के रूप में sbyte को हटा दिया जाए और इसे डिफ़ॉल्ट, int के रूप में होने दिया जाए , इसलिए कोई साइन एक्सटेंशन आवश्यक नहीं है।

आप बग को connect.microsoft.com पर दर्ज कर सकते हैं, इस Q + A से लिंक करना उन्हें सब कुछ बताने के लिए पर्याप्त होना चाहिए जो उन्हें जानना आवश्यक है। मुझे बताएं कि क्या आप समय नहीं लेना चाहते हैं और मैं इसका ध्यान रखूंगा।


33
ऐसे अजीब मुद्दे के सटीक कारण के साथ अच्छा, ठोस डेटा, हमेशा पढ़ने के लिए एक खुशी, +1।
लास वी। कार्लसन

11
कृपया connect.microsoft.com लेख के लिए एक लिंक पोस्ट करें ताकि हम उसे वोट कर सकें।
हंस पैसेंट

मुझे लगता है कि byteइसके बजाय का उपयोग sbyteकरना ठीक होना चाहिए और बेहतर हो सकता है यदि वास्तविक कोड का उपयोग ओआरएम के साथ किया जाता है जहां आप डेटाबेस में अपने झंडे को अतिरिक्त स्थान नहीं लेना चाहते हैं।
वू

6
मैं कनेक्ट करने के बजाय डॉटनेट / कॉर्केल पर बग पोस्ट करूँगा, आप सीधे जेआईटी देवों से मिलेंगे।
लुकास ट्रेजेनिव्स्की

8
मैं Microsoft पर JIT टीम में एक देव हूँ। मैंने बग को पुन: पेश किया है और आंतरिक रूप से इसके लिए एक मुद्दा खोला है (शिपिंग x86 JIT अभी तक गीथब में खुले में नहीं है)। जब यह तय हो जाएगा, तो समय के संदर्भ में, मुझे आशा है कि हमारे पास यह उपकरण के अगले प्रमुख रिलीज में शामिल फिक्स होगा। यदि इस बग का व्यावसायिक प्रभाव हो रहा है, और आपको पहले से ठीक करने की आवश्यकता है, तो कृपया कनेक्ट (connect.microsoft.com) समस्या दर्ज करें ताकि हम प्रभाव देख सकें और हमें आपको ठीक करने के लिए क्या विकल्प मिलेंगे।
रसेल सी। हैडली

8

आइए ओपी की घोषणा पर विचार करें:

enum State : sbyte { OK = 0, BUG = -1 }

चूंकि बग केवल तब होता है जब BUGनकारात्मक (-128) से -1 तक होता है और राज्य हस्ताक्षरित बाइट का एक प्रतीक है, मुझे लगता है कि कहीं न कहीं एक कच्चा मुद्दा था।

यदि आप इसे चलाते हैं:

Console.WriteLine((sbyte)s[0, 0]);
Console.WriteLine((sbyte)State.BUG);
Console.WriteLine(s[0, 0]);
unchecked
{
    Console.WriteLine((byte) State.BUG);
}

यह उत्पादन होगा:

255

-1

बग

255

इस कारण से कि मैं उपेक्षा करता हूं (अब के रूप में) s[0, 0] मूल्यांकन से पहले एक बाइट के लिए डाली जाती है और इसलिए यह दावा करता a == s[0,0]है कि यह गलत है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.