در محاسبات، خطای گذرگاه خطایی است که توسط سختافزار ایجاد شده و به یک سیستم عامل (سیستم عامل) اطلاع میدهد که پردازه ای در تلاش است تا به حافظه ای دسترسی پیدا کند که پردازنده از نظر فیزیکی نمیتواند آن را آدرس دهی کند: یک آدرس نامعتبر برای آدرس گذرگاه. در استفاده مدرن در بیشتر معماریها، این موارد بسیار نادرتر از خطاهای تقسیمبندی است که عمدتاً به دلیل نقض دسترسی حافظه رخ میدهد: مشکلات در آدرس منطقی یا مجوزها.
در سیستم عاملهای سازگار با POSIX، خطاهای گذرگاه معمولاً منجر به ارسال سیگنال SIGBUS به پردازه ای میشود که باعث بروز خطا شدهاست. SIGBUS همچنین میتواند ناشی از هرگونه خطای کلی دستگاه باشد که رایانه تشخیص میدهد، اگرچه خطای گذرگاه به ندرت به معنای شکسته شدن فیزیکی سختافزار کامپیوتر است - بهطور معمول به دلیل یک اشکال در نرمافزار ایجاد میشود.
حداقل سه دلیل اصلی برای خطاهای باس وجود دارد:
نرمافزار به CPU دستور میدهد تا آدرس حافظه فیزیکی خاصی را بخواند یا بنویسد. بر این اساس، پردازنده مرکزی این آدرس فیزیکی را روی گذرگاه آدرس خود قرار میدهد و از سایر سختافزارهای متصل به پردازنده مرکزی میخواهد در صورت پاسخ دادن به این آدرس خاص، نتایج را برگردانند. اگر هیچ سختافزار دیگری پاسخ ندهد، CPU یک ارور را برمیگرداند، حاکی از اینکه آدرس فیزیکی درخواست شده توسط کل سیستم رایانه ای شناسایی نشدهاست. توجه داشته باشید که این فقط آدرسهای حافظه فیزیکی را پوشش میدهد. تلاش برای دستیابی به آدرس حافظه مجازی تعریف نشده معمولاً به عنوان یک خطای تقسیمبندی به جای خطای گذرگاه در نظر گرفته میشود، اگرچه اگر MMU جدا باشد، پردازنده نمیتواند تفاوت را تشخیص دهد.
بیشتر پردازندهها با بایت آدرس پذیر هستند، جایی که هر آدرس حافظه منحصر به فرد به یک بایت ۸ بیتی اشاره دارد. اکثر پردازندهها میتوانند از هر آدرس حافظه به بایتهای مشخصی دسترسی داشته باشند، اما بهطور کلی نمیتوانند به واحدهای بزرگتر (۱۶ بیت، ۳۲ بیت، ۶۴ بیت و غیره) دسترسی داشته باشند بدون اینکه این واحدها با یک مرز خاص تراز شوند (سیستم عامل x86 یک استثنا قابل توجه است))
به عنوان مثال، اگر دسترسیهای چند بایت با ۱۶ بیتی تراز باشد، آدرسها در ۰، ۲ ، ۴، ۶ و غیره، تراز شده در نظر گرفته میشوند و بنابراین قابل دسترسی هستند، در حالی که آدرسهای ۱، ۳ ، ۵ و به همین ترتیب بدون تراز در نظر گرفته میشود و قابل دسترسی مستقیم نیستند، اگر دسترسیهای چند بایت با۳۲ بیتی تراز باشند، آدرسهای ۰، ۴ ، ۸، ۱۲ و غیره، تراز شده در نظر گرفته میشوند و بنابراین در دسترس هستند، و تمام آدرسهای بین آنها بی تراز شناخته میشوند. تلاش برای دستیابی به واحدی بزرگتر از بایت در یک آدرس غیر تراز شده میتواند باعث خطای گذرگاه شود.
برخی از سیستمها بسته به معماری مورد استفاده ممکن است ترکیبی از این سیستمها داشته باشند. به عنوان مثال، برای سختافزارهای مبتنی بر سیستم اصلی IBM System / 360، از جمله IBM System z، Fujitsu B8000، RCA Spectra و UNIVAC Series 90، دستورالعملها باید در یک حد ۱۶ بیتی باشند، یعنی آدرسهای اجرا باید از یک باید زوج شروع شوند. تلاش برای انشعاب به یک آدرس فرد منجر به یک ارور میشود. با این حال، دادهها ممکن است از هر آدرس در حافظه بازیابی شوند، و بسته به دستورالعمل ممکن است یک بایت یا بیشتر باشند.
پردازندهها بهطور کلی در تمام زمانها به دادهها در حد عرض کامل گذرگاه دادههای خود دسترسی دارند. برای آدرس دهی به بایتها، آنها به حافظه دربا عرض گذرگاه داده خود دسترسی پیدا میکنند سپس برای آدرس دهی به بایتهای جداگانه، ماسک میزنند و تغییر مکان میدهند. سیستمها این الگوریتم ناکارآمد را تحمل میکنند، زیرا این یک ویژگی اساسی برای اکثر نرمافزارها، به ویژه پردازش رشتهاست. برخلاف بایت، واحدهای بزرگتر میتوانند دو آدرس تراز را داشته باشند و بنابراین به بیش از یک بارگیری در گذرگاه داده نیاز دارند. پشتیبانی از پردازندههای مرکزی امکانپذیر است، اما این قابلیت به ندرت مستقیماً در سطح کد دستگاه مورد نیاز است، بنابراین طراحان پردازنده بهطور معمول از اجرای آن اجتناب میکنند و در عوض برای دسترسی به حافظه غیرهمسطح خطاهای گذرگاه صادر میکنند.
در freeBSD , Linux و Solaris وقتی صفحات حافظه مجازی را نمیتوان صفحه بندی کرد، میتوانند خطای گذرگاه را نشان دهند، به عنوان مثال زیرا ناپدید شدهاست (به عنوان مثال دسترسی به یک فایل نقشهبرداری شده از حافظه یا اجرای یک تصویر باینری که هنگام اجرای برنامه کوتاه شدهاست)، یا به این دلیل که یک فایل نقشهبرداری شده از حافظه که فقط ایجاد شدهاست، نمیتواند به صورت فیزیکی تخصیص یابد، زیرا دیسک پر شده.
در x86 یک مکانیسم مدیریت حافظه قدیمی وجود دارد که به عنوان تقسیمبندی شناخته میشود. اگر برنامه، بخش انتخاب را با انتخاب بخش غیر موجود بارگیری کند (که تحت سیستم عامل سازگار با POSIX فقط با یک زبان اسمبلی قابل انجام است)، این استثنا ایجاد میشود. برخی از سیستم عاملها از این سیستم برای تعویض استفاده میکردند، اما در Linux این سیستم SIGBUS تولید میکند.
این نمونه ای از دسترسی حافظه غیرهمتراز است که به زبان برنامهنویسی C با نحو مونتاژ AT&T نوشته شدهاست.
#include <stdlib.h>
int main(int argc, char **argv)
{
int *iptr;
char *cptr;
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif
/* malloc() always provides memory which is aligned for all fundamental types */
cptr = malloc(sizeof(int) + 1);
/* Increment the pointer by one, making it misaligned */
iptr = (int *) ++cptr;
/* Dereference it as an int pointer, causing an unaligned access */
*iptr = 42;
/*
Following accesses will also result in sigbus error.
short *sptr;
int i;
sptr = (short *)&i;
// For all odd value increments, it will result in sigbus.
sptr = (short *)(((char *)sptr) + 1);
*sptr = 100;
*/
return 0;
}
کامپایل و اجرای مثال در سیستم عامل سازگار با POSIX در x86 خطا را نشان میدهد:
$ gcc -ansi sigbus.c -o sigbus
$ ./sigbus
Bus error
$ gdb ./sigbus
(gdb) r
Program received signal SIGBUS, Bus error.
0x080483ba in main ()
(gdb) x/i $pc
0x80483ba <main+54>: mov DWORD PTR [eax],0x2a
(gdb) p/x $eax
$1 = 0x804a009
(gdb) p/t $eax & (sizeof(int) - 1)
$2 = 1
debugger GDB نشان میدهد که مقدار فوری 0x2a با استفاده از زبان اسمبلی X86 در محلی که در ثبت کننده EAX ذخیره شدهاست ذخیره میشود. این نمونه ای از ثبت آدرسهای غیرمستقیم است.
چاپ بیتهای کم ارزش آدرس نشان میدهد که با مرز کلمه همخوانی ندارد ("dword" با استفاده از اصطلاحات x86).