# [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 ...