किसी फ़ंक्शन से संरचना लौटते समय संभावित जीसीसी बग


133

मेरा मानना ​​है कि मुझे ओ'नील के पीसीजी पीआरएनजी को लागू करते समय जीसीसी में एक बग मिला। ( गॉडबोल्ट के कंपाइलर एक्सप्लोरर पर प्रारंभिक कोड )

गुणा करने के बाद oldstateसे MULTIPLIER, (आरडीआई में संग्रहीत परिणाम), जीसीसी है कि परिणाम नहीं जोड़ता है INCREMENT, movabs'ing INCREMENTबजाय RDX के लिए है, जो तब rand32_ret.state की वापसी मान के रूप में इस्तेमाल किया जाता है

एक न्यूनतम प्रजनन योग्य उदाहरण ( कंपाइलर एक्सप्लोरर ):

#include <stdint.h>

struct retstruct {
    uint32_t a;
    uint64_t b;
};

struct retstruct fn(uint64_t input)
{
    struct retstruct ret;

    ret.a = 0;
    ret.b = input * 11111111111 + 111111111111;

    return ret;
}

निर्मित विधानसभा (GCC 9.2, x86_64, -O3):

fn:
  movabs rdx, 11111111111     # multiplier constant (doesn't fit in imm32)
  xor eax, eax                # ret.a = 0
  imul rdi, rdx
  movabs rdx, 111111111111    # add constant; one more 1 than multiplier
     # missing   add rdx, rdi   # ret.b=... that we get with clang or older gcc
  ret
# returns RDX:RAX = constant 111111111111 : 0
# independent of input RDI, and not using the imul result it just computed

दिलचस्प है, पहले सदस्य के रूप में uint64_t के लिए संरचना को संशोधित करना सही कोड का उत्पादन करता है , जैसा कि दोनों सदस्यों को uint64_t में बदलना

x86-64 सिस्टम V RDX में 16 बाइट्स से छोटे स्ट्रक्चर्स को लौटाता है: RAX, जब वे तुच्छ रूप से कॉपी करने योग्य होते हैं। इस मामले में दूसरा सदस्य RDX में है क्योंकि RAX का उच्च आधा संरेखण या .bजब के लिए पैडिंग है.a एक संकीर्ण प्रकार है। ( sizeof(retstruct)16 या तो रास्ता है; हम इसका उपयोग नहीं कर रहे हैं, __attribute__((packed))इसलिए यह alignof (uint64_t) = 8 का सम्मान करता है।)

क्या इस कोड में कोई अपरिभाषित व्यवहार है जो GCC को "गलत" असेंबली से बाहर निकालने की अनुमति देगा?

यदि नहीं, तो इसे https://gcc.gnu.org/bugzilla/ पर सूचित किया जाना चाहिए


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
शमूएल ल्यू

जवाबों:


102

मैं यहाँ कोई UB नहीं देखता; आपके प्रकार अहस्ताक्षरित हैं इसलिए हस्ताक्षरित-अतिप्रवाह UB असंभव है, और कुछ भी अजीब नहीं है। (और यहां तक ​​कि अगर हस्ताक्षर किए गए हैं, तो यह इनपुट के लिए सही आउटपुट का उत्पादन करना होगा जो नहीं करते हैं UB, जैसे अतिप्रवाह का कारण हैं rdi=1)। यह GCC के C ++ फ्रंट-एंड के साथ भी टूट गया है।

इसके अलावा, GCC8.2 AAAch64 और RISC-V के लिए इसे सही ढंग से संकलित करता है ( maddउपयोग करने के बाद एक निर्देश परmovk स्थिरांक, या RISC-V करने और स्थिरांक को लोड करने के बाद जोड़ने के लिए)। यदि यह UB था जो GCC ढूंढ रहा था, तो हम आम तौर पर यह अपेक्षा करते हैं कि इसे खोजने के लिए और अन्य ISAs के लिए आपके कोड को तोड़ने के साथ-साथ कम से कम जिनके पास समान प्रकार की चौड़ाई और रजिस्टर चौड़ाई हो।

क्लैंग भी इसे सही ढंग से संकलित करता है।

यह जीसीसी 5 से 6 तक प्रतिगमन प्रतीत होता है; GCC5.4 संकलन सही ढंग से, 6.1 और बाद में नहीं है। ( गॉडबोल्ट )।

आप अपने प्रश्न से MCVE का उपयोग करके जीसीसी की बगज़िला पर इसकी रिपोर्ट कर सकते हैं ।

यह वास्तव में ऐसा लगता है कि यह x86-64 सिस्टम V स्ट्रक्चर-रिटर्न हैंडलिंग में एक बग है, शायद पैडिंग वाले स्ट्रक्चर्स का। यह समझाता है कि यह क्यों काम करता है जब इनलाइनिंग करता है, और जब auint64_t (पैडिंग से बचने) के लिए चौड़ा होता है।



11
@vitorhnn लगता है जैसे यह तय हो गया है master
एसएस ऐनी

19

इस पर तय किया गया है trunk/ master

यहाँ प्रासंगिक है

और इस मुद्दे को ठीक करने के लिए एक पैच है।

पैच में एक टिप्पणी के आधार पर, reload_combine_recognize_patternफ़ंक्शन यूएसई इंसन्स को समायोजित करने की कोशिश कर रहा था ।


14

क्या इस कोड में कोई अपरिभाषित व्यवहार है जो GCC को "गलत" असेंबली से बाहर निकालने की अनुमति देगा?

प्रश्न में प्रस्तुत कोड का व्यवहार C99 और बाद के C भाषा मानकों के संबंध में अच्छी तरह से परिभाषित है। विशेष रूप से, सी प्रतिबंध के बिना संरचना मूल्यों को वापस करने के लिए कार्य करता है।


2
जीसीसी फ़ंक्शन की एक स्टैंड-अलोन परिभाषा का उत्पादन करता है; यह वही है जो हम देख रहे हैं, चाहे वह वही हो जो तब चलता है जब आप इसे अनुवाद इकाई में अन्य कार्यों के साथ संकलित करते हैं। आप बस इसे आसानी से वास्तव में इसका उपयोग __attribute__((noinline))करके बिना अनुवाद इकाई में संकलन करके और LTO के बिना लिंक करके, या यह संकलन कर सकते हैं, -fPICजिसका अर्थ है कि सभी वैश्विक प्रतीक (डिफ़ॉल्ट रूप से) हैं, जो कि प्रयोज्य अंतःक्षिप्त नहीं हैं। लेकिन वास्तव में समस्या केवल फोन करने वालों की परवाह किए बिना उत्पन्न आसम को देखने से पता लगाने योग्य है।
पीटर कॉर्डेस

काफी हद तक, @PeterCordes, हालांकि मुझे पूरा विश्वास है कि यह विस्तार मुझे गॉडबोल्ट में मेरे नीचे से बदल दिया गया था।
जॉन बोलिंगर

प्रश्न का संस्करण 1 गॉडबोल्ट से जुड़ा हुआ है, केवल अनुवाद इकाई में ही कार्य करता है, जैसे प्रश्न का उत्तर जब आप उत्तर देते हैं। मैंने उन सभी संशोधनों या टिप्पणियों की जाँच नहीं की जिन्हें आप देख रहे थे। पुल के नीचे पानी, लेकिन मुझे नहीं लगता कि कभी दावा किया गया था कि स्रोत के उपयोग के दौरान स्टैंड-अलोन एएसएम परिभाषा केवल टूट गई थी __attribute__((noinline))। (यह चौंकाने वाला होगा, न कि जिस तरह से एक जीसीसी शुद्धता बग आश्चर्यचकित है)। संभवतः जिसका उल्लेख केवल एक परीक्षण करने वाले के लिए किया गया था जो परिणाम प्रिंट करता है।
पीटर कॉर्डेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.