# [AIdrifter CS 浮生筆錄](https://hackmd.io/s/rypeUnYSb) <br> RD Rule For Coding Style ## Four Guide Rule - Check input - Function Input Parameter - User Input - Check return value - You can not assume all value get success - `fopen()`, `malloc()`, `socket open()`… etc - 如果失敗後會有不同的行為,就應該檢查 - No Magic number, no hard-coded string - You can not use `strcpy()`, `strcat()`, `sprintf()`, `get()` - replace n series `strncpy()`, `strncat()`, `snprintf()`, `fgets()` - Rember to release all source when process`exit()` - C++ API 使用 return value (不是 throw exception) ## Student Coding Style ```C void addExt(char *s) { strcat(s,".dat"); } main() { char s[10]; strcpy(s,"abc"); addExt(s); printf("%s",s); } ``` ## Engineer Coding Style ```C #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include <unistd.h> /* 1. No Magic Numnber */ #define SUCCESS 0 #define ERR_PARAM -1 #define ERR_BUF_SIZE -2 #define LEN 10 #define MP4 ".mp4" int addMP4(char *s, int nLen) { /* 2. Check all input parameter */ if (s == NULL) return ERR_PARAM; /* 3. Check array buffer size */ if (strlen(s) + strlen(MP4) >= nLen) return ERR_BUF_SIZE; /* * If src contains n or more bytes, strncat() writes n+1 bytes to dest * (n from src plus the terminating null byte). * Therefore, the size of dest must be at least strlen(dest)+n+1 */ strncat(s, MP4, nLen - strlen(s) - 1); s[nLen-1] = '\0'; // [FIXME] I don't think so, original strncat() has "\0" return SUCCESS; } int main() { int ret = 0; char s[LEN]; /* 6. Prevent buffer overflow */ strncpy(s, "video", LEN-1); // copy size < LEN -1 s[Len - 1] = '\0'; // make sure string has '\0' /* 4. Check return value */ ret = addMP4(s, LEN); if (ret != SUCCESS) { /* 5. Error Handling */ printf("buffer is too small\n"); return ERR_BUF_SIZE; } else printf("%s",s); return SUCCESS; } ``` ### strncpy() and strncat() sample code - `strncpy()` ```C char * strncpy(char *dest, const char *src, size_t n) { size_t i; for (i = 0; i < n && src[i] != '\0'; i++) dest[i] = src[i]; for ( ; i < n; i++) dest[i] = '\0'; return dest; } ``` ![strncpy()](https://i.imgur.com/OKWdsHm.png =x300 ) - `strncat()` ```C char * strncat(char *dest, const char *src, size_t n) { size_t dest_len = strlen(dest); size_t i; for (i = 0 ; i < n && src[i] != '\0' ; i++) dest[dest_len + i] = src[i]; dest[dest_len + i] = '\0'; return dest; } ``` ![strncat()](https://i.imgur.com/UUYtu4d.png =x300) ## Naming Rules - varaible need meaning - i,j,k,l,m,n is loop index only - function name need meaning - Local,Global,Constant,Class - Const : 全大寫,底線隔開(M_PI,_MAX_PATH) - Global : 前面加上 g_ ,(g_nIndex) - Class : 前面加上 m_,(m_szName) - Local : - 單字頭字母大寫?(nLastArray) - 單字之間用底線隔開?(last_array) ## Memory Layout ### Call Stack - Stack overflow - Local var is too much - Recursive is too much - Stack default size: `1Mb` - Buffer overflow - String length is too much, cover original ret addr, - Buffer **overrun**: - 導致 function return 的時候跳到本來無法到達的地方 ![Call Stack](https://i.imgur.com/OwExLFE.png =x300) ### Stack and Heap ![Stack and Heap](https://i.imgur.com/XeXzhIV.png =x300) ### Linux Memory Layout - text segment - machine-language instructions can **share with threads or process** and **read only** - initialized **data** segment - global and static variables have initialized value - uninitialized data segment(**bss**) - global and static variables don't have initialized value - `static char mbuf[10240000];` // binary file is 8.7k - `static char mbuf[10240000]={1};` // binary file is 9.8M - stack segment: - stack frame, each function's - local variable - argument - return value(next instructions). - heap segment: - C: `malloc()`, `calloc()`, `realloc()`, and `free()` - C++: `new` and `delete` - program break can adjust size via `brk()` and `sbrk()` to change **heap segment** size. - Summary - ==text、 initialized data、 bss==這些segment在程式執行的時候就已經確定大小了 ![Process Memory Layout](https://i.imgur.com/oBLAjSp.png) ```C #include <stdio.h> #include <stdlib.h> char globBuf[65536]; /* Uninitialized data segment */ int primes[] = { 2, 3, 5, 7 }; /* Initialized data segment */ static int square(int x) /* Allocated in frame for square() */ { int result; /* Allocated in frame for square() */ result = x * x; return result; /* Return value passed via register */ } static void doCalc(int val) /* Allocated in frame for doCalc() */ { printf("The square of %d is %d\n", val, square(val)); if (val < 1000) { int t; /* Allocated in frame for doCalc() */ t = val * val * val; printf("The cube of %d is %d\n", val, t); } } int main(int argc, char *argv[]) /* Allocated in frame for main() */ { static int key = 9973; /* Initialized data segment */ static char mbuf[10240000]; /* Uninitialized data segment */ char *p; /* Allocated in frame for main() */ p = malloc(1024); /* Points to memory in heap segment */ doCalc(key); exit(EXIT_SUCCESS); } ``` Reference: [ Ping Blog process memey laout 初淺認識](https://pinglinblog.wordpress.com/2016/10/18/linux-%E7%A8%8B%E5%BA%8F%E7%9A%84-memory-layout-%E5%88%9D%E6%B7%BA%E8%AA%8D%E8%AD%98) ## Defensive Programming - Don't rely on Compiler - 程式碼任何地方會去檢查【該檢查】的部分 - Defensive Programming,程式不會有下列問題 - Crash - Buffer overflow - Memory leak - Double free - Race condition - 基本的安全性問題 - etc ...