C++ Academy · บทเรียน

UBSan และ TSan

ค้นหาพฤติกรรมไม่กำหนดและการแข่งขัน

บทเรียน 3 จาก 413 ขั้นตอน

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

ตัวตรวจสอบอีกสองชนิด

นอกจากเอเอสแซนแล้ว ยังมีตัวตรวจสอบอีกสองชนิดที่มุ่งตรวจจับข้อบกพร่องคนละประเภท

  • ยูบีแซน: พฤติกรรมที่ไม่กำหนดไว้ (ค่าล้น การเลื่อนบิตผิด การอ้างอิงตัวชี้ว่าง)
  • ทีแซน: การแย่งข้อมูลในโค้ดหลายเธรด

การเปิดใช้ยูบีแซน

เปิดใช้ UndefinedBehaviorSanitizer ด้วย -fsanitize=undefined และสามารถใช้ร่วมกับเอเอสแซนได้

g++ -fsanitize=undefined -g main.cpp -o app
./app

จำนวนเต็มมีเครื่องหมายล้น

จำนวนเต็มมีเครื่องหมายล้นถือเป็นพฤติกรรมที่ไม่กำหนดไว้ใน C++ ยูบีแซนจะแจ้งเตือนที่บรรทัดที่เกิดเหตุโดยตรง

#include <climits>
#include <iostream>

int main() {
    int x = INT_MAX;
    int y = x + 1; // signed overflow: UB
    std::cout << y << "\n";
    return 0;
}

พฤติกรรมที่ไม่กำหนดไว้อื่น ๆ ที่ยูบีแซนตรวจจับได้

ยูบีแซนตรวจจับข้อผิดพลาดแฝงได้หลายชนิด

  • การเลื่อนบิตเกินช่วง (x << 40 สำหรับจำนวนเต็ม 32 บิต)
  • การอ้างอิงตัวชี้ว่าง
  • การเข้าถึงที่จัดแนวไม่ถูกต้อง
  • ค่าของ enum หรือบูลีนไม่ถูกต้อง

ทำให้ยูบีแซนหยุดทำงาน

โดยค่าเริ่มต้น ยูบีแซนจะแสดงข้อความแล้วทำงานต่อ เพิ่ม -fno-sanitize-recover=undefined เพื่อยุติการทำงานเมื่อพบข้อผิดพลาดแรก ซึ่งเหมาะกับการผสานรวมอย่างต่อเนื่องมากกว่า

g++ -fsanitize=undefined -fno-sanitize-recover=undefined -g main.cpp -o app

การเปิดใช้ทีแซน

เปิดใช้ ThreadSanitizer ด้วย -fsanitize=thread โดยจะตรวจจับการแย่งข้อมูล ซึ่งเกิดเมื่อสองเธรดเข้าถึงหน่วยความจำเดียวกันโดยไม่มีการประสานงาน และมีอย่างน้อยหนึ่งเธรดเขียนข้อมูล

g++ -fsanitize=thread -g main.cpp -o app -pthread
./app

ตัวอย่างการแย่งข้อมูล

สองเธรดเพิ่มค่าตัวนับที่ใช้ร่วมกันโดยไม่มีการล็อก ทีแซนจะแจ้งการเข้าถึงที่แย่งกันและสแตกของการเข้าถึงเหล่านั้น

#include <thread>
#include <iostream>

int counter = 0;

void work() { for (int i = 0; i < 1000; ++i) ++counter; }

int main() {
    std::thread t1(work), t2(work);
    t1.join();
    t2.join();
    std::cout << counter << "\n";
    return 0;
}

การแก้การแย่งข้อมูล

ปกป้องข้อมูลที่ใช้ร่วมกันด้วยมิวเท็กซ์ หรือใช้ std::atomic หลังแก้ไขแล้ว ทีแซนจะไม่รายงานการแย่งข้อมูล

#include <thread>
#include <atomic>
#include <iostream>

std::atomic<int> counter{0};

void work() { for (int i = 0; i < 1000; ++i) ++counter; }

int main() {
    std::thread t1(work), t2(work);
    t1.join();
    t2.join();
    std::cout << counter << "\n";
    return 0;
}

ความเข้ากันได้ระหว่างทีแซนกับเอเอสแซน

ไม่สามารถใช้ทีแซนร่วมกับเอเอสแซนในโปรแกรมสร้างเดียวกันได้ (ทั้งสองขัดแย้งกัน) ให้ใช้การกำหนดค่าโปรแกรมสร้างแยกกัน โดยแบบหนึ่งใช้สำหรับเอเอสแซนร่วมกับยูบีแซน และอีกแบบใช้สำหรับทีแซน

เมทริกซ์โปรแกรมสร้างสำหรับตัวตรวจสอบ

การตั้งค่าการผสานรวมอย่างต่อเนื่องที่ใช้งานได้จริงจะเรียกใช้ชุดการทดสอบด้วยโปรแกรมสร้างที่มีตัวตรวจสอบสองแบบ

  • โปรแกรมสร้าง A: -fsanitize=address,undefined
  • โปรแกรมสร้าง B: -fsanitize=thread

วิธีนี้ครอบคลุมข้อบกพร่องด้านหน่วยความจำ พฤติกรรมที่ไม่กำหนดไว้ และการทำงานพร้อมกัน

ต้นทุนและข้อจำกัด

ทีแซนอาจทำให้โปรแกรมช้าลง 5–15 เท่าและใช้หน่วยความจำเพิ่มขึ้นมาก เช่นเดียวกับตัวตรวจสอบทั้งหมด ทีแซนตรวจจับได้เฉพาะข้อบกพร่องบนเส้นทางของโค้ดที่ถูกเรียกใช้ ดังนั้นการทดสอบหลายเธรดที่ดีจึงสำคัญ

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

ทบทวนว่าทีแซนตรวจจับอะไร

สรุปทบทวน

คุณได้เรียนรู้ยูบีแซนและทีแซน

  • ยูบีแซน (-fsanitize=undefined) ค้นหาค่าล้น การเลื่อนบิตผิด และการอ้างอิงตัวชี้ว่าง
  • ใช้ -fno-sanitize-recover เพื่อยุติการทำงานเมื่อพบพฤติกรรมที่ไม่กำหนดไว้ครั้งแรก
  • ทีแซน (-fsanitize=thread) ค้นหาการแย่งข้อมูล แก้ไขด้วยมิวเท็กซ์หรืออะตอมิก
  • ทีแซนและเอเอสแซนต้องใช้โปรแกรมสร้างแยกกัน
เริ่มต้นได้ฟรี

เรียนรู้ C++ ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

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

บทเรียน “UBSan และ TSan” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “UBSan และ TSan”

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

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

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

บทเรียน “UBSan และ TSan” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การใช้ gdb และ lldb
  2. AddressSanitizer
  3. UBSan และ TSan
  4. พื้นฐาน Valgrind
← กลับไปที่ C++ Academy