라벨이 pointer인 게시물 표시

2018년 9번째 주

이 포스팅은 그냥 지난 한 주간 읽었던 것들을 정리하는 포스트입니다. 그냥 예전에 봤던 글 중 나중에 필요한데 뭐였는지 기억 안 나는 글들이 있어서 쓰기 시작했습니다.
 보통 하는 일과 관련된 글들이 올라오겠지만 딱히 정해둔 주제는 없고, 그때그때 관심 있었던 것을 읽었기 때문에 지난주에 쓰인 글일 수도 있고 몇 년 전에 쓰인 글일 수도 있습니다.Lifetime Safety: Preventing Leaks and DanglingHerb Sutter와 Neil MacIntosh가 쓴 C++에서 memory leakdangling pointer를 어떻게 없앨 수 있는지에 관한 글이다. 일반적으로 C++의 포인터는 매우 강력하기 때문에, memory leak이나 dangling pointer를 없애기 위해서 C++의 기능을 일부 제한하거나 새로운 문법을 추가하거나 한다. 하지만 이 글에서는 언어를 바꾸지 않으면서 런타임 오버헤드 없이 컴파일 타임에 분석할 수 있는 알고리즘을 제시한다.
 특히 이 알고리즘은 프로그램 전체를 분석하는 것이 아니라 함수 단위, 정확히는 블록 단위로 적용할 수 있고, 변수 재사용 등 많은 스타일 가이드에서 권하지 않지만 실제로는 많이 사용되는 패턴들에 대해서도 고려돼있기 때문에 레거시 코드에 적용하기도 좋다.
 기계적인 작업이기 때문에 툴을 만드는 것이 가장 좋을 것이다. 하지만 툴을 만들 여유가 없더라도 포인터나 레퍼런스를 어떻게 써야 안전한지 보여주는 좋은 글이기 때문에 일단 읽어보는 것을 추천한다.GitHub DDoS 공격당함 지난 2018년 2월 28일, GitHubDistributed Denial-of-Service(a.k.a. DDoS) 공격을 당해 약 10분 정도 서비스가 멈췄었다. 이 공격은 memcached를 이용한 공격으로 중국의 0kee team이 찾은 Deluge라는 기법을 이용한 공격이었다.
 Deluge는 다른 서버에 설치된 memcached에 데이터를 요청할 때 source IP를 목표가 되는 서버의 …

[C] tagged pointer - 포인터에 정보 담기

Tagged pointer는 메모리 크기를 줄이기 위한 고전적인 테크닉이다. 기본적인 아이디어는 포인터의 모든 값이 의미 있는 값은 아니라는 것이다. 예를 들어 4 byte 단위로 align 되는 객체의 32-bit 포인터를 생각해보자. 그렇다면 이 객체의 주소는 4로 나누어 떨어지는 값이 돼야 하니 LSB(Least Significant Bit)으로 부터 2 bit은 언제나 0b00으로 고정될 것이다. 그렇다면 이 2 bit을 다른 정보를 담는 데 써도 아무 문제가 없다. 조금 더 구체적으로 경우 포인터의 값이 0x5678FFF0, 0x5678FFF1, 0x5678FFF2, 0x5678FFF3인 경우 모두 0x5678FFF0에 있는 객체를 가리키도록 하고, 0x5678FFF4, 0x5678FFF5, 0x5678FFF6, 0x5678FFF7인 경우 모두 0x5678FFF4를 가리키는 포인터로 해석하는 것이다. Tagged pointer를 만드는데 LSB 만 쓸 수 있는 건 아니다. 보통 user space에서 쓸 수 있는 최대 메모리가 제한돼 있다. 예를 들어 32-bit 윈도우에서 user space는 최대 3GB 까지 늘릴 수 있지만, 기본적으로 2GB이다. 즉, MSB(Most Significant Bit) 1 bit를 tag에 쓸 수 있다. 64-bit 리눅스라면, 프로세스당 최대 메모리 스페이스는 256 TB까지 이므로 48 bit만 사용된다. 즉, MSB로부터 16 bit를 tag에 사용할 수 있다. 하지만 위의 두 예시에서 보았듯이 tag에 이용할 수 있는 MSB의 크기는 시스템별로 다르다. 따라서 MSB를 tagged pointer로 사용하는 경우 portable 한 코드를 만들기 어려워진다. Tagged pointer를 모든 포인터에 일반적으로 적용하지 않아도 된다. 그보다는 테이블같은 것에 저장할 포인터에만 사용하거나 포인터를 리턴하는 함수에 대해서만 사용하는 것이 일반적이다. 특히 포인터와 추가 정보를 리턴하는 함수를 tagged poi…

[CppCoreGuidelines] 포인터 구분해서 쓰기 - span, owner

C++을 쓰는 사람들이 가장 어려워하는 것 중 하나가 포인터다. 그중에서도 함수 포인터를 읽고 해석하는 것이 가장 어렵다고 한다. 하지만 실제 코드에서는 함수 포인터를 볼 일은 거의 없다. 특히 modern c++에서는 가능하면 std::function를 쓰는 걸 권장하기 때문에 몇몇 특수한 목적을 가진 코드를 제외하고는 함수 포인터를 볼 일은 거의 없다. 그다음으로 어려운 것은 메모리 관리다. C++에서 전통적으로 많이 발생하던 문제가 double free와 memory leak이다. 이는 C++에서 포인터로 가리키는 객체의 소유권이 명확하지 않기 때문이었다. 이를 해결하기 위해 C++11에서는 소유권을 혼자 차지하고 있는 std::unique_ptr과 소유권을 공유하는 std::shared_ptr을 만들었다. std::unique_ptr과 std::shared_ptr을 잘 활용하면 dobule free와 memory leak은 예방할 수 있다. 하지만 C++11 이후에도 여전히 포인터는 다양한 역할을 가지고 있다. 현재 C++의 포인터에 남은 역할은 다음과 같다.std::unique_ptr을 사용하지 않지만, 소유권을 넘길 때함수의 인자로 배열을 넘길 때문자열을 가리킬 때소유권을 넘기지 않고 하나의 객체를 가리킬 때스마트 포인터를 사용하지 않지만, 소유권을 넘길 때 앞에서 말했듯이 C++11은 std::unique_ptr과 std::shared_ptr를 도입하여 소유권을 관리할 수 있도록 하였다. 하지만 스마트 포인터를 사용하지 못하는 경우도 있다. 이 경우 적절한 지점에서 객체를 소멸시켜줘야 한다. 하지만 이를 지칭하는 것이 단순히 포인터이기 때문에, 메모리를 소멸시켰는지, 한 번만 소멸시켰는지 알기 어렵다. 그래서 C++ Core Guidelines에서는 이 경우 owner<T>라는 클래스를 사용하는 것을 권장한다. owner<T> 클래스는 아무런 일도 하지 않는 클래스다. 사실 클래스일 필요도 없기에 GSL에서는 포인터의 al…