बस त्रुटि क्या है?


254

"बस त्रुटि" संदेश का क्या मतलब है, और यह एक segfault से कैसे भिन्न होता है?


5
मैं दोनों के लिए एक सरल स्पष्टीकरण जोड़ना चाहता हूं: सेगमेंटेशन दोष का मतलब है कि आप उस मेमोरी तक पहुंचने की कोशिश कर रहे हैं जिसे आपको अनुमति नहीं है (जैसे यह आपके प्रोग्राम का हिस्सा नहीं है)। हालांकि, एक बस त्रुटि पर इसका मतलब यह है कि आप स्मृति का उपयोग करने की कोशिश कर रहे हैं जो मौजूद नहीं है (जैसे आप 12 जी पर एक पते तक पहुंचने का प्रयास करते हैं लेकिन आपके पास केवल 8 जी मेमोरी है) या यदि आप उपयोग करने योग्य स्मृति की सीमा से अधिक है।
xdevs23

आपने इसे किस मंच पर देखा? पीसी? मैक? 86? 32/64?
पीटर मोर्टेंसन

जवाबों:


243

बस की गलतियाँ आजकल x86 पर दुर्लभ हैं और तब होती हैं जब आपका प्रोसेसर अनुरोधित मेमोरी एक्सेस का प्रयास नहीं कर सकता है, आमतौर पर:

  • एक पते के साथ एक प्रोसेसर निर्देश का उपयोग करना जो अपनी संरेखण आवश्यकताओं को पूरा नहीं करता है।

स्मृति तक पहुँचते समय विभाजन दोष उत्पन्न होते हैं जो आपकी प्रक्रिया से संबंधित नहीं होते हैं, वे बहुत आम हैं और आमतौर पर इसका परिणाम होता है:

  • किसी चीज़ के लिए एक संकेतक का उपयोग किया गया था जिसे डीलॉल किया गया।
  • एक असंसाधित इसलिए फर्जी सूचक का उपयोग करना।
  • अशक्त सूचक का उपयोग करना।
  • एक बफर बह निकला।

पुनश्च: अधिक सटीक होने के लिए यह पॉइंटर को हेरफेर नहीं कर रहा है जो स्वयं मुद्दों का कारण बनेगा, यह उस मेमोरी तक पहुंच रहा है जो इसे इंगित करता है (डेरेफेरिंग)।


105
वे दुर्लभ नहीं हैं; मैं एक्सरसाइज 9 में हाउ टू लर्न सी से हार्ड वे और पहले से ही एक का सामना कर रहा हूं ...
11684

24
बस त्रुटियों का एक अन्य कारण (वैसे भी लिनक्स पर) है जब ऑपरेटिंग सिस्टम भौतिक मेमोरी के साथ एक वर्चुअल पेज को वापस नहीं कर सकता है (उदाहरण के लिए कम मेमोरी की स्थिति या विशाल पेज मेमोरी का उपयोग करते समय बड़े पृष्ठों से बाहर।) आमतौर पर मिमीप (और मॉलोक)। आभासी पता स्थान आरक्षित करें, और कर्नेल भौतिक स्मृति को मांग पर निर्दिष्ट करता है (जिसे नरम पृष्ठ दोष कहा जाता है।) एक बड़ा पर्याप्त मॉलोक बनाएं, और फिर इसे पर्याप्त रूप से लिखें और आपको एक बस त्रुटि मिलेगी।
एलॉफ़

1
मेरे लिए विभाजन वाला /var/cache
भाग पूर्णतः पूछ रहा

2
मेरे मामले में, एक विधि एक ऑब्जेक्ट को static_castएक void *पैरामीटर को एड करती है जो एक कॉलबैक (एक विशेषता ऑब्जेक्ट और विधि के लिए दूसरा) को संग्रहीत करती है। फिर कॉलबैक कहा जाता है। हालांकि, जैसा कि पारित किया void *गया था वह कुछ पूरी तरह से अलग था और इस प्रकार विधि कॉल ने बस त्रुटि का कारण बना।
क्रिस्टोफर के।

@bltxd क्या आप बस त्रुटियों की प्रकृति जानते हैं। अर्थात रिंग बस के संदेश में कुछ तंत्र होता है जहां रिंग पर एक स्टॉप भी एक संदेश स्वीकार करता है जो इसके द्वारा भेजा गया था, लेकिन जो भी गंतव्य के रूप में यह बताता है कि यह रिंग के चारों ओर चला गया है और स्वीकार नहीं किया गया है। मैं अनुमान लगा रहा हूं कि लाइन फिल बफ़र एक त्रुटि स्थिति देता है और जब यह रिटायर हो जाता है तो यह पाइप लाइन को फ्लश करता है और सही अपवाद माइक्रोट्रॉइन कहता है। यह मूल रूप से आवश्यक है कि मेमोरी कंट्रोलर अपनी सीमा में सभी पते को स्वीकार करे जो यह सुझाव देगा कि जब BAR आदि को बदल दिया जाता है, तो उसे आंतरिक रूप से करना होगा
लुईस केल्सी

84

एक segfault मेमोरी एक्सेस कर रहा है जिसे आपको एक्सेस करने की अनुमति नहीं है। यह केवल पढ़ने के लिए है, आपके पास अनुमति नहीं है, आदि ...

एक बस त्रुटि मेमोरी को एक्सेस करने की कोशिश कर रही है जो संभवतः नहीं हो सकती है। आपने उस पते का उपयोग किया है जो सिस्टम के लिए अर्थहीन है, या उस ऑपरेशन के लिए गलत प्रकार का पता है।


14

mmap न्यूनतम POSIX 7 उदाहरण

"बस त्रुटि" तब होती है जब कर्नेल भेजता है SIGBUS एक प्रक्रिया को है।

एक न्यूनतम उदाहरण जो इसे बनाता है क्योंकि ftruncateइसे भुला दिया गया था:

#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */

int main() {
    int fd;
    int *map;
    int size = sizeof(int);
    char *name = "/a";

    shm_unlink(name);
    fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
    /* THIS is the cause of the problem. */
    /*ftruncate(fd, size);*/
    map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    /* This is what generates the SIGBUS. */
    *map = 0;
}

साथ दौड़ो:

gcc -std=c99 main.c -lrt
./a.out

Ubuntu 14.04 में परीक्षण किया गया।

POSIX का वर्णन इस SIGBUS प्रकार है:

किसी मेमोरी ऑब्जेक्ट के अपरिभाषित हिस्से तक पहुंच।

Mmap कल्पना है कि कहते हैं:

पता सीमा के भीतर संदर्भ देहात पर शुरू होता है और एक वस्तु के अंत के बाद पूरे पृष्ठों को लेन बाइट्स के लिए जारी रखने के परिणामस्वरूप SIGBUS सिग्नल की डिलीवरी होगी।

और shm_open कहते हैं कि यह आकार की वस्तुओं को उत्पन्न करता है 0:

साझा मेमोरी ऑब्जेक्ट का आकार शून्य है।

इसलिए *map = 0हम आवंटित वस्तु के अंत को छू रहे हैं।

ARMv8 anarch64 में बिना स्टैक वाली मैमोरी एक्सेस

यह उल्लेख किया गया था: एक बस त्रुटि क्या है? SPARC के लिए, लेकिन यहां मैं एक अधिक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण प्रदान करूंगा।

आप सभी की जरूरत है एक फ्रीस्टैंडिंग अराजकता 64 कार्यक्रम है:

.global _start
_start:
asm_main_after_prologue:
    /* misalign the stack out of 16-bit boundary */
    add sp, sp, #-4
    /* access the stack */
    ldr w0, [sp]

    /* exit syscall in case SIGBUS does not happen */
    mov x0, 0
    mov x8, 93
    svc 0

उस कार्यक्रम के बाद उबंटू 18.04 अनार्च 64, थिसॉरस Linux5 कर्नेल 4.15.0 थंडरएक्स 2 सर्वर मशीन में SIGBUS उठाता है

दुर्भाग्य से, मैं इसे QEMU v4.0.0 उपयोगकर्ता मोड पर पुन: पेश नहीं कर सकता, मुझे यकीन नहीं है कि क्यों।

गलती वैकल्पिक और के द्वारा नियंत्रित हो गया लगता है SCTLR_ELx.SAऔर SCTLR_EL1.SA0खेतों, मैं संबंधित दस्तावेज़ों का संक्षेपण किया है थोड़ा आगे यहाँ


11

मेरा मानना ​​है कि जब कोई एप्लिकेशन डेटा बस में डेटा मिसलिग्न्मेंट प्रदर्शित करता है तो कर्नेल SIGBUS उठाता है। मुझे लगता है कि चूंकि अधिकांश [?] अधिकांश प्रोसेसर के लिए आधुनिक कंपाइलर प्रोग्रामर के लिए डेटा को संरेखित / संरेखित करते हैं, योर के संरेखण की परेशानी (कम से कम) कम हो जाती है, और इसलिए कोई भी इन दिनों (एएफआईआईके) को बहुत ज्यादा नहीं देखता है।

प्रेषक: यहाँ से


1
आप अपने कोड के साथ कर रहे हैं बुरा चाल पर निर्भर करता है। यदि आप कुछ मूर्खतापूर्ण काम करते हैं जैसे कि पॉइंटर गणित और फिर टाइपकास्ट करने के लिए समस्या मोड (यानी आपने uint8_t सरणी सेट की है, तो एक, दो, या तीन को सरणी के पॉइंटर में जोड़ें और फिर टाइपकास्ट टाइप करें) आप एक बस त्रुटि / संरेखण ट्रैप को ट्रिगर कर सकते हैं। एक छोटे, int, या लंबे और आपत्तिजनक परिणाम तक पहुँचने का प्रयास करें।) X86 सिस्टम आपको वास्तव में ऐसा करने देगा, जो वास्तविक प्रदर्शन के दंड के रूप में होगा। कुछ ARMv7 सिस्टम आपको ऐसा करने देंगे- लेकिन अधिकांश ARM, MIPS, Power, आदि आपको इस पर जोर देंगे।
Svartalf

6

जब किसी कारण से कोड पृष्ठ को पृष्ठांकित नहीं किया जा सकता है तो आप SIGBUS भी प्राप्त कर सकते हैं।


7
यह अक्सर तब होता है जब मैं प्रक्रिया को चलाते समय .so फ़ाइल को अपडेट करता हूं
poordeveloper

ऐसा होने का एक अन्य कारण यह है कि यदि आप mmapफ़ाइल का आकार/dev/shm
ilija139

3

ओएस एक्स पर प्रोग्रामिंग करते समय बस में आई एक त्रुटि का एक विशिष्ट उदाहरण:

#include <string.h>
#include <stdio.h>

int main(void)
{
    char buffer[120];
    fgets(buffer, sizeof buffer, stdin);
    strcat("foo", buffer);
    return 0;
}

यदि आपको याद नहीं है कि डॉक्स strcatने पहले तर्क को बदलकर दूसरा तर्क दिया है (तर्कों को फ्लिप करें और यह ठीक काम करता है)। लिनक्स पर यह एक विभाजन दोष देता है (जैसा कि अपेक्षित है), लेकिन ओएस एक्स पर यह एक बस त्रुटि देता है। क्यों? मैं वास्तव में नहीं जानता।


संभवतः स्टैक ओवरफ्लो सुरक्षा बस त्रुटि उठाती है।
यहोशू

1
"foo"मेमोरी के केवल-पढ़ने वाले खंड में संग्रहीत किया जाता है, इसलिए इसे लिखना असंभव है। यह स्टैक ओवरफ्लो संरक्षण नहीं होगा, बस मेमोरी राइट प्रोटेक्शन (यह एक सुरक्षा छेद है यदि आपका प्रोग्राम खुद को फिर से लिख सकता है)।
मार्क लकाटा

3

बस त्रुटि का एक क्लासिक उदाहरण कुछ आर्किटेक्चर पर है, जैसे कि SPARC (कम से कम कुछ SPARCs, शायद इसे बदल दिया गया है), जब आप गलत संरेखित एक्सेस करते हैं। उदाहरण के लिए:

unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;

यह स्निपेट 32-बिट पूर्णांक मान 0xdeadf00dको एक पते पर लिखने की कोशिश करता है जो (सबसे अधिक संभावना है) ठीक से संरेखित नहीं है, और इस संबंध में "picky" हैं आर्किटेक्चर पर एक बस त्रुटि उत्पन्न करेगा। इंटेल x86 वैसे, यह है, नहीं इस तरह के एक वास्तुकला, यह एक्सेस (यद्यपि यह अधिक धीरे धीरे निष्पादित) की अनुमति होगी।


1
मामले में, मेरे पास डेटा [8] था; यह अब 32-बिट आर्किटेक्चर में 4 के कई है। तो, यह गठबंधन है। क्या मुझे अब भी त्रुटि मिलेगी? इसके अलावा, कृपया समझाएं, क्या यह पॉइंटर्स के लिए डेटा टाइप रूपांतरण के लिए एक बुरा विचार है। क्या यह एक नाजुक वास्तुकला पर गलत संरेखण त्रुटियों का कारण होगा। कृपया विस्तृत करें, यह मेरी मदद करेगा।
निपुण

हे। यह इतना प्रकार का रूपांतरण नहीं है जितना कि आप एक पॉइंटर पर टाइप रूपांतरण कर रहे हैं जिस पर आपने पॉइंटर गणित किया है। ऊपर दिए गए कोड को ध्यान से देखें । कंपाइलर ने डेटा के लिए आपके पॉइंटर को सावधानी से संयोजित किया है- और फिर आप TWO द्वारा संदर्भ को ऑफसेट करके कंपाइलर पर सब कुछ पेंच कर देते हैं और एक गैर-डॉर्ड बाउंड्री होने जा रही है, जिस पर डॉर्ड एलाइड होने की आवश्यकता होती है।
Svartalf

"फ्रैगाइल" यह शब्द नहीं है जो मैं इस सब के लिए उपयोग करूंगा। X86 मशीनों और कोड ने लोगों को कुछ समय के लिए मूर्खतापूर्ण चीजें करने के लिए मिला है, यह उनमें से एक है। इस तरह की समस्या होने पर अपने कोड को रीथिंक करें- यह X86 पर शुरू करने के लिए बहुत अच्छा नहीं है।
Svartalf

@Svartalf: x86 पर, अलिखित बिंदुओं पर शब्द अभिगम निश्चित रूप से संरेखित बिंदुओं तक शब्द अभिगम की तुलना में धीमा है, लेकिन कम से कम ऐतिहासिक रूप से वे सरल कोड की तुलना में तेज़ हैं जो बिना किसी चीज़ के बाइट्स से असेंबल करते हैं, और वे कोड की तुलना में निश्चित रूप से सरल होते हैं जो कोशिश करता है विभिन्न आकार के संचालन के एक इष्टतम संयोजन का उपयोग करने के लिए। मैं चाहता हूं कि सी मानक में छोटे पूर्णांक / वर्णों के अनुक्रम से / बड़े पूर्णांक प्रकारों को पैक करने / अनपैक करने के साधन शामिल होंगे ताकि संकलक को किसी दिए गए प्लेटफॉर्म पर जो भी दृष्टिकोण सबसे अच्छा हो उसका उपयोग करने दिया जा सके।
सुपरकैट

@Supercat: बात यह है- आप X86 पर इसके साथ भाग जाते हैं। आप एआरएम, एमआइपी, पावर आदि पर यह कोशिश करते हैं और आप को घटिया चीजें मिल रही हैं। एआरएम वी 7 से कम एआरएम पर, आपके पास एक कोड की विफलता होगी - और वी 7 पर, आप कर सकते हैं, यदि आपका रनटाइम इसके लिए सेट है, तो इसे एक सेवर प्रदर्शन हिट के साथ संभाल लें। आप बस इसे करना नहीं चाहते हैं। यह बुरा व्यवहार है, कुंद होना। : D
Svartalf

2

यह आपके ओएस, सीपीयू, कंपाइलर और संभवतः अन्य कारकों पर निर्भर करता है।

सामान्य तौर पर इसका मतलब है कि सीपीयू बस एक कमांड को पूरा नहीं कर सकता है, या एक संघर्ष का सामना कर सकता है, लेकिन इसका मतलब पर्यावरण और कोड के आधार पर चलने वाली चीजों की एक पूरी श्रृंखला हो सकती है।

-Adam


2

यह सामान्य रूप से एक संयुक्त गठबंधन का मतलब है।

भौतिक रूप से मौजूद मेमोरी को एक्सेस करने का प्रयास भी एक बस त्रुटि देगा, लेकिन अगर आप एक MMU और OS के साथ एक प्रोसेसर का उपयोग कर रहे हैं तो आपको यह दिखाई नहीं देगा कि छोटी गाड़ी नहीं है, क्योंकि आपके पास कोई गैर नहीं होगा आपकी प्रक्रिया के पते स्थान पर मैप की गई निरंतर मेमोरी।


2
मेरे i7 में निश्चित रूप से एक एमएमयू है, लेकिन मैं अभी भी ओएस एक्स पर सी सीखते समय इस त्रुटि के पार आया था (असिंचित सूचक को पास करना scanf)। इसका मतलब यह है कि OS X Mavericks छोटी गाड़ी है? एक गैर-छोटी गाड़ी ओएस पर व्यवहार क्या होता है?
केल्विन हुआंग

2

रूट डायरेक्टरी 100% होने पर मुझे एक बस त्रुटि हो रही थी।


1

मैक ओएस एक्स पर बस की त्रुटि का मेरा कारण यह था कि मैंने स्टैक पर लगभग 1Mb आवंटित करने का प्रयास किया था। यह एक सूत्र में अच्छी तरह से काम करता है, लेकिन जब ओपनएमपी इस ड्राइव का उपयोग बस त्रुटि में करता है, क्योंकि मैक ओएस एक्स में गैर-मुख्य थ्रेड्स के लिए बहुत सीमित स्टैक आकार है


1

मैं उपरोक्त सभी उत्तरों से सहमत हूं। यहाँ मेरे 2 सेंट बस त्रुटि के बारे में हैं:

कार्यक्रम के कोड के भीतर निर्देशों से एक बस त्रुटि उत्पन्न नहीं होनी चाहिए। यह तब हो सकता है जब आप एक बाइनरी चला रहे हों और निष्पादन के दौरान, बाइनरी को संशोधित किया गया हो (एक निर्माण या हटाए गए आदि द्वारा अधिलेखित)।

यदि यह मामला है तो सत्यापित करना: यह जांचने का एक सरल तरीका है कि क्या यह कारण एक ही बाइनरी के रनिंग इंस्टेंस को लॉन्च करने और बिल्ड को चलाने के लिए है। दोनों चल उदाहरण एक के साथ दुर्घटना होगीSIGBUSनिर्माण के समाप्त होने और बाइनरी को बदलने के बाद त्रुटि के (वर्तमान में दोनों इंस्टेंसेस रन करने वाले एक हैं)

अंतर्निहित कारण: यह इसलिए है क्योंकि OS मेमोरी पेजों को स्वैप करता है और कुछ मामलों में बाइनरी पूरी तरह से मेमोरी में लोड नहीं हो सकती है और ये क्रैश तब होंगे जब ओएस अगले पेज को उसी बाइनरी से लाने की कोशिश करेगा, लेकिन बाइनरी पिछले दिनों से बदल गई है इसे पढ़ें।


सहमत, यह मेरे अनुभव में बस त्रुटियों का सबसे आम कारण है।
itaych

0

ऊपर बताए गए ब्लॅक्सडैट में जोड़ने के लिए, बस त्रुटियां तब भी होती हैं जब आपकी प्रक्रिया किसी विशेष 'चर' की मेमोरी तक पहुंचने का प्रयास नहीं कर सकती है

for (j = 0; i < n; j++) {
    for (i =0; i < m; i++) {
        a[n+1][j] += a[i][j];
    }
}

सूचना ' अनजाने का' उपयोग 'मैं' चर में 'पाश के लिए' पहले? यही कारण है कि इस मामले में बस त्रुटि हो रही है।


यदि m> = n है, तो बाहरी लूप एक बार या बिल्कुल भी निष्पादित नहीं करेगा, जो कि i के preexisting मूल्य पर निर्भर करता है। यदि m <n तब यह अनिश्चित रूप से j इंडेक्स के बढ़ने के साथ चलेगा, जब तक कि आप अपने एरे की सीमा से बाहर नहीं निकलेंगे और सबसे अधिक संभावना एक विभाजन त्रुटि का कारण होगी, न कि एक बस त्रुटि। यदि यह कोड संकलित करता है तो चर 'i' की मेमोरी तक पहुँचने में कोई समस्या नहीं है। क्षमा करें, लेकिन यह उत्तर गलत है।
itaych

0

मुझे अभी यह पता चला है कि ARMv7 प्रोसेसर पर आप कुछ कोड लिख सकते हैं जो आपको अडॉप्ट किए जाने पर एक विभाजन दोष देता है, लेकिन -O2 के साथ संकलित होने पर यह आपको एक बस त्रुटि देता है (अधिक ऑप्टिमाइज़ करें)।

मैं उबंटू 64 बिट से GCC ARM gnueabihf क्रॉस कंपाइलर का उपयोग कर रहा हूं।


यह प्रश्न का उत्तर कैसे देता है?
पीटर मोर्टेंसन

-1

एक सामान्य बफर अतिप्रवाह जिसके परिणामस्वरूप बस त्रुटि होती है,

{
    char buf[255];
    sprintf(buf,"%s:%s\n", ifname, message);
}

यहाँ अगर डबल कोट्स ("") में स्ट्रिंग का आकार बुफ़ के आकार से अधिक है तो यह बस त्रुटि देता है।


1
हेह ... अगर ऐसा होता, तो आप विंडोज और अन्य मशीनों के लिए हर समय पढ़े जाने वाले स्टैक स्मैशिंग कारनामों के बदले बस त्रुटि की चिंताएं करते। बस "मेमोरी" को एक्सेस करने के प्रयास के कारण बस त्रुटियों का कारण बनता है कि मशीन केवल इसलिए एक्सेस नहीं कर सकती क्योंकि पता अमान्य है। (इसलिए "बस" त्रुटि शब्द।) यह अवैध संरेखण सहित विफलताओं के एक मेजबान के कारण हो सकता है, और जैसे- जब तक प्रोसेसर बस लाइनों पर पता नहीं लगा सकता है।
Svartalf
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.