owned this note
owned this note
Published
Linked with GitHub
# 2021q1 Homework1 (lab0)
contributed by < `yellow-hank` >
###### tags: `LinuxKernel`
:::danger
注意書寫規範:中英文間用一個半形空白字元區隔
:notes: jserv
:::
## Queue 實作
### Structure
### queue
```cpp
typedef struct {
list_ele_t *head; /* Linked list of elements */
list_ele_t *tail; /* End of list */
size_t size; /* list size */
} queue_t;
```
#### linked list
```cpp
typedef struct ELE {
/* Pointer to array holding string.
* This array needs to be explicitly allocated and freed
*/
char *value;
struct ELE *next;
} list_ele_t;
```
### functions
#### q_new
:::spoiler code
```cpp
/*
* Create empty queue.
* Return NULL if could not allocate space.
*/
queue_t *q_new()
{
queue_t *q = malloc(sizeof(queue_t));
// check malloc whether allocating space sucess or not
if (!q) {
return q;
}
q->head = NULL;
q->tail = NULL;
q->size = 0;
return q;
}
```
:::
- 產生一個新的 queue 的資料結構,若是配置記憶體失敗,則回傳 NULL ,餅切初始化 queue 的變數
#### q_free
:::spoiler code
```cpp
/* Free all storage used by queue */
void q_free(queue_t *q)
{
if (!q) {
return;
}
/* go through each list node to release value's space.
* After release value's space, release list node
*/
for (; q->head != NULL;) {
free(q->head->value);
list_ele_t *delete_node = q->head;
q->head = q->head->next;
free(delete_node);
}
free(q);
}
```
:::
**釋放一個 queue ,裡面有兩個節點的示意圖**
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> delete_node"];
struct2 [label="<f0> head"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct3;
struct3:f1 -> struct4;
}
```
更改第一個 next 指向方式,並且讓 head 指向下一個節點
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> delete_node"];
struct2 [label="<f0> head"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
}
```
釋放 delete_node 指向的空間,並且讓 delete_node 指向下一個節點
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> delete_node"];
struct2 [label="<f0> head"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct3;
}
```
#### q_insert_head
:::spoiler code
```cpp
/*
* Attempt to insert element at head of queue.
* Return true if successful.
* Return false if q is NULL or could not allocate space.
* Argument s points to the string to be stored.
* The function must explicitly allocate space and copy the string into it.
*/
bool q_insert_head(queue_t *q, char *s)
{
list_ele_t *newh;
char *s_new;
// check malloc whether allocating space sucess or not
if (!q) {
return false;
}
newh = malloc(sizeof(list_ele_t));
if (!newh) {
return false;
}
// allocate space for string
s_new = malloc(sizeof(char) * (strlen(s) + 1));
if (!s_new) {
free(newh);
return false;
}
// deal with the first time inserting node
if (!q->head) {
q->tail = newh;
}
newh->next = q->head;
q->head = newh;
newh->value = s_new;
/*using memcpy because strcpy may cause source string won't
* have a teminating character and it may crash program.
*/
memcpy(s_new, s, strlen(s) + 1);
q->size++;
return true;
}
```
:::
- 這裡使用 memcpy ,是因為 strcpy 會導致 '\0' 有機會不會被放入,可能會使程式存取到非法的空間,使程式終止。
- 在進行除錯時,發現如果在第二次配置記體失敗時,要記得將先前配置的空間釋放掉,第一次撰寫未注意到導致測試未通過。
**示意圖**
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> newh"];
struct2 [label="<f0> head"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> newh"];
struct2 [label="<f0> head"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct3:f1 -> struct4:f0;
struct2:f1 -> struct4;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> newh"];
struct2 [label="<f0> head"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct3:f1 -> struct4:f0;
struct2:f1 -> struct3;
}
```
#### q_insert_tail
:::spoiler code
```cpp
/*
* Attempt to insert element at tail of queue.
* Return true if successful.
* Return false if q is NULL or could not allocate space.
* Argument s points to the string to be stored.
* The function must explicitly allocate space and copy the string into it.
*/
bool q_insert_tail(queue_t *q, char *s)
{
list_ele_t *newh;
char *s_new;
if (!q) {
return false;
}
newh = malloc(sizeof(list_ele_t));
if (!newh) {
return false;
}
s_new = malloc(sizeof(char) * (strlen(s) + 1));
if (!s_new) {
free(newh);
return false;
}
newh->next = NULL;
if (q->tail) {
q->tail->next = newh;
} else {
q->head = newh;
}
q->tail = newh;
newh->value = s_new;
/*using memcpy because strcpy may cause source string won't
* have a teminating character and it may crash program.
*/
memcpy(s_new, s, strlen(s) + 1);
q->size++;
return true;
}
```
:::
- 這裡使用 memcpy ,是因為 strcpy 會導致 '\0' 有機會不會被放入,可能會使程式存取到非法的空間,使程式終止。
- 為了實現時間複雜度為 O(1) ,在 queue 的結構中加入一個變數紀錄 list 的末端,如此一來,可以在常數時間內加入資料在末端。
**示意圖**
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct2 [label="<f0> tail"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
struct3:f1 -> struct4:f0;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct2 [label="<f0> tail"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="<f0> newh"];
struct6 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
struct3:f1 -> struct4:f0;
struct5:f1 -> struct6;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct2 [label="<f0> tail"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="<f0> newh"];
struct6 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
struct3:f1 -> struct4:f0;
struct5:f1 -> struct6;
struct4:f1 -> struct6:f0;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct2 [label="<f0> tail"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="<f0> newh"];
struct6 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct6;
struct3:f1 -> struct4:f0;
struct5:f1 -> struct6;
struct4:f1 -> struct6:f0;
}
```
#### q_remove_head
:::spoiler code
```cpp
/*
* Attempt to remove element from head of queue.
* Return true if successful.
* Return false if queue is NULL or empty.
* If sp is non-NULL and an element is removed, copy the removed string to *sp
* (up to a maximum of bufsize-1 characters, plus a null terminator.)
* The space used by the list element and the string should be freed.
*/
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
list_ele_t *delete_ptr;
if (!q) {
return false;
}
if (!q->head) {
return false;
}
if (sp) {
memcpy(sp, q->head->value, bufsize);
sp[bufsize - 1] = '\0';
}
free(q->head->value);
delete_ptr = q->head;
q->head = q->head->next;
free(delete_ptr);
q->size--;
return true;
}
```
:::
- 這裡需要注意的是節點中的 value 需要被釋放,因為先前是透過 malloc 配置,若不進行釋放記憶體使用量會隨時間增加,可能會導致記憶體不足的情況
- 先釋放 value 空間,而後釋放整個節點。
**示意圖**
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct2 [label="<f0> delete_ptr"];
struct3 [label="<f0> tail"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct4;
struct2:f1 -> struct4;
struct3:f1 -> struct5:f0;
struct4:f1 -> struct5:f0;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct2 [label="<f0> delete_ptr"];
struct3 [label="<f0> tail"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct5;
struct2:f1 -> struct4;
struct3:f1 -> struct5:f0;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> head"];
struct3 [label="<f0> tail"];
struct5 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct5;
struct3:f1 -> struct5:f0;
}
```
#### q_size
:::spoiler code
```cpp
/*
* Return number of elements in queue.
* Return 0 if q is NULL or empty
*/
int q_size(queue_t *q)
{
/* using a variable in queue_t to store size.After insert or remove
* operation increase or decrease size.With this implement, to reach time
* complexity O(1)
*/
if (!q) {
return 0;
}
return q->size;
}
```
:::
- 為了實現時間複雜度為 O(1) ,在 queue 的結構中加入一個變數紀錄節點的個數,而個數的增加或減少則是在新增函示或是移除函示中進行變動。
- 注意的是 queue 為空時,個數為零。
#### q_reverse
:::spoiler code
```cpp
/*
* Reverse elements in queue
* No effect if q is NULL or empty
* This function should not allocate or free any list elements
* (e.g., by calling q_insert_head, q_insert_tail, or q_remove_head).
* It should rearrange the existing ones.
*/
void q_reverse(queue_t *q)
{
list_ele_t *prev = NULL, *current, *next, *swap;
if (!q) {
return;
}
for (current = q->head; current != NULL;) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
swap = q->head;
q->head = q->tail;
q->tail = swap;
}
```
:::
**示意圖**
用三個指標個別指向三個個別節點
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> prev"];
struct2 [label="<f0> current"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="<f0> next"];
struct6 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
struct3:f1 -> struct4:f0;
struct5:f1 -> struct6;
struct4:f1 -> struct6:f0;
}
```
把個別指向的節點中的 next 指向反向, current 指向 prev , next 指向 current
```graphviz
digraph structs {
node[shape=record]
struct1 [label="<f0> prev"];
struct2 [label="<f0> current"];
struct3 [label="{<f0> value|<f1> next\n}"];
struct4 [label="{<f0> value|<f1> next\n}"];
struct5 [label="<f0> next"];
struct6 [label="{<f0> value|<f1> next\n}"];
struct1:f1 -> struct3;
struct2:f1 -> struct4;
struct4:f1 -> struct3:f0;
struct5:f1 -> struct6;
struct6:f1 -> struct4:f0;
}
```
#### q_sort
:::spoiler code
```cpp
/* insert node at list tail and change head and tail pointer*/
void list_insert_tail(list_ele_t **head, list_ele_t **tail, list_ele_t *node)
{
if (*tail == NULL) {
*tail = node;
*head = node;
} else {
(*tail)->next = node;
(*tail) = node;
}
}
list_ele_t *merge(list_ele_t *first, list_ele_t *second)
{
list_ele_t *result_head = NULL, *result_tail = NULL;
while (first && second) {
// compare and put the smaller one in result
if (strcmp(first->value, second->value) <= 0) {
list_insert_tail(&result_head, &result_tail, first);
first = first->next;
} else {
list_insert_tail(&result_head, &result_tail, second);
second = second->next;
}
}
// Find the list that still have data, and add it in result
if (first) {
list_insert_tail(&result_head, &result_tail, first);
}
if (second) {
list_insert_tail(&result_head, &result_tail, second);
}
return result_head;
}
list_ele_t *mergesort(list_ele_t *list)
{
if (!list->next) {
return list;
}
list_ele_t *slow = list, *fast = list->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
list_ele_t *tmp = slow->next;
slow->next = NULL;
return merge(mergesort(list), mergesort(tmp));
}
/*
* Sort elements of queue in ascending order
* No effect if q is NULL or empty. In addition, if q has only one
* element, do nothing.
*/
void q_sort(queue_t *q)
{
if (!q || !q->head || !q->head->next) {
return;
}
list_ele_t *i;
q->head = mergesort(q->head);
// update tail's information
for (i = q->head; i->next != NULL; i = i->next)
;
q->tail = i;
}
```
:::
- 第一次實作時使用 Quick Sort , 尚未注意到測試中有考慮到時間複雜度需要達到 O(nlgn) , Quick Sort 最差的時間複雜度會是 O(n^2^) 。為了達成目標,我去尋找較為接近的演算法,後來選擇 Merge Sort , 平均時間複雜度為 O(nlgn) ,在實作中遇到的問題是很容易發生 segmentation fault ,需要了解出錯的地點,很容易在這邊打轉。
- 第一次將 Merge Sort 實作出來,但是因為在加入節點的設計使用到重頭開始移動到尾巴再將其加入,這樣耗費許多時間,雖然結果是正確的。後來,我新增一個變數紀錄尾巴,如同上述 q_insert_tail 的做法,減少許多時間。
## 修正 qtest
使用 Adress Sanitizer 分析 qtest 執行 help 指令發生的錯誤
```
==234967==ERROR: AddressSanitizer: global-buffer-overflow on address 0x557eaae33400 at pc 0x557eaae1c90f bp 0x7ffcc876bad0 sp 0x7ffcc876bac0
READ of size 4 at 0x557eaae33400 thread T0
#0 0x557eaae1c90e in do_help_cmd /home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/console.c:307
#1 0x557eaae1ca22 in interpret_cmda /home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/console.c:221
#2 0x557eaae1d207 in interpret_cmd /home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/console.c:244
#3 0x557eaae1e951 in run_console /home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/console.c:660
#4 0x557eaae1b531 in main /home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/qtest.c:788
#5 0x7f19f18b10b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#6 0x557eaae18b8d in _start (/home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/qtest+0x8b8d)
0x557eaae33401 is located 0 bytes to the right of global variable 'echo' defined in 'console.c:59:13' (0x557eaae33400) of size 1
SUMMARY: AddressSanitizer: global-buffer-overflow /home/yellowhank/Desktop/linux_kernel/hw0/lab0-c/console.c:307 in do_help_cmd
Shadow bytes around the buggy address:
0x0ab0555be630: f9 f9 f9 f9 04 f9 f9 f9 f9 f9 f9 f9 00 f9 f9 f9
0x0ab0555be640: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 00 f9 f9 f9
0x0ab0555be650: f9 f9 f9 f9 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9
0x0ab0555be660: 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9
0x0ab0555be670: 01 f9 f9 f9 f9 f9 f9 f9 01 f9 f9 f9 f9 f9 f9 f9
=>0x0ab0555be680:[01]f9 f9 f9 f9 f9 f9 f9 04 f9 f9 f9 f9 f9 f9 f9
0x0ab0555be690: 04 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
0x0ab0555be6a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ab0555be6b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ab0555be6c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ab0555be6d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==234967==ABORTING
```
這裡發現在存取 echo 變數時,會發生 global-buffer-overflow 。查詢 C99 規格書發現 bool 的空間是足夠放 0 和 1 。
- C99 [6.2.5] **Types**
> An object declared as type _Bool is large enough to store the values 0 and 1.
下列程式碼使用 plist->valp 整數指標去指向 echo 空間,會導致指標直接存取 4bytes 的空間,但是實際上 echo 的空間不足 4bytes ,會導致 global-buffer-overflow
```cpp
report(1, "\t%s\t%d\t%s", plist->name, *plist->valp,
plist->documentation);
```
也實測 bool 和 int 的空間大小,得到 bool 1bytes, int 4 bytes
```cpp
printf("%ld %ld\n",sizeof(bool), sizeof(int))
// 1 4
```
### 嘗試解決方式
- 可以將 echo 變數的宣告型態提升至 int ,但是接下來 simulation 會遇到相同的問題, simulation 是外部的變數,不一定能夠更動型態。
- 把 plist->valp 轉型成 bool* ,但是需注意到原本是 int* ,這是非常危險的方式,有機會導致資訊量減少,得到錯誤的結果,這個方式需要評估原本的 int 有沒有超過 1bytes 的空間,在這裡因為 option length 使用數字 1024 ,所以不適用。
### 解決方式
- 在結構 PELE 中加入一個變數紀錄是布林值還是整數值
```cpp
struct PELE {
char *name;
int *valp;
char *documentation;
/* Function that gets called whenever parameter changes */
setter_function setter;
param_ptr next;
bool checkboolint;
};
```
- 在加入參數時,設定此值是布林值還是整數值
```cpp
void add_param(char *name,
int *valp,
char *doccumentation,
setter_function setter);
setter_function setter,
bool setbool);
```
- 在 report 的地方分為布林值解決方式或是整數值解決方式
```cpp
if (plist->checkboolint)
report(1, "\t%s\t%d\t%s", plist->name, *(bool *) plist->valp,
plist->documentation);
else
report(1, "\t%s\t%d\t%s", plist->name, *plist->valp,
plist->documentation);
```
## 使用 valgrind 排除 queue 實作時記憶體錯誤
使用 make valgrind 針對記憶體進行除錯
- 錯誤結果 (擷取第一個測試錯誤)
```
+++ TESTING trace trace-01-ops:
# Test of insert_head and remove_head
==288083== Invalid read of size 8
==288083== at 0x4842C30: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8ff8 is 8 bytes before a block of size 2,049 alloc'd
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10B3B4: do_remove_head (qtest.c:334)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842C3B: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8ff0 is 16 bytes before a block of size 2,049 alloc'd
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10B3B4: do_remove_head (qtest.c:334)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842C1C: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8fe8 is 24 bytes before a block of size 2,049 alloc'd
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10B3B4: do_remove_head (qtest.c:334)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842C28: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8fe0 is 32 bytes before a block of size 2,064 in arena "client"
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842A8F: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8c50 is 3 bytes after a block of size 45 alloc'd
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10DEDF: test_malloc (harness.c:138)
==288083== by 0x10E399: q_insert_head (queue.c:64)
==288083== by 0x10BC57: do_insert_head (qtest.c:216)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842A97: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8c58 is 11 bytes after a block of size 45 alloc'd
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10DEDF: test_malloc (harness.c:138)
==288083== by 0x10E399: q_insert_head (queue.c:64)
==288083== by 0x10BC57: do_insert_head (qtest.c:216)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842A7C: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8c60 is 19 bytes after a block of size 45 alloc'd
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10DEDF: test_malloc (harness.c:138)
==288083== by 0x10E399: q_insert_head (queue.c:64)
==288083== by 0x10BC57: do_insert_head (qtest.c:216)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
==288083== Invalid read of size 8
==288083== at 0x4842A87: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba8c68 is 24 bytes after a block of size 48 in arena "client"
==288083==
==288083== Invalid read of size 1
==288083== at 0x4842B60: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10E4DF: memcpy (string_fortified.h:34)
==288083== by 0x10E4DF: q_remove_head (queue.c:144)
==288083== by 0x10B57A: do_remove_head (qtest.c:368)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Address 0x4ba9040 is 64 bytes inside a block of size 2,049 free'd
==288083== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10B68D: do_remove_head (qtest.c:413)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083== Block was alloc'd at
==288083== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==288083== by 0x10B3B4: do_remove_head (qtest.c:334)
==288083== by 0x10CEA1: interpret_cmda (console.c:224)
==288083== by 0x10D338: interpret_cmd (console.c:247)
==288083== by 0x10DBA0: cmd_select (console.c:601)
==288083== by 0x10DE6D: run_console (console.c:674)
==288083== by 0x10C2D1: main (qtest.c:789)
==288083==
--- trace-01-ops 0/6
```
- 問題分析
- 發現在 q_remove_head 中的 memmove 有發生 invalid read 的情況
### 嘗試解決方式
- 閱讀資料針對 memcpy 可能發生的問題進行解決,在規格書中發現 memcpy 和 memmove 雖然都是複製字串,但是 memcpy 針對 [overlapping](https://cs50.stackexchange.com/questions/14615/memory-overlap-in-c) 的問題, memcpy 會發生未定義行為。
- C99 [7.21.2.1] **The memcpy function**
> The memcpy function copies n characters from the object pointed to by s2 into the
object pointed to by s1. If copying takes place between objects that overlap, the behavior
is undefined.
- 相對 memmove 可以針對 overlapping 進行處置,是透過複製到一個暫存的陣列來解決
- C99 [7.21.2.2] **The memmove function**
> The memmove function copies n characters from the object pointed to by s2 into the
object pointed to by s1. Copying takes place as if the n characters from the object
pointed to by s2 are first copied into a temporary array of n characters that does not
overlap the objects pointed to by s1 and s2, and then the n characters from the
temporary array are copied into the object pointed to by s1.
- memcpy 的好處是效率快速,前提是沒有 overlapping
- 所以將 memcpy 替換成 memmove
### 解決方式
- 發現到 memcpy 中的 size 都是使用 buffersize 並沒有針對
q->head->value 做適度的調整導致 sp 的大小都是 bufsize。
```cpp
memcpy(sp, q->head->value, bufsize);
sp[bufsize - 1] = '\0';
```
- 去檢查原本字串的長度,如果超過 bufsize 則另行處理
```cpp
if (bufsize < string_len + 1) {
memmove(sp, q->head->value, bufsize);
sp[bufsize - 1] = '\0';
} else {
memmove(sp, q->head->value, string_len + 1);
sp[string_len] = '\0';
}
```
### 視覺化 simulation 的記憶體使用量
- 使用 valgrind 中的 massif 進行分析
```bash
valgrind --tool=massif ./qtest -v 3 -f ./traces/trace-17-complexity.cmd
#印出結果
ms_print massif.out.258408
```
- 結果 (直接執行上述實做的 queue)
```
--------------------------------------------------------------------------------
Command: ./qtest -v 3 -f ./traces/trace-17-complexity.cmd
Massif arguments: (none)
ms_print arguments: massif.out.258408
--------------------------------------------------------------------------------
MB
1.231^ #
| #
| #
| # : :
| # : : :
| # : : :: : : @
| # : : :: : : @
| # : : :: : : @ :
| # :: : : : :: : : @ : :
| # : : : :::: : : : @ : :
| #: : : : :::: : : : @: : ::
| #: : ::: : :::: : : : @: : : ::
| #: : ::: : @::::: : : : @::: : : : ::@
| #: : ::: : @ :::: : : : @:: : : : ::@
| #: :: : ::: : : @ :::: : ::: : @:: ::: : : ::@
| #: : : ::: : : @ :::: : :: : @:: :::@: : ::@
| #::: : : :::@: : @ :::: : :: : : : @:: :::@: : ::@
| #:: : : : :::@:::@ : @ ::::::: : :: : : : @:: :::@: ::::@
| #:: : : : :::@:::@ : @ ::::: : : :: ::: ::@:: :::@: ::::@
| #:: : : : :::@:::@:: @ : @ ::::: : ::::: :::@@::@:: :: :::@::::::@
0 +----------------------------------------------------------------------->Gi
0 26.97
Number of snapshots: 65
Detailed snapshots: [1, 2 (peak), 14, 18, 21, 25, 41, 44, 54, 64]
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
0 0 0 0 0 0
1 451,350,369 304,816 250,300 54,516 0
82.12% (250,300B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->76.75% (233,955B) 0x10DEDF: test_malloc (harness.c:138)
| ->41.34% (126,000B) 0x10E375: q_insert_head (queue.c:59)
| | ->41.34% (126,000B) 0x10E9FE: measure (constant.c:65)
| | ->41.34% (126,000B) 0x10EB7E: doit (fixture.c:136)
| | ->41.34% (126,000B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->41.34% (126,000B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->41.34% (126,000B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->41.34% (126,000B) 0x10D338: interpret_cmd (console.c:247)
| | ->41.34% (126,000B) 0x10DBA0: cmd_select (console.c:601)
| | ->41.34% (126,000B) 0x10DE6D: run_console (console.c:674)
| | ->41.34% (126,000B) 0x10C2D1: main (qtest.c:789)
| |
| ->35.36% (107,787B) 0x10E399: q_insert_head (queue.c:64)
| | ->35.36% (107,787B) 0x10E9FE: measure (constant.c:65)
| | ->35.36% (107,787B) 0x10EB7E: doit (fixture.c:136)
| | ->35.36% (107,787B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->35.36% (107,787B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->35.36% (107,787B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->35.36% (107,787B) 0x10D338: interpret_cmd (console.c:247)
| | ->35.36% (107,787B) 0x10DBA0: cmd_select (console.c:601)
| | ->35.36% (107,787B) 0x10DE6D: run_console (console.c:674)
| | ->35.36% (107,787B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.06% (168B) in 1+ places, all below ms_print's threshold (01.00%)
|
->02.98% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->02.70% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->02.70% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->02.70% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.29% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->02.38% (7,249B) in 10 places, all below massif's threshold (1.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
2 744,872,031 1,290,600 1,051,284 239,316 0
81.46% (1,051,284B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->80.19% (1,034,939B) 0x10DEDF: test_malloc (harness.c:138)
| ->43.18% (557,256B) 0x10E375: q_insert_head (queue.c:59)
| | ->43.18% (557,256B) 0x10E9FE: measure (constant.c:65)
| | ->43.18% (557,256B) 0x10EB7E: doit (fixture.c:136)
| | ->43.18% (557,256B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->43.18% (557,256B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->43.18% (557,256B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->43.18% (557,256B) 0x10D338: interpret_cmd (console.c:247)
| | ->43.18% (557,256B) 0x10DBA0: cmd_select (console.c:601)
| | ->43.18% (557,256B) 0x10DE6D: run_console (console.c:674)
| | ->43.18% (557,256B) 0x10C2D1: main (qtest.c:789)
| |
| ->37.00% (477,515B) 0x10E399: q_insert_head (queue.c:64)
| | ->37.00% (477,515B) 0x10E9FE: measure (constant.c:65)
| | ->37.00% (477,515B) 0x10EB7E: doit (fixture.c:136)
| | ->37.00% (477,515B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->37.00% (477,515B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->37.00% (477,515B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->37.00% (477,515B) 0x10D338: interpret_cmd (console.c:247)
| | ->37.00% (477,515B) 0x10DBA0: cmd_select (console.c:601)
| | ->37.00% (477,515B) 0x10DE6D: run_console (console.c:674)
| | ->37.00% (477,515B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.01% (168B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.27% (16,345B) in 11 places, all below massif's threshold (1.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
3 1,196,716,406 705,968 575,645 130,323 0
4 1,525,314,876 273,712 224,842 48,870 0
5 2,195,497,317 49,640 43,108 6,532 0
6 2,590,737,257 28,976 26,331 2,645 0
7 3,086,439,722 445,488 364,123 81,365 0
8 3,814,260,269 201,520 166,510 35,010 0
9 4,121,127,632 34,864 31,125 3,739 0
10 4,581,428,795 787,120 641,617 145,503 0
11 5,246,308,143 629,680 514,129 115,551 0
12 5,757,754,359 600,040 490,065 109,975 0
13 6,249,528,173 1,058,480 861,461 197,019 0
14 6,579,996,777 274,864 226,034 48,830 0
82.23% (226,034B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->76.29% (209,689B) 0x10DEDF: test_malloc (harness.c:138)
| ->41.09% (112,952B) 0x10E375: q_insert_head (queue.c:59)
| | ->41.09% (112,952B) 0x10E9FE: measure (constant.c:65)
| | ->41.09% (112,952B) 0x10EB7E: doit (fixture.c:136)
| | ->41.09% (112,952B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->41.09% (112,952B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->41.09% (112,952B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->41.09% (112,952B) 0x10D338: interpret_cmd (console.c:247)
| | ->41.09% (112,952B) 0x10DBA0: cmd_select (console.c:601)
| | ->41.09% (112,952B) 0x10DE6D: run_console (console.c:674)
| | ->41.09% (112,952B) 0x10C2D1: main (qtest.c:789)
| |
| ->35.17% (96,673B) 0x10E399: q_insert_head (queue.c:64)
| | ->35.17% (96,673B) 0x10E9FE: measure (constant.c:65)
| | ->35.17% (96,673B) 0x10EB7E: doit (fixture.c:136)
| | ->35.17% (96,673B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->35.17% (96,673B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->35.17% (96,673B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->35.17% (96,673B) 0x10D338: interpret_cmd (console.c:247)
| | ->35.17% (96,673B) 0x10DBA0: cmd_select (console.c:601)
| | ->35.17% (96,673B) 0x10DE6D: run_console (console.c:674)
| | ->35.17% (96,673B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.02% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->03.31% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->02.99% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->02.99% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->02.99% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.32% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->02.64% (7,249B) in 10 places, all below massif's threshold (1.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
15 7,075,699,585 394,544 322,629 71,915 0
16 7,488,785,369 200,112 164,754 35,358 0
17 7,819,253,909 837,352 682,465 154,887 0
18 8,232,339,793 211,304 174,359 36,945 0
82.52% (174,359B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->74.78% (158,014B) 0x10DEDF: test_malloc (harness.c:138)
| ->40.28% (85,120B) 0x10E375: q_insert_head (queue.c:59)
| | ->40.28% (85,120B) 0x10E9FE: measure (constant.c:65)
| | ->40.28% (85,120B) 0x10EB7E: doit (fixture.c:136)
| | ->40.28% (85,120B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->40.28% (85,120B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->40.28% (85,120B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->40.28% (85,120B) 0x10D338: interpret_cmd (console.c:247)
| | ->40.28% (85,120B) 0x10DBA0: cmd_select (console.c:601)
| | ->40.28% (85,120B) 0x10DE6D: run_console (console.c:674)
| | ->40.28% (85,120B) 0x10C2D1: main (qtest.c:789)
| |
| ->34.47% (72,830B) 0x10E399: q_insert_head (queue.c:64)
| | ->34.47% (72,830B) 0x10E9FE: measure (constant.c:65)
| | ->34.47% (72,830B) 0x10EB7E: doit (fixture.c:136)
| | ->34.47% (72,830B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->34.47% (72,830B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->34.47% (72,830B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->34.47% (72,830B) 0x10D338: interpret_cmd (console.c:247)
| | ->34.47% (72,830B) 0x10DBA0: cmd_select (console.c:601)
| | ->34.47% (72,830B) 0x10DE6D: run_console (console.c:674)
| | ->34.47% (72,830B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.03% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->04.30% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->03.89% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->03.89% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->03.89% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.42% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->02.29% (4,849B) in 9 places, all below massif's threshold (1.00%)
|
->01.14% (2,400B) 0x10EB30: doit (fixture.c:127)
->01.14% (2,400B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
->01.14% (2,400B) 0x10B7F2: do_insert_tail (qtest.c:263)
->01.14% (2,400B) 0x10CEA1: interpret_cmda (console.c:224)
->01.14% (2,400B) 0x10D338: interpret_cmd (console.c:247)
->01.14% (2,400B) 0x10DBA0: cmd_select (console.c:601)
->01.14% (2,400B) 0x10DE6D: run_console (console.c:674)
->01.14% (2,400B) 0x10C2D1: main (qtest.c:789)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
19 8,810,659,780 65,512 56,001 9,511 0
20 9,471,596,719 48,688 42,333 6,355 0
21 9,884,682,472 91,880 77,400 14,480 0
84.24% (77,400B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->66.45% (61,055B) 0x10DEDF: test_malloc (harness.c:138)
| ->35.72% (32,816B) 0x10E375: q_insert_head (queue.c:59)
| | ->35.72% (32,816B) 0x10E9FE: measure (constant.c:65)
| | ->35.72% (32,816B) 0x10EB7E: doit (fixture.c:136)
| | ->35.72% (32,816B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->35.72% (32,816B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->35.72% (32,816B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->35.72% (32,816B) 0x10D338: interpret_cmd (console.c:247)
| | ->35.72% (32,816B) 0x10DBA0: cmd_select (console.c:601)
| | ->35.72% (32,816B) 0x10DE6D: run_console (console.c:674)
| | ->35.72% (32,816B) 0x10C2D1: main (qtest.c:789)
| |
| ->30.55% (28,071B) 0x10E399: q_insert_head (queue.c:64)
| | ->30.55% (28,071B) 0x10E9FE: measure (constant.c:65)
| | ->30.55% (28,071B) 0x10EB7E: doit (fixture.c:136)
| | ->30.55% (28,071B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->30.55% (28,071B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->30.55% (28,071B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->30.55% (28,071B) 0x10D338: interpret_cmd (console.c:247)
| | ->30.55% (28,071B) 0x10DBA0: cmd_select (console.c:601)
| | ->30.55% (28,071B) 0x10DE6D: run_console (console.c:674)
| | ->30.55% (28,071B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.18% (168B) in 1+ places, all below ms_print's threshold (01.00%)
|
->09.90% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->08.94% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->08.94% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->08.94% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.96% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->02.61% (2,400B) 0x10EB30: doit (fixture.c:127)
| ->02.61% (2,400B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| ->02.61% (2,400B) 0x10B7F2: do_insert_tail (qtest.c:263)
| ->02.61% (2,400B) 0x10CEA1: interpret_cmda (console.c:224)
| ->02.61% (2,400B) 0x10D338: interpret_cmd (console.c:247)
| ->02.61% (2,400B) 0x10DBA0: cmd_select (console.c:601)
| ->02.61% (2,400B) 0x10DE6D: run_console (console.c:674)
| ->02.61% (2,400B) 0x10C2D1: main (qtest.c:789)
|
->01.31% (1,208B) 0x10EAE8: doit (fixture.c:122)
| ->01.31% (1,208B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| ->01.31% (1,208B) 0x10B7F2: do_insert_tail (qtest.c:263)
| ->01.31% (1,208B) 0x10CEA1: interpret_cmda (console.c:224)
| ->01.31% (1,208B) 0x10D338: interpret_cmd (console.c:247)
| ->01.31% (1,208B) 0x10DBA0: cmd_select (console.c:601)
| ->01.31% (1,208B) 0x10DE6D: run_console (console.c:674)
| ->01.31% (1,208B) 0x10C2D1: main (qtest.c:789)
|
->01.31% (1,208B) 0x10EAF8: doit (fixture.c:123)
| ->01.31% (1,208B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| ->01.31% (1,208B) 0x10B7F2: do_insert_tail (qtest.c:263)
| ->01.31% (1,208B) 0x10CEA1: interpret_cmda (console.c:224)
| ->01.31% (1,208B) 0x10D338: interpret_cmd (console.c:247)
| ->01.31% (1,208B) 0x10DBA0: cmd_select (console.c:601)
| ->01.31% (1,208B) 0x10DE6D: run_console (console.c:674)
| ->01.31% (1,208B) 0x10C2D1: main (qtest.c:789)
|
->01.31% (1,200B) 0x10EB08: doit (fixture.c:124)
| ->01.31% (1,200B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| ->01.31% (1,200B) 0x10B7F2: do_insert_tail (qtest.c:263)
| ->01.31% (1,200B) 0x10CEA1: interpret_cmda (console.c:224)
| ->01.31% (1,200B) 0x10D338: interpret_cmd (console.c:247)
| ->01.31% (1,200B) 0x10DBA0: cmd_select (console.c:601)
| ->01.31% (1,200B) 0x10DE6D: run_console (console.c:674)
| ->01.31% (1,200B) 0x10C2D1: main (qtest.c:789)
|
->01.11% (1,024B) 0x4A2AE83: _IO_file_doallocate (filedoalloc.c:101)
| ->01.11% (1,024B) 0x4A3B04F: _IO_doallocbuf (genops.c:347)
| ->01.11% (1,024B) 0x4A3A0AF: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:745)
| | ->01.11% (1,024B) 0x4A38834: _IO_new_file_xsputn (fileops.c:1244)
| | ->01.11% (1,024B) 0x4A38834: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1197)
| | ->01.11% (1,024B) 0x4A1FAF1: __vfprintf_internal (vfprintf-internal.c:1373)
| | ->01.11% (1,024B) 0x10C8C9: vfprintf (stdio2.h:130)
| | ->01.11% (1,024B) 0x10C8C9: report_noreturn (report.c:122)
| | ->01.11% (1,024B) 0x10DB5E: readline (console.c:534)
| | ->01.11% (1,024B) 0x10DB5E: cmd_select (console.c:599)
| | ->01.11% (1,024B) 0x10DE6D: run_console (console.c:674)
| | ->01.11% (1,024B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
|
->00.23% (209B) in 1+ places, all below ms_print's threshold (01.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
22 10,417,751,127 23,984 22,279 1,705 0
23 11,017,665,208 222,640 183,631 39,009 0
24 11,497,596,509 47,792 41,589 6,203 0
25 12,097,510,777 518,248 423,278 94,970 0
81.67% (423,278B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->78.52% (406,933B) 0x10DEDF: test_malloc (harness.c:138)
| ->42.34% (219,408B) 0x10E375: q_insert_head (queue.c:59)
| | ->42.34% (219,408B) 0x10E9FE: measure (constant.c:65)
| | ->42.34% (219,408B) 0x10EB7E: doit (fixture.c:136)
| | ->42.34% (219,408B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->42.34% (219,408B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->42.34% (219,408B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->42.34% (219,408B) 0x10D338: interpret_cmd (console.c:247)
| | ->42.34% (219,408B) 0x10DBA0: cmd_select (console.c:601)
| | ->42.34% (219,408B) 0x10DE6D: run_console (console.c:674)
| | ->42.34% (219,408B) 0x10C2D1: main (qtest.c:789)
| |
| ->36.17% (187,461B) 0x10E399: q_insert_head (queue.c:64)
| | ->36.17% (187,461B) 0x10E9FE: measure (constant.c:65)
| | ->36.17% (187,461B) 0x10EB7E: doit (fixture.c:136)
| | ->36.17% (187,461B) 0x10EDD6: is_insert_tail_const (fixture.c:168)
| | ->36.17% (187,461B) 0x10B7F2: do_insert_tail (qtest.c:263)
| | ->36.17% (187,461B) 0x10CEA1: interpret_cmda (console.c:224)
| | ->36.17% (187,461B) 0x10D338: interpret_cmd (console.c:247)
| | ->36.17% (187,461B) 0x10DBA0: cmd_select (console.c:601)
| | ->36.17% (187,461B) 0x10DE6D: run_console (console.c:674)
| | ->36.17% (187,461B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.01% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.76% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->01.59% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->01.59% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->01.59% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.17% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.40% (7,249B) in 10 places, all below massif's threshold (1.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
26 12,457,459,255 580,072 473,733 106,339 0
27 13,057,373,388 970,088 790,451 179,637 0
28 13,417,321,965 764,976 623,253 141,723 0
29 14,017,235,984 1,125,296 916,184 209,112 0
30 14,377,184,366 993,072 809,010 184,062 0
31 14,857,115,714 215,272 177,607 37,665 0
32 15,577,012,612 1,144,552 931,820 212,732 0
33 16,056,943,800 23,656 22,024 1,632 0
34 16,627,378,405 257,840 212,026 45,814 0
35 17,288,316,182 93,104 78,407 14,697 0
36 17,949,253,519 1,027,888 837,327 190,561 0
37 18,279,722,221 388,656 318,568 70,088 0
38 18,940,659,559 261,864 215,480 46,384 0
39 19,601,597,277 134,576 112,087 22,489 0
40 20,097,300,581 725,864 592,461 133,403 0
41 20,427,769,452 125,104 104,329 20,775 0
83.39% (104,329B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->70.33% (87,982B) 0x10DEDF: test_malloc (harness.c:138)
| ->37.91% (47,432B) 0x10E375: q_insert_head (queue.c:59)
| | ->37.91% (47,432B) 0x10EAA3: measure (constant.c:76)
| | | ->37.91% (47,432B) 0x10EB7E: doit (fixture.c:136)
| | | ->37.91% (47,432B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->37.91% (47,432B) 0x10AE1A: do_size (qtest.c:482)
| | | ->37.91% (47,432B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->37.91% (47,432B) 0x10D338: interpret_cmd (console.c:247)
| | | ->37.91% (47,432B) 0x10DBA0: cmd_select (console.c:601)
| | | ->37.91% (47,432B) 0x10DE6D: run_console (console.c:674)
| | | ->37.91% (47,432B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->32.36% (40,486B) 0x10E399: q_insert_head (queue.c:64)
| | ->32.36% (40,486B) 0x10EAA3: measure (constant.c:76)
| | | ->32.36% (40,486B) 0x10EB7E: doit (fixture.c:136)
| | | ->32.36% (40,486B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->32.36% (40,486B) 0x10AE1A: do_size (qtest.c:482)
| | | ->32.36% (40,486B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->32.36% (40,486B) 0x10D338: interpret_cmd (console.c:247)
| | | ->32.36% (40,486B) 0x10DBA0: cmd_select (console.c:601)
| | | ->32.36% (40,486B) 0x10DE6D: run_console (console.c:674)
| | | ->32.36% (40,486B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->00.05% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->07.27% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->06.57% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->06.57% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->06.57% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.70% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->03.88% (4,851B) in 10 places, all below massif's threshold (1.00%)
|
->01.92% (2,400B) 0x10EB30: doit (fixture.c:127)
->01.92% (2,400B) 0x10EEB7: is_size_const (fixture.c:188)
| ->01.92% (2,400B) 0x10AE1A: do_size (qtest.c:482)
| ->01.92% (2,400B) 0x10CEA1: interpret_cmda (console.c:224)
| ->01.92% (2,400B) 0x10D338: interpret_cmd (console.c:247)
| ->01.92% (2,400B) 0x10DBA0: cmd_select (console.c:601)
| ->01.92% (2,400B) 0x10DE6D: run_console (console.c:674)
| ->01.92% (2,400B) 0x10C2D1: main (qtest.c:789)
|
->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
42 21,088,706,911 311,472 255,648 55,824 0
43 21,584,410,151 179,760 148,603 31,157 0
44 22,080,113,397 979,816 797,457 182,359 0
81.39% (797,457B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->79.72% (781,110B) 0x10DEDF: test_malloc (harness.c:138)
| ->43.00% (421,344B) 0x10E375: q_insert_head (queue.c:59)
| | ->43.00% (421,344B) 0x10EAA3: measure (constant.c:76)
| | | ->43.00% (421,344B) 0x10EB7E: doit (fixture.c:136)
| | | ->43.00% (421,344B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->43.00% (421,344B) 0x10AE1A: do_size (qtest.c:482)
| | | ->43.00% (421,344B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->43.00% (421,344B) 0x10D338: interpret_cmd (console.c:247)
| | | ->43.00% (421,344B) 0x10DBA0: cmd_select (console.c:601)
| | | ->43.00% (421,344B) 0x10DE6D: run_console (console.c:674)
| | | ->43.00% (421,344B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->36.71% (359,702B) 0x10E399: q_insert_head (queue.c:64)
| | ->36.71% (359,702B) 0x10EAA3: measure (constant.c:76)
| | | ->36.71% (359,702B) 0x10EB7E: doit (fixture.c:136)
| | | ->36.71% (359,702B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->36.71% (359,702B) 0x10AE1A: do_size (qtest.c:482)
| | | ->36.71% (359,702B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->36.71% (359,702B) 0x10D338: interpret_cmd (console.c:247)
| | | ->36.71% (359,702B) 0x10DBA0: cmd_select (console.c:601)
| | | ->36.71% (359,702B) 0x10DE6D: run_console (console.c:674)
| | | ->36.71% (359,702B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->00.01% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.67% (16,347B) in 12 places, all below massif's threshold (1.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
45 22,410,582,233 691,504 564,228 127,276 0
46 22,906,285,509 575,408 470,207 105,201 0
47 23,567,223,065 102,120 85,737 16,383 0
48 24,228,160,705 47,848 41,635 6,213 0
49 24,558,629,618 413,360 338,365 74,995 0
50 24,852,151,295 309,352 253,855 55,497 0
51 25,145,673,018 803,944 655,724 148,220 0
52 25,439,194,714 441,576 361,213 80,363 0
53 25,732,716,420 338,920 277,857 61,063 0
54 26,026,238,269 375,984 308,165 67,819 0
81.96% (308,165B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->77.61% (291,818B) 0x10DEDF: test_malloc (harness.c:138)
| ->41.81% (157,192B) 0x10E375: q_insert_head (queue.c:59)
| | ->41.81% (157,192B) 0x10EAA3: measure (constant.c:76)
| | | ->41.81% (157,192B) 0x10EB7E: doit (fixture.c:136)
| | | ->41.81% (157,192B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->41.81% (157,192B) 0x10AE1A: do_size (qtest.c:482)
| | | ->41.81% (157,192B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->41.81% (157,192B) 0x10D338: interpret_cmd (console.c:247)
| | | ->41.81% (157,192B) 0x10DBA0: cmd_select (console.c:601)
| | | ->41.81% (157,192B) 0x10DE6D: run_console (console.c:674)
| | | ->41.81% (157,192B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->35.79% (134,562B) 0x10E399: q_insert_head (queue.c:64)
| | ->35.79% (134,562B) 0x10EAA3: measure (constant.c:76)
| | | ->35.79% (134,562B) 0x10EB7E: doit (fixture.c:136)
| | | ->35.79% (134,562B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->35.79% (134,562B) 0x10AE1A: do_size (qtest.c:482)
| | | ->35.79% (134,562B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->35.79% (134,562B) 0x10D338: interpret_cmd (console.c:247)
| | | ->35.79% (134,562B) 0x10DBA0: cmd_select (console.c:601)
| | | ->35.79% (134,562B) 0x10DE6D: run_console (console.c:674)
| | | ->35.79% (134,562B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->00.02% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->02.42% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->02.19% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->02.19% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->02.19% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.23% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.93% (7,251B) in 11 places, all below massif's threshold (1.00%)
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
55 26,319,760,052 627,304 512,013 115,291 0
56 26,613,281,750 87,728 74,028 13,700 0
57 26,906,803,465 106,856 89,523 17,333 0
58 27,200,325,223 553,392 452,071 101,321 0
59 27,493,846,934 201,704 166,547 35,157 0
60 27,787,368,701 697,960 569,144 128,816 0
61 28,080,890,458 595,944 486,374 109,570 0
62 28,374,412,178 895,280 729,489 165,791 0
63 28,667,933,895 219,368 180,804 38,564 0
64 28,961,455,583 521,904 426,399 95,505 0
81.70% (426,399B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->78.57% (410,052B) 0x10DEDF: test_malloc (harness.c:138)
| ->42.35% (221,032B) 0x10E375: q_insert_head (queue.c:59)
| | ->42.35% (221,032B) 0x10EAA3: measure (constant.c:76)
| | | ->42.35% (221,032B) 0x10EB7E: doit (fixture.c:136)
| | | ->42.35% (221,032B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->42.35% (221,032B) 0x10AE1A: do_size (qtest.c:482)
| | | ->42.35% (221,032B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->42.35% (221,032B) 0x10D338: interpret_cmd (console.c:247)
| | | ->42.35% (221,032B) 0x10DBA0: cmd_select (console.c:601)
| | | ->42.35% (221,032B) 0x10DE6D: run_console (console.c:674)
| | | ->42.35% (221,032B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->36.21% (188,956B) 0x10E399: q_insert_head (queue.c:64)
| | ->36.21% (188,956B) 0x10EAA3: measure (constant.c:76)
| | | ->36.21% (188,956B) 0x10EB7E: doit (fixture.c:136)
| | | ->36.21% (188,956B) 0x10EEB7: is_size_const (fixture.c:188)
| | | ->36.21% (188,956B) 0x10AE1A: do_size (qtest.c:482)
| | | ->36.21% (188,956B) 0x10CEA1: interpret_cmda (console.c:224)
| | | ->36.21% (188,956B) 0x10D338: interpret_cmd (console.c:247)
| | | ->36.21% (188,956B) 0x10DBA0: cmd_select (console.c:601)
| | | ->36.21% (188,956B) 0x10DE6D: run_console (console.c:674)
| | | ->36.21% (188,956B) 0x10C2D1: main (qtest.c:789)
| | |
| | ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
| |
| ->00.01% (64B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.74% (9,096B) 0x10C946: malloc_or_fail (report.c:189)
| ->01.57% (8,216B) 0x10CFF9: push_file (console.c:457)
| | ->01.57% (8,216B) 0x10DDDE: run_console (console.c:659)
| | ->01.57% (8,216B) 0x10C2D1: main (qtest.c:789)
| |
| ->00.17% (880B) in 1+ places, all below ms_print's threshold (01.00%)
|
->01.39% (7,251B) in 11 places, all below massif's threshold (1.00%)
```
## web server 實作
- web-server 引用自 [tiny-web_server](https://github.com/7890/tiny-web-server)
- 修正裡面使用 sprintf 的實作,改用 snprintf ,對於長度過長不會發生溢位。
- 修正 local variable 的 scope ,不需要宣告在較大的 scope 中。
- 新增 web 指令在 qtest 中,可以開啟 web server
```cpp
add_cmd("web", do_open_web, " | run a webserver");
```
- 新增 closeweb 指令在 qtest 中,可以關閉 web-server
```cpp
add_cmd("closeweb", do_close_web, " | close webserver");
```
- 若沒手動關閉 web server ,程式也會在 quit 後,自動關閉 web server
- 目前為了讓 web server 可以在 qtest 的背景執行,使用 fork 實作,之後會改成 coroutine