"बस त्रुटि" संदेश का क्या मतलब है, और यह एक segfault से कैसे भिन्न होता है?
"बस त्रुटि" संदेश का क्या मतलब है, और यह एक segfault से कैसे भिन्न होता है?
जवाबों:
बस की गलतियाँ आजकल x86 पर दुर्लभ हैं और तब होती हैं जब आपका प्रोसेसर अनुरोधित मेमोरी एक्सेस का प्रयास नहीं कर सकता है, आमतौर पर:
स्मृति तक पहुँचते समय विभाजन दोष उत्पन्न होते हैं जो आपकी प्रक्रिया से संबंधित नहीं होते हैं, वे बहुत आम हैं और आमतौर पर इसका परिणाम होता है:
पुनश्च: अधिक सटीक होने के लिए यह पॉइंटर को हेरफेर नहीं कर रहा है जो स्वयं मुद्दों का कारण बनेगा, यह उस मेमोरी तक पहुंच रहा है जो इसे इंगित करता है (डेरेफेरिंग)।
static_cast
एक void *
पैरामीटर को एड करती है जो एक कॉलबैक (एक विशेषता ऑब्जेक्ट और विधि के लिए दूसरा) को संग्रहीत करती है। फिर कॉलबैक कहा जाता है। हालांकि, जैसा कि पारित किया void *
गया था वह कुछ पूरी तरह से अलग था और इस प्रकार विधि कॉल ने बस त्रुटि का कारण बना।
एक segfault मेमोरी एक्सेस कर रहा है जिसे आपको एक्सेस करने की अनुमति नहीं है। यह केवल पढ़ने के लिए है, आपके पास अनुमति नहीं है, आदि ...
एक बस त्रुटि मेमोरी को एक्सेस करने की कोशिश कर रही है जो संभवतः नहीं हो सकती है। आपने उस पते का उपयोग किया है जो सिस्टम के लिए अर्थहीन है, या उस ऑपरेशन के लिए गलत प्रकार का पता है।
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
खेतों, मैं संबंधित दस्तावेज़ों का संक्षेपण किया है थोड़ा आगे यहाँ ।
मेरा मानना है कि जब कोई एप्लिकेशन डेटा बस में डेटा मिसलिग्न्मेंट प्रदर्शित करता है तो कर्नेल SIGBUS उठाता है। मुझे लगता है कि चूंकि अधिकांश [?] अधिकांश प्रोसेसर के लिए आधुनिक कंपाइलर प्रोग्रामर के लिए डेटा को संरेखित / संरेखित करते हैं, योर के संरेखण की परेशानी (कम से कम) कम हो जाती है, और इसलिए कोई भी इन दिनों (एएफआईआईके) को बहुत ज्यादा नहीं देखता है।
प्रेषक: यहाँ से
जब किसी कारण से कोड पृष्ठ को पृष्ठांकित नहीं किया जा सकता है तो आप SIGBUS भी प्राप्त कर सकते हैं।
mmap
फ़ाइल का आकार/dev/shm
ओएस एक्स पर प्रोग्रामिंग करते समय बस में आई एक त्रुटि का एक विशिष्ट उदाहरण:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
यदि आपको याद नहीं है कि डॉक्स strcat
ने पहले तर्क को बदलकर दूसरा तर्क दिया है (तर्कों को फ्लिप करें और यह ठीक काम करता है)। लिनक्स पर यह एक विभाजन दोष देता है (जैसा कि अपेक्षित है), लेकिन ओएस एक्स पर यह एक बस त्रुटि देता है। क्यों? मैं वास्तव में नहीं जानता।
"foo"
मेमोरी के केवल-पढ़ने वाले खंड में संग्रहीत किया जाता है, इसलिए इसे लिखना असंभव है। यह स्टैक ओवरफ्लो संरक्षण नहीं होगा, बस मेमोरी राइट प्रोटेक्शन (यह एक सुरक्षा छेद है यदि आपका प्रोग्राम खुद को फिर से लिख सकता है)।
बस त्रुटि का एक क्लासिक उदाहरण कुछ आर्किटेक्चर पर है, जैसे कि SPARC (कम से कम कुछ SPARCs, शायद इसे बदल दिया गया है), जब आप गलत संरेखित एक्सेस करते हैं। उदाहरण के लिए:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
यह स्निपेट 32-बिट पूर्णांक मान 0xdeadf00d
को एक पते पर लिखने की कोशिश करता है जो (सबसे अधिक संभावना है) ठीक से संरेखित नहीं है, और इस संबंध में "picky" हैं आर्किटेक्चर पर एक बस त्रुटि उत्पन्न करेगा। इंटेल x86 वैसे, यह है, नहीं इस तरह के एक वास्तुकला, यह एक्सेस (यद्यपि यह अधिक धीरे धीरे निष्पादित) की अनुमति होगी।
यह सामान्य रूप से एक संयुक्त गठबंधन का मतलब है।
भौतिक रूप से मौजूद मेमोरी को एक्सेस करने का प्रयास भी एक बस त्रुटि देगा, लेकिन अगर आप एक MMU और OS के साथ एक प्रोसेसर का उपयोग कर रहे हैं तो आपको यह दिखाई नहीं देगा कि छोटी गाड़ी नहीं है, क्योंकि आपके पास कोई गैर नहीं होगा आपकी प्रक्रिया के पते स्थान पर मैप की गई निरंतर मेमोरी।
scanf
)। इसका मतलब यह है कि OS X Mavericks छोटी गाड़ी है? एक गैर-छोटी गाड़ी ओएस पर व्यवहार क्या होता है?
मैक ओएस एक्स पर बस की त्रुटि का मेरा कारण यह था कि मैंने स्टैक पर लगभग 1Mb आवंटित करने का प्रयास किया था। यह एक सूत्र में अच्छी तरह से काम करता है, लेकिन जब ओपनएमपी इस ड्राइव का उपयोग बस त्रुटि में करता है, क्योंकि मैक ओएस एक्स में गैर-मुख्य थ्रेड्स के लिए बहुत सीमित स्टैक आकार है ।
मैं उपरोक्त सभी उत्तरों से सहमत हूं। यहाँ मेरे 2 सेंट बस त्रुटि के बारे में हैं:
कार्यक्रम के कोड के भीतर निर्देशों से एक बस त्रुटि उत्पन्न नहीं होनी चाहिए। यह तब हो सकता है जब आप एक बाइनरी चला रहे हों और निष्पादन के दौरान, बाइनरी को संशोधित किया गया हो (एक निर्माण या हटाए गए आदि द्वारा अधिलेखित)।
यदि यह मामला है तो सत्यापित करना:
यह जांचने का एक सरल तरीका है कि क्या यह कारण एक ही बाइनरी के रनिंग इंस्टेंस को लॉन्च करने और बिल्ड को चलाने के लिए है। दोनों चल उदाहरण एक के साथ दुर्घटना होगीSIGBUS
निर्माण के समाप्त होने और बाइनरी को बदलने के बाद त्रुटि के (वर्तमान में दोनों इंस्टेंसेस रन करने वाले एक हैं)
अंतर्निहित कारण: यह इसलिए है क्योंकि OS मेमोरी पेजों को स्वैप करता है और कुछ मामलों में बाइनरी पूरी तरह से मेमोरी में लोड नहीं हो सकती है और ये क्रैश तब होंगे जब ओएस अगले पेज को उसी बाइनरी से लाने की कोशिश करेगा, लेकिन बाइनरी पिछले दिनों से बदल गई है इसे पढ़ें।
ऊपर बताए गए ब्लॅक्सडैट में जोड़ने के लिए, बस त्रुटियां तब भी होती हैं जब आपकी प्रक्रिया किसी विशेष 'चर' की मेमोरी तक पहुंचने का प्रयास नहीं कर सकती है ।
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
सूचना ' अनजाने का' उपयोग 'मैं' चर में 'पाश के लिए' पहले? यही कारण है कि इस मामले में बस त्रुटि हो रही है।
मुझे अभी यह पता चला है कि ARMv7 प्रोसेसर पर आप कुछ कोड लिख सकते हैं जो आपको अडॉप्ट किए जाने पर एक विभाजन दोष देता है, लेकिन -O2 के साथ संकलित होने पर यह आपको एक बस त्रुटि देता है (अधिक ऑप्टिमाइज़ करें)।
मैं उबंटू 64 बिट से GCC ARM gnueabihf क्रॉस कंपाइलर का उपयोग कर रहा हूं।
एक सामान्य बफर अतिप्रवाह जिसके परिणामस्वरूप बस त्रुटि होती है,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
यहाँ अगर डबल कोट्स ("") में स्ट्रिंग का आकार बुफ़ के आकार से अधिक है तो यह बस त्रुटि देता है।