ความผิดพลาดในการแบ่งส่วนคืออะไร? มันแตกต่างใน C และ C ++ หรือไม่ ข้อผิดพลาดในการแบ่งกลุ่มและตัวชี้ห้อยเกี่ยวข้องอย่างไร
NullPointerException
Java
ความผิดพลาดในการแบ่งส่วนคืออะไร? มันแตกต่างใน C และ C ++ หรือไม่ ข้อผิดพลาดในการแบ่งกลุ่มและตัวชี้ห้อยเกี่ยวข้องอย่างไร
NullPointerException
Java
คำตอบ:
การแบ่งส่วนความผิดพลาดเป็นข้อผิดพลาดชนิดหนึ่งที่เกิดจากการเข้าถึงหน่วยความจำที่“ ไม่ได้เป็นของคุณ” มันเป็นกลไกตัวช่วยที่ทำให้คุณไม่สามารถทำลายหน่วยความจำและแนะนำบั๊กหน่วยความจำที่ยากต่อการดีบัก เมื่อใดก็ตามที่คุณได้รับ segfault คุณจะรู้ว่าคุณกำลังทำสิ่งผิดปกติกับหน่วยความจำ - การเข้าถึงตัวแปรที่ได้รับการปลดปล่อยแล้วการเขียนไปยังส่วนของหน่วยความจำแบบอ่านอย่างเดียวและอื่น ๆ การจัดการหน่วยความจำไม่มีความแตกต่างหลักระหว่าง segfaults ใน C และ C ++
มีหลายวิธีในการรับ segfault อย่างน้อยในภาษาระดับต่ำกว่าเช่น C (++) วิธีทั่วไปในการรับ segfault คือการยกเลิกการอ้างถึงตัวชี้ null:
int *p = NULL;
*p = 1;
segfault อื่นเกิดขึ้นเมื่อคุณพยายามเขียนลงในส่วนของหน่วยความจำที่ทำเครื่องหมายว่าอ่านอย่างเดียว:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
ตัวชี้กำลังชี้ไปยังสิ่งที่ไม่มีอยู่อีกต่อไปเช่นที่นี่:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
ตัวชี้p
dangles เนื่องจากชี้ไปที่ตัวแปรอักขระc
ที่หยุดอยู่หลังจากบล็อกสิ้นสุดลง และเมื่อคุณพยายามที่จะอ่านเอกสาร dangling pointer (เช่น*p='A'
) คุณอาจได้รับ segfault
c
มันเป็นแบบโลคอลหมายความว่ามันถูกผลักลงบนสแต็กหลังจากนั้น{
และป๊อปอัปออกมาหลังจาก}
นั้น dangling pointer เป็นเพียงการอ้างอิงถึง offset ซึ่งตอนนี้ออกมาจาก stack นั่นเป็นสาเหตุที่การแก้ไขในโปรแกรมอย่างง่ายจะไม่ทำให้เกิด segfault ใด ๆ ในทางกลับกันอาจนำไปสู่ segfault ในกรณีการใช้งานที่ซับซ้อนมากขึ้นซึ่งการเรียกฟังก์ชั่นอื่น ๆ อาจนำไปสู่สแต็คที่จะเติบโตและมีข้อมูลที่ชี้ไปโดยชี้ห้อย การเขียนไปยังข้อมูลนั้น (vars ในพื้นที่) จะนำไปสู่พฤติกรรมที่ไม่ได้กำหนด (segfault & Co)
SIGSEGV
ดังนั้นฉันจึงไม่คาดหวังว่า
มันจะคุ้มค่าที่จะสังเกตว่าข้อผิดพลาดในการแบ่งส่วนนั้นไม่ได้เกิดจากการเข้าถึงหน่วยความจำกระบวนการอื่นโดยตรง (นี่คือสิ่งที่ฉันได้ยินในบางครั้ง) เนื่องจากเป็นไปไม่ได้ ด้วยหน่วยความจำเสมือนทุกขั้นตอนจะมีพื้นที่ที่อยู่เสมือนของตัวเองและไม่มีทางที่จะเข้าถึงอีกอันโดยใช้ค่าของตัวชี้ใด ๆ ข้อยกเว้นนี้สามารถใช้ร่วมกันกับไลบรารีซึ่งเป็นพื้นที่ที่อยู่ทางกายภาพเดียวกันที่แมปไป (อาจ) ที่อยู่เสมือนที่แตกต่างกันและหน่วยความจำเคอร์เนลซึ่งแมปในลักษณะเดียวกันในทุกกระบวนการ (เพื่อหลีกเลี่ยงการล้าง TLB บน syscall) และสิ่งต่าง ๆ เช่น shmat;) - นี่คือสิ่งที่ฉันนับว่าเป็นการเข้าถึงแบบทางอ้อม อย่างไรก็ตามหนึ่งสามารถตรวจสอบว่าพวกเขามักจะอยู่ไกลจากรหัสกระบวนการและเรามักจะสามารถเข้าถึงพวกเขา (นี่คือเหตุผลที่พวกเขามี
แต่ถึงกระนั้นความผิดพลาดของการแบ่งส่วนสามารถเกิดขึ้นได้ในกรณีที่เข้าถึงหน่วยความจำของเราเอง (กระบวนการ) ในวิธีที่ไม่เหมาะสม (เช่นพยายามเขียนลงในพื้นที่ที่ไม่สามารถเขียนได้) แต่สาเหตุที่พบบ่อยที่สุดคือการเข้าถึงส่วนของพื้นที่ที่อยู่เสมือนที่ไม่ได้ถูกแมปกับทางกายภาพเลย
และทั้งหมดนี้เกี่ยวกับระบบหน่วยความจำเสมือน
ความผิดพลาดของการแบ่งส่วนเกิดจากการร้องขอสำหรับเพจที่กระบวนการไม่ได้ระบุไว้ในตารางตัวให้คำอธิบายหรือการร้องขอที่ไม่ถูกต้องสำหรับหน้านั้นมีอยู่ในรายการ (เช่นการร้องขอการเขียนบนหน้าอ่านอย่างเดียว)
ตัวชี้ห้อยเป็นตัวชี้ที่อาจหรืออาจไม่ชี้ไปยังหน้าที่ถูกต้อง แต่จะชี้ไปยังส่วนของหน่วยความจำ "ที่ไม่คาดคิด"
พูดตามความจริงตามที่ผู้โพสต์คนอื่นพูดถึง Wikipedia มีบทความที่ดีมากเกี่ยวกับเรื่องนี้ดังนั้นลองมาดูที่นั่น ข้อผิดพลาดประเภทนี้เกิดขึ้นบ่อยมากและมักเรียกสิ่งอื่น ๆ เช่นการละเมิดการเข้าถึงหรือข้อบกพร่องการป้องกันทั่วไป
พวกเขาจะไม่แตกต่างกันใน C, C ++ หรือภาษาอื่น ๆ ที่ช่วยให้พอยน์เตอร์ ข้อผิดพลาดประเภทนี้มักเกิดจากพอยน์เตอร์ที่
ตามวิกิพีเดีย:
ความผิดพลาดของการแบ่งส่วนเกิดขึ้นเมื่อโปรแกรมพยายามเข้าถึงตำแหน่งหน่วยความจำที่ไม่ได้รับอนุญาตให้เข้าถึงหรือพยายามเข้าถึงตำแหน่งหน่วยความจำในลักษณะที่ไม่ได้รับอนุญาต (เช่นพยายามเขียนไปยังตำแหน่งแบบอ่านอย่างเดียวหรือ เพื่อเขียนทับส่วนหนึ่งของระบบปฏิบัติการ)
การแบ่งส่วนความผิดเกิดจากความล้มเหลวของฮาร์ดแวร์ในกรณีนี้หน่วยความจำแรม นี่เป็นสาเหตุที่พบได้ทั่วไปน้อยลง แต่ถ้าคุณไม่พบข้อผิดพลาดในรหัสของคุณบางที memtest อาจช่วยคุณได้
ทางออกในกรณีนี้เปลี่ยนแรม
แก้ไข:
ที่นี่มีการอ้างอิง: ความผิดการแบ่งส่วนโดยฮาร์ดแวร์
ความผิดพลาดของการแบ่งส่วนเกิดขึ้นเมื่อกระบวนการ (การรันอินสแตนซ์ของโปรแกรม) กำลังพยายามเข้าถึงที่อยู่หน่วยความจำแบบอ่านอย่างเดียวหรือช่วงหน่วยความจำซึ่งกำลังถูกใช้โดยกระบวนการอื่นหรือเข้าถึงที่อยู่หน่วยความจำที่ไม่มีอยู่ ปัญหา Dangling Reference (ตัวชี้)หมายถึงการพยายามเข้าถึงวัตถุหรือตัวแปรที่เนื้อหาถูกลบออกจากหน่วยความจำแล้วเช่น:
int *arr = new int[20];
delete arr;
cout<<arr[1]; //dangling problem occurs here
หน้าSegmentation_faultของ Wikipedia มีคำอธิบายที่ดีมากเกี่ยวกับเรื่องนี้เพียงแค่ระบุสาเหตุและเหตุผล ดูวิกิพีเดียเพื่อดูคำอธิบายโดยละเอียด
ในการคำนวณความผิดพลาดของการแบ่งส่วน (มักสั้นลงถึง segfault) หรือการละเมิดการเข้าถึงเป็นความผิดที่เกิดจากฮาร์ดแวร์ที่มีการป้องกันหน่วยความจำโดยแจ้งให้ระบบปฏิบัติการ (OS) ทราบเกี่ยวกับการละเมิดการเข้าถึงหน่วยความจำ
ต่อไปนี้เป็นสาเหตุทั่วไปของความผิดพลาดในการแบ่งกลุ่ม:
สิ่งเหล่านี้มักเกิดจากข้อผิดพลาดในการเขียนโปรแกรมซึ่งส่งผลให้เกิดการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง:
การอ้างอิงหรือการกำหนดให้กับตัวชี้ที่ไม่มีการกำหนดค่าเริ่มต้น (ตัวชี้ป่าซึ่งชี้ไปยังที่อยู่หน่วยความจำแบบสุ่ม)
การอ้างถึงหรือกำหนดให้กับตัวชี้ที่เป็นอิสระ (ตัวชี้ห้อยซึ่งชี้ไปยังหน่วยความจำที่ได้รับการเพิ่ม / ยกเลิกการจัดสรร / ลบ)
บัฟเฟอร์ล้น
สแต็กล้น
ความพยายามในการเรียกใช้งานโปรแกรมที่คอมไพล์ไม่ถูกต้อง (คอมไพเลอร์บางตัวจะส่งออกไฟล์เรียกทำงานแม้จะมีข้อผิดพลาดในการคอมไพล์ก็ตาม)
กล่าวอย่างง่าย ๆ : การแบ่งเซกเมนต์เป็นระบบปฏิบัติการที่ส่งสัญญาณไปยังโปรแกรมโดยบอกว่าตรวจพบการเข้าถึงหน่วยความจำที่ผิดกฎหมายและกำลังยกเลิกโปรแกรมก่อนกำหนดเพื่อป้องกันไม่ให้หน่วยความจำเสียหาย
"การแบ่งกลุ่มผิดพลาด" หมายความว่าคุณพยายามเข้าถึงหน่วยความจำที่คุณไม่สามารถเข้าถึงได้
ปัญหาแรกอยู่ที่ข้อโต้แย้งหลักของคุณ หน้าที่หลักควรเป็นint main(int argc, char *argv[])
และคุณควรตรวจสอบว่า argc มีอย่างน้อย 2 ก่อนที่จะเข้าถึง argv [1]
นอกจากนี้เนื่องจากคุณผ่านการลอยเป็น printf (ซึ่งโดยวิธีการได้รับการแปลงเป็นสองเท่าเมื่อผ่านไปยัง printf) คุณควรใช้ตัวระบุรูปแบบ% f ตัวระบุรูปแบบ% s ใช้สำหรับสตริง (อาร์เรย์อักขระ '\ 0'-terminated)
ความผิดพลาดของการแบ่งส่วนหรือการละเมิดการเข้าถึงเกิดขึ้นเมื่อโปรแกรมพยายามเข้าถึงตำแหน่งหน่วยความจำที่ไม่มีอยู่หรือพยายามเข้าถึงตำแหน่งหน่วยความจำในลักษณะที่ไม่ได้รับอนุญาต
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
ที่นี่ฉันไม่มี [1,000] อยู่ดังนั้นจึงเกิด segfault
สาเหตุของการแบ่งส่วนความผิดพลาด:
it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.
De-referencing NULL pointers – this is special-cased by memory management hardware.
Attempting to access a nonexistent memory address (outside process’s address space).
Attempting to access memory the program does not have rights to (such as kernel structures in process context).
Attempting to write read-only memory (such as code segment).
มีคำอธิบายที่ดีหลายประการของ "ความผิดส่วน" ในคำตอบตั้งแต่ที่มีความผิดส่วนมักจะมีการถ่ายโอนข้อมูลของเนื้อหาหน่วยความจำที่มี แต่ผมอยากจะแบ่งปันที่ความสัมพันธ์ระหว่าง "แก่นทิ้ง" มีส่วนร่วมในความผิดส่วน (หลักทิ้ง)และ หน่วยความจำมาจาก:
จากปีพ. ศ. 2498 ถึง 2518 - ก่อนหน้าหน่วยความจำเซมิคอนดักเตอร์ - เทคโนโลยีที่โดดเด่นในหน่วยความจำคอมพิวเตอร์ใช้แม่เหล็กโดนัทขนาดเล็กที่พันกันบนสายทองแดง โดนัทเป็นที่รู้จักกันในชื่อ "แกนเฟอร์ไรต์" และหน่วยความจำหลักที่รู้จักกันในชื่อ "หน่วยความจำหลัก" หรือ "แกนกลาง"
มีคำจำกัดความของการแบ่งเซ็กเมนต์ที่เพียงพอฉันต้องการอ้างอิงตัวอย่างเล็ก ๆ น้อย ๆ ที่ฉันเจอในขณะที่การเขียนโปรแกรมซึ่งอาจดูเหมือนความผิดพลาดโง่ ๆ แต่จะเสียเวลามาก
คุณสามารถรับข้อผิดพลาดการแบ่งกลุ่มในกรณีด้านล่างในขณะที่ประเภท argumet ไม่ตรงกันใน printf
#include<stdio.h>
int main(){
int a = 5;
printf("%s",a);
return 0;
}
ผลลัพธ์: Segmentation Fault (SIGSEGV)
เมื่อคุณลืมจัดสรรหน่วยความจำให้กับตัวชี้ แต่พยายามใช้งาน
#include<stdio.h>
typedef struct{
int a;
}myStruct;
int main(){
myStruct *s;
/* few lines of code */
s->a = 5;
return 0;
}
ผลลัพธ์: Segmentation Fault (SIGSEGV)
ความหมายง่ายๆSegmentation fault
คือคุณพยายามเข้าถึงหน่วยความจำบางส่วนที่ไม่ได้เป็นของคุณ Segmentation fault
เกิดขึ้นเมื่อเราพยายามอ่านและ / หรือเขียนงานในตำแหน่งหน่วยความจำแบบอ่านอย่างเดียวหรือพยายามที่จะเพิ่มหน่วยความจำ กล่าวอีกนัยหนึ่งเราสามารถอธิบายสิ่งนี้ว่าเป็นความเสียหายของหน่วยความจำ
Segmentation fault
ด้านล่างนี้ผมพูดถึงความผิดพลาดที่พบบ่อยทำโดยโปรแกรมเมอร์ที่นำไปสู่
scanf()
ในทางที่ผิด (ลืมใส่&
)int num;
scanf("%d", num);// must use &num instead of num
int *num;
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
char *str;
//Stored in read only part of data segment
str = "GfG";
//Problem: trying to modify read only memory
*(str+1) = 'n';
// allocating memory to num
int* num = malloc(8);
*num = 100;
// de-allocated the space allocated to num
free(num);
// num is already freed there for it cause segmentation fault
*num = 110;
printf()
และscanf()
'