owned this note changed 5 years ago
Published Linked with GitHub

2018q3 第 2 週測驗題

目的: 檢驗學員對 C 語言程式設計 的認知


測驗 1

  • 認領人: butastur

考慮到以下程式碼:

const char *p;
void dont_do_this(void) {
    const char c_str[] = "This will change";
    p = c_str;
}

指出存在的問題和提出修正機制,需要用 C99/C11 規格解釋。
C99/C11 6.2.4
object referred out of lifetime is undefined behavior

延伸問題: 在 Common Vulnerabilities and Exposure (CVE) 找出類似上述不當的 string literal 操作,而導致的安全漏洞,並加以探討


測驗 2

  • 認領人: Michael

指標篇 提到 signal 系統呼叫的原型宣告:

void (*signal(int sig, void (*handler)(int))) (int);

該如何解析呢?
提示: 參閱 manpage: signal(2)

延伸問題: 解釋 signal(2) 的作用,並在 GitHub 找出應用案例


測驗 3

  • 認領人:

Linux 核心程式碼 include/linux/list.h 提到以下程式碼,為何每個 head 使用時都要先加上 () 呢?

#define list_for_each_prev(pos, head) \
    for (pos = (head)->prev; pos != (head); pos = pos->prev)

延伸問題: 在 Linux 核心原始程式碼找出類似上述「走訪節點」的片段,討論其實作技巧和考量點


測驗 4

  • 認領人:kdy136811

考慮到以下程式碼:

int B = 2;
void func(int *p) { p = &B; }
int main() {
    int A = 1, C = 3;
    int *ptrA = &A;
    func(ptrA);
    printf("%d\n", *ptrA);
    return 0;
}

該如何修改,才能讓 func 得以變更到 main 裡頭 ptrA 的內含值?

延伸問題: 在 GitHub 找出使用 the pointer to the pointer 的 C 語言程式碼,並加以討論


測驗 5

  • 認領人: ian910297

以下程式是合法 C99 程式嗎?

#include <stdio.h>
int main() { return (********puts)("Hello"); }

請搭配 C 語言規格書解釋

繼續思考以下是否合法:

#include <stdio.h>
int main() { return (**&puts)("Hello"); }

繼續變形:

#include <stdio.h>
int main() { return (&**&puts)("Hello"); }

也會合法嗎?為什麼?請翻閱 C 語言規格書解說。


測驗 6

  • 認領人: jeremycheng0715

考慮以下程式碼:

int **arr = malloc(3 * sizeof(int *));
for (int i = 0; i < 3; i++)
    arr[i] = malloc(4 * sizeof(int));

如果要 free() 時,是否需要兩層的迴圈呢?倘若有人只是 free(arr); 會發生什麼事?又,該如何改善?

延伸問題: 藉由 AddressSanitizer 一類的記憶體分析工具,探討上述程式碼在執行時期的行為,並且比較你引入的改善是否有效益


測驗 7

  • 認領人: jkrvivian

推敲以下程式碼的作用:

void hex2(unsigned int x) {
    do {
        char c = "0123456789abcdef" [x & 0xf];
        printf("char %c for %d\n", c, x);
        x >>= 4; 
        printf("char %c for %d\n", c, x);
    } while (x);
}

延伸問題: 在 glibc 原始程式碼找出類似作用和寫法的程式碼,並探討其實作技巧


測驗 8

  • 認領人: ChingChieh

以下程式碼改寫自 Linux 核心原始程式碼,請對照註解 (預期功能),指出實作上的問題,假設輸入 value 不會超過 32-bit。

/*
 * Convert a signed n-bit integer to signed 32-bit integer.
 * Common cases are done through the compiler,
 * the screwed things has to be done by hand.
 */
static int32_t snto32(uint32_t value, unsigned n) {
    switch (n) {
    case  8: return ((int8_t) value);
    case 16: return ((int16_t) value);
    case 32: return ((int32_t) value);
    }
    return value & (1 << (n - 1)) ? value | (-1 << n) : value;
}

延伸問題:

  1. 參照 Linux 核心原始程式碼 (以及 git log),探討對應的修正;
  2. Common Vulnerabilities and Exposure (CVE) 找出類似的安全弱點,並且進行案例分析;
Select a repo