0Pricing
C Academy · บทเรียน

การเข้าถึงที่ไม่ถูกต้อง

การเข้าถึงนอกขอบเขตและข้อมูลที่ยังไม่เริ่มต้น

การเข้าถึงที่ไม่ถูกต้อง เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

นอกเหนือจากหน่วยความจำรั่ว

หน่วยความจำรั่วทำให้เสียพื้นที่หน่วยความจำ แต่ข้อผิดพลาดจาก การเข้าถึงที่ไม่ถูกต้อง ทำให้ข้อมูลเสียหาย memcheck ตรวจจับได้หลายกรณี:

  • อ่านหรือเขียนเลยจุดสิ้นสุดของบัฟเฟอร์
  • ใช้หน่วยความจำหลังเรียก free
  • อ่านค่าที่ยังไม่ได้กำหนด
  • อ่านหรือเขียนผ่านพอยน์เตอร์ที่ไม่ถูกต้อง

ข้อผิดพลาดเหล่านี้ทำให้เกิดการล้มเหลวที่อันตรายที่สุดและทำซ้ำได้ยากที่สุด

การเขียนเกินขอบเขต

โค้ดนี้จัดสรรพื้นที่สำหรับ int จำนวน 5 ตัว แต่เขียนไปยังดัชนี 5 ซึ่งเป็นช่องที่หก

ดัชนี 5 อยู่ถัดจากจุดสิ้นสุดหนึ่งสมาชิก memcheck จะแจ้ง การเขียนไม่ถูกต้องขนาด 4 ที่บรรทัดนี้

#include <stdlib.h>

int main(void) {
    int *a = malloc(5 * sizeof(int));
    a[5] = 99; /* valid indices are 0..4 */
    free(a);
    return 0;
}

การอ่านข้อผิดพลาด

รายงานจะระบุการดำเนินการ ขนาด และความสัมพันธ์กับบล็อก:

Invalid write of size 4
Address 0x... is 0 bytes after a block of size 20 alloc'd

ข้อความ '0 bytes after a block of size 20' บอกว่าการเข้าถึงเกิดขึ้นทันทีหลังการจัดสรรขนาด 20 ไบต์ (int 5 ตัว)

การอ่านเกินขอบเขต

การอ่านก็ตรวจจับได้เช่นกัน ในกรณีนี้ลูปทำงานเลยไปหนึ่งสมาชิก

memcheck จะแจ้ง การอ่านไม่ถูกต้องขนาด 4 ในรอบสุดท้าย แม้โปรแกรมอาจจะ 'ทำงานได้' โดยบังเอิญ

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int *a = calloc(3, sizeof(int));
    for (int i = 0; i <= 3; i++)   /* should be i < 3 */
        printf("%d\n", a[i]);
    free(a);
    return 0;
}

ค่าที่ยังไม่ได้กำหนด

malloc ไม่ได้กำหนดค่าให้หน่วยความจำเป็นศูนย์ การนำหน่วยความจำไปใช้ก่อนกำหนดค่าจะทำให้ได้ค่าที่คาดเดาไม่ได้

memcheck จะแจ้ง การกระโดดหรือการย้ายตามเงื่อนไขขึ้นอยู่กับค่าที่ไม่ได้กำหนด เมื่อค่าดังกล่าวส่งผลต่อการควบคุมการทำงานหรือผลลัพธ์

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int *p = malloc(sizeof(int));
    if (*p == 0)              /* *p was never set */
        printf("zero\n");
    free(p);
    return 0;
}

เหตุใดรายงานค่าที่ยังไม่ได้กำหนดจึงล่าช้า

memcheck จะไม่แจ้งเตือนทันทีที่คุณอ่านหน่วยความจำที่ยังไม่ได้กำหนดค่า แต่จะติดตาม 'การมีค่าที่กำหนด' และรายงานก็ต่อเมื่อค่าที่ไม่กำหนดนั้น มีผลจริง เช่น ถูกใช้ในแขนง การแสดงผล หรือการเรียกระบบ

วิธีนี้ช่วยหลีกเลี่ยงการแจ้งเตือนเกินจริงเมื่อคุณเพียงคัดลอกไบต์ที่ยังไม่ได้กำหนดค่าไปมาโดยไม่ก่อให้เกิดอันตราย

การใช้หน่วยความจำหลังคืนแล้ว

การแตะต้องหน่วยความจำหลังจากคืนหน่วยความจำแล้วถือเป็นพฤติกรรมที่ไม่ได้กำหนด memcheck ตรวจจับกรณีนี้ได้อย่างแม่นยำ

โปรแกรมจะแจ้ง การอ่านไม่ถูกต้องขนาด 4 พร้อมหมายเหตุ Address ... is 0 bytes inside a block of size 4 free'd และยังแสดงตำแหน่งที่เรียก free ด้วย

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 7;
    free(p);
    printf("%d\n", *p);   /* read after free */
    return 0;
}

การคืนหน่วยความจำซ้ำสองครั้ง

การคืนหน่วยความจำให้พอยน์เตอร์เดิมสองครั้งจะทำให้ข้อมูลการจัดการหน่วยความจำของตัวจัดสรรเสียหาย

memcheck จะแจ้ง การคืนหน่วยความจำที่ไม่ถูกต้อง และแสดงทั้งการคืนหน่วยความจำครั้งปัจจุบันกับการจัดสรรหน่วยความจำเดิม ทำให้เห็นข้อผิดพลาดได้อย่างชัดเจน

#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    free(p);
    free(p);   /* freed twice */
    return 0;
}

ติดตามต้นกำเนิด

สำหรับข้อผิดพลาดจากค่าที่ยังไม่ได้กำหนดค่า ให้เพิ่ม --track-origins=yes

จากนั้น memcheck จะแจ้งว่าค่าที่ไม่ถูกต้องถูก สร้างขึ้น ที่ใด ไม่ใช่เพียงแค่ถูกใช้งานที่ใด ทำให้คำเตือนที่คลุมเครือกลายเป็นแนวทางแก้ไขที่ชัดเจน

valgrind --track-origins=yes ./prog

สแตกและตัวแปรโกลบอล

memcheck ทำงานได้ดีเยี่ยมกับข้อผิดพลาดในฮีป แต่การตรวจจับการเขียนเกินขอบเขตบนสแตกหรือในอาร์เรย์โกลบอลยังทำได้ไม่ดีเท่า

ในกรณีดังกล่าว AddressSanitizer (gcc -fsanitize=address) มักเป็นตัวเลือกที่ดีกว่า เครื่องมือทั้งสองช่วยเสริมการทำงานซึ่งกันและกัน

เกินหนึ่งตำแหน่ง: ตัวสิ้นสุดค่าว่าง

การเขียนเกินขอบเขตฮีปที่พบบ่อยคือการลืมตัวสิ้นสุดสตริง strlen จะคืนค่า 5 สำหรับ 'hello' แต่สตริงต้องใช้ 6 ไบต์เพื่อเก็บ '\0' ที่ต่อท้าย

memcheck จะแจ้งการเขียนที่ไม่ถูกต้อง เมื่อ strcpy เขียนไบต์สุดท้ายนั้นเลยจุดสิ้นสุดออกไป

#include <stdlib.h>
#include <string.h>

int main(void) {
    char *s = malloc(strlen("hello")); /* needs +1 */
    strcpy(s, "hello");                 /* writes the '\0' past end */
    free(s);
    return 0;
}

ตรวจสอบอย่างรวดเร็ว

ระบุสิ่งที่ memcheck แจ้งสำหรับโค้ดส่วนนี้

สรุปทบทวน

ขณะนี้คุณสามารถตรวจจับข้อผิดพลาดจากการเข้าถึงที่ไม่ถูกต้องได้แล้ว:

  • การอ่านหรือเขียนนอกขอบเขตจะแสดงเป็นการอ่านหรือเขียนที่ไม่ถูกต้อง พร้อมออฟเซ็ตของบล็อก
  • ค่าที่ยังไม่ได้กำหนดค่าจะถูกแจ้งเตือนเมื่อส่งผลต่อการตัดสินใจหรือเอาต์พุต
  • ตรวจจับการใช้งานหลังคืนหน่วยความจำและการคืนหน่วยความจำซ้ำสองครั้ง พร้อมแสดงตำแหน่งการเรียกทั้งสองจุด
  • ใช้ --track-origins=yes เพื่อระบุตำแหน่งของค่าที่ไม่กำหนด และใช้ร่วมกับ ASan สำหรับข้อผิดพลาดบนสแตก

ถัดไป: การอ่านรายงานฉบับเต็ม

คำถามที่พบบ่อย

บทเรียน “การเข้าถึงที่ไม่ถูกต้อง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเข้าถึงที่ไม่ถูกต้อง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเข้าถึงที่ไม่ถูกต้อง”

การเข้าถึงนอกขอบเขตและข้อมูลที่ยังไม่เริ่มต้น คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การเข้าถึงที่ไม่ถูกต้อง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม

ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุใดจึงใช้ Valgrind
  2. การตรวจจับหน่วยความจำรั่ว
  3. การเข้าถึงที่ไม่ถูกต้อง
  4. การอ่านรายงาน
← กลับไปที่ C Academy