Back to COMP2521 返回 COMP2521
Week 1 - Lab 01 第一周 - 实验 01

Sanitizers & Debugging Sanitizers 与调试

Learn to read and understand sanitizer error messages 学习阅读和理解 sanitizer 错误信息

🎯 Take the Quiz (40 Questions)做测验(40 题)

📚 What are Sanitizers? 📚 什么是 Sanitizers?

Sanitizers are tools that insert extra code into your program to detect various errors at runtime. In COMP2521, we use them to catch memory errors that would otherwise cause undefined behavior. Sanitizers 是在程序运行时检测各种错误的工具。在 COMP2521 中,我们使用它们来捕获会导致未定义行为的内存错误。

# Compile with AddressSanitizer (most commonly used) clang -Wall -Werror -g -fsanitize=address,undefined -o prog prog.c # Compile with MemorySanitizer clang -Wall -Werror -g -fsanitize=memory,undefined -fsanitize-memory-track-origins -o prog prog.c

🎯 Quick Reference: Error Types 🎯 快速参考:错误类型

Error Type错误类型 Meaning含义 First Reaction第一反应
heap-buffer-overflow Accessing memory outside allocated region访问超出分配区域的内存 Array index out of bounds / malloc too small数组越界 / malloc 分配太小
heap-use-after-free Using memory after it's been freed使用已释放的内存 Accessed pointer after free()free() 后又访问指针
use-of-uninitialized-value Reading uninitialized variable/field读取未初始化的变量/字段 Forgot to initialize variable or struct field忘记初始化变量或结构体字段
SEGV / null pointer Accessing memory at address 0 (NULL)访问地址 0(NULL)的内存 Dereferencing NULL pointer解引用空指针
memory-leak Allocated memory never freed分配的内存从未释放 Missing free() for malloc()malloc() 后缺少 free()

💥 Error Type 1: heap-buffer-overflow 💥 错误类型 1:堆缓冲区溢出

🔴 heap-buffer-overflow

What it means: 含义:

Your program tried to read or write outside the allocated memory region. 你的程序尝试在分配的内存区域之外读取或写入。

Common causes: 常见原因:

  • Array index out of bounds (e.g., arr[5] when size is 5)数组索引越界(如大小为 5 时访问 arr[5]
  • malloc() allocated too little memorymalloc() 分配的内存太小
  • Wrong sizeof() usage (e.g., sizeof(pointer) instead of sizeof(struct))sizeof() 使用错误(如 sizeof(pointer) 而不是 sizeof(struct)

Lab Examples: 实验示例:

Program 1: listAddStart.c

struct node *n = malloc(sizeof(n)); // ❌ Only 8 bytes (pointer size) // Should be: struct node *n = malloc(sizeof(struct node)); // ✅ 16 bytes

Program 2: shuffleArray.c

int *arr = malloc(size); // ❌ Only 'size' bytes // Should be: int *arr = malloc(size * sizeof(int)); // ✅ size * 4 bytes

Program 3: reverseArray.c

arr[size - i] // ❌ When i=0, size=5: accesses arr[5] (out of bounds!) // Should be: arr[size - 1 - i] // ✅ When i=0, size=5: accesses arr[4] (last element)

💥 Error Type 2: heap-use-after-free 💥 错误类型 2:释放后使用

🟠 heap-use-after-free

What it means: 含义:

Your program accessed memory after it was freed with free(). 你的程序在用 free() 释放内存后又访问了它。

🏠 Analogy: The Returned Locker 🏠 比喻:归还的储物柜

Imagine you returned a locker to the gym. You no longer own it. If you try to open it again, you might find someone else's stuff inside, or the locker might be demolished. The same applies to freed memory. 想象你把储物柜还给了健身房。你不再拥有它。如果你再试图打开它,可能会发现里面是别人的东西, 或者储物柜可能已经被拆除。释放的内存也是一样的道理。

Lab Example: listDeleteFirst.c 实验示例:listDeleteFirst.c

// ❌ WRONG: Access after free free(list); return list->next; // list is already freed! // ✅ CORRECT: Save before free struct node *newHead = list->next; free(list); return newHead;

Golden Rule 黄金法则

Save any data you need BEFORE calling free()! 在调用 free() 之前保存你需要的数据!

💥 Error Type 3: use-of-uninitialized-value 💥 错误类型 3:使用未初始化的值

🟡 use-of-uninitialized-value

What it means: 含义:

Your program read a variable or struct field that was never assigned a value. 你的程序读取了一个从未被赋值的变量或结构体字段。

Common causes: 常见原因:

  • Struct fields not initialized after mallocmalloc 后结构体字段未初始化
  • Local array declared but not initialized局部数组声明但未初始化
  • Variable declared but never assigned变量声明但从未赋值

Lab Examples: 实验示例:

Program 4: listPrepend.c

struct node *n = malloc(sizeof(*n)); n->value = value; // ❌ Forgot to set n->next! return n; // ✅ CORRECT: n->value = value; n->next = NULL; // Don't forget!

Program 7: listNumEvens.c

struct node *n = malloc(sizeof(*n)); n->next = NULL; // ❌ Forgot to set n->value! return n; // ✅ CORRECT: n->value = value; // Don't forget! n->next = NULL;

Program 8: mostFrequentLetter.c

int counts[ALPHABET_SIZE]; // ❌ Contains garbage values! // When you do counts[i]++, it adds to garbage // ✅ CORRECT: int counts[ALPHABET_SIZE] = {0}; // Initialize all to 0 // OR for (int i = 0; i < ALPHABET_SIZE; i++) counts[i] = 0;

Checklist for newNode functions: newNode 函数检查清单:

  • Did I initialize every struct field?我初始化了每个结构体字段吗?
  • Did I assign the value parameter to n->value?我把 value 参数赋给 n->value 了吗?
  • Did I set n->next to NULL?我把 n->next 设为 NULL 了吗?

💥 Error Type 4: SEGV / Null Pointer 💥 错误类型 4:段错误 / 空指针

💀 SEGV / null pointer dereference

What it means: 含义:

Your program tried to access memory at address 0 (NULL). This is always invalid. 你的程序尝试访问地址 0(NULL)的内存。这永远是无效的。

Program 5: listAppend.c

// ❌ WRONG: Loop goes one step too far while (curr != NULL) { curr = curr->next; } curr->next = newNode(value); // curr is NULL here! // ✅ CORRECT: Stop at the last node, not after it while (curr->next != NULL) { // Check next, not curr curr = curr->next; } curr->next = newNode(value); // Now curr is the last node

Key Insight 关键洞察

while (curr != NULL) exits when curr becomes NULL.
while (curr->next != NULL) exits when curr is the last node.
while (curr != NULL) 在 curr 变成 NULL 时退出。
while (curr->next != NULL) 在 curr 是最后一个节点时退出。

📖 How to Read Error Messages 📖 如何阅读错误信息

Step-by-step guide: 分步指南:

Step 1: Identify the error type

==402841==ERROR: AddressSanitizer: heap-buffer-overflow

Look for the text after "ERROR: AddressSanitizer:"查找 "ERROR: AddressSanitizer:" 后面的文字

Step 2: Find YOUR code in the stack trace

#0 ... in newNode listAddStart.c:44:10 ← Your code! #1 ... in listAddStart listAddStart.c:31:19 #2 ... in main listAddStart.c:23:10 #3 ... in __libc_start_main ← Library code (ignore)

Look for lines with .c files - that's your code!查找带有 .c 文件的行 - 那是你的代码!

Step 3: Check where memory was allocated

allocated by thread T0 here: #1 ... in newNode listAddStart.c:37:19 ← Memory was malloc'd here

This tells you where the memory was created.这告诉你内存是在哪里创建的。

Step 4: Check the memory size

0x502000000018 is located 0 bytes after 8-byte region

This tells you how much memory was allocated.这告诉你分配了多少内存。

🚀 Quick Fix Summary 🚀 快速修复总结

Error错误 Likely Fix可能的修复
heap-buffer-overflow Check array bounds, verify malloc size检查数组边界,验证 malloc 大小
heap-use-after-free Save data BEFORE free()在 free() 之前保存数据
use-of-uninitialized-value Initialize all struct fields / array elements初始化所有结构体字段 / 数组元素
SEGV / null pointer Check loop conditions, handle NULL cases检查循环条件,处理 NULL 情况
memory-leak Add free() for every malloc()为每个 malloc() 添加 free()
🎯 Take the Quiz (40 Questions)做测验(40 题)