[CSAPP] C Review
C언어를 사용해 CS:APP의 LAB을 진행하면서 저지르기 쉬운 실수들을 정리해둔 게시물입니다.
아래의 내용은 모두 저자의 강의에서 소개된 예시들을 옮긴 것입니다.
int foo(unsigned int u) {
return (u > -1) ? 1 : 0;
}
u
가 unsigned
이므로 -1 역시 unsigned
로 implicit casting
된다.
-1의 binary expression은 111...1
이므로 자동으로 UNSIGNED_MAX
가 되어 원래의 의도와 다르게 작동하게 된다.
int main() {
int* a = malloc(100*sizeof(int));
for (int i=0; i<100 ; i++) {
a[i] = i / a[i];
}
free(a);
return 0;
}
a
를 초기화하지 않았기 때문에 main()
의 행동이 정의되지 않은 상태다.
main()
이 실행될 때마다 행동이 달라지고, 때로는 zero division error
가 발생한다.
int main() {
char w[strlen("C programming")];
strcpy(w, "C programming");
printf("%s\n", w);
return 0;
}
strlen()
은 문자열의 끝에 오는 null
은 문자열의 길이로 계산하지 않는다.
따라서, strcpy()
가 진행되며 null
에 의해 준비된 buffer
를 1 byte 초과해서 적게 된다. 즉, buffer overflow
.
struc ht_node {
int key;
int data;
};
typedef struct ht_node* node;
node makeNode(int k, int e) {
node curr = malloc(sizeof(node));
curr->key = k;
curr->data = e;
return curr;
}
여기서 node
는 struct
가 아닌 pointer
이다. 그러므로, 32-bit System
인지 64-bit System
인지에 따라 malloc()
이 4 byte 또는 8 byte를 return하게되고, 전자의 경우 해당 공간에 struct
의 전체 내용을 담지 못할 수도 있다.
또, 메모리를 할당해줬으면 free()
를 통해 메모리를 해제해줘야 한다.
char *strcdup(int n, char c) {
char dup[n+1];
int i;
for (i=0; i<n; i++)
dup[i] = c;
dup[i] = '\0';
char *A = dup;
return A;
}
위에서 dup
배열을 local variable로 선언했다. 이 경우 해당 함수의 stack frame 내에 원소들이 저장된다.
문제는, 이 함수가 종료되고 나면, stack pointer
는 다시 더 높은 메모리 주소를 가리키게 되며 이후 프로그램이 더 작동하며 원래의 dup
배열의 내용이 overwrite 될 수 있다는 점이다.
그럼에도 A
는 계속 원래의 dup
의 시작주소를 가리키고 있을 것이다. 프로그래머는 dup
의 내용물이 변경된 줄 모르고 사용하게 될 위험이 있다.
#define IS_GREATER(a, b) a > b
inline int isGreater(int a, int b) {
return a > b ? 1 : 0;
}
int m1 = IS_GREATER(1, 0) + 1;
int m2 = isGreater(1, 0) + 1;
원래는 IS_GREATER
과 isGreater()
이 같은 작동을 하도록 의도되었을 것이다.
하지만 IS_GREATER
는 매크로이다. 괄호로 감싸져 있지 않기 때문에, m1
의 경우 1 > 0 + 1
로 대체되고, 원래의 의도와 달리 0을 return하게 된다.
#define NEXT_BYTE(a) ((char*) (a+1))
//여기서 NEXT_BYTE(a)의 의도는 a의 시작주소 바로 다음 주소를 return 하는 것이다.
main() {
int a1 = 54; //&a1 = 0x100 이라 가정한다.
long long a2 = 42; //&a2 = 0x200 이라 가정한다.
void* b1 = NEXT_BYTE(&a1); //0x104
void* b2 = NEXT_BYTE(&a2); //0x108
}
pointer arithmetic에서 발생할 수 있는 문제다. pointer arithmetic은 해당 type의 size에 영향을 받는다. 그러므로, 주석에 적혀있는 의도와 달리 작동하게 되는 것이다. int
인 a1
을 가리키는 포인터인 &a1
에 1을 더한 &a1 + 1
의 결과는 (a1의 주소값) + 0x4
와 같다.
원래의 의도대로라면 ((char*)a + 1)
로 작성해줘야 한다.
Comments