programing

C 표준 라이브러리의 어떤 기능이 일반적으로 나쁜 관행을 장려합니까?

firstcheck 2022. 7. 27. 21:59
반응형

C 표준 라이브러리의 어떤 기능이 일반적으로 나쁜 관행을 장려합니까?

이것은 이 질문과 내가 배운 하나의 특정 답변에 대한 코멘트에서 영감을 얻었다.strncpyC의 안전한 문자열 처리 기능은 아니며, 0에 도달할 때까지 패딩됩니다.n내가 몰랐던 어떤 것.

구체적으로 R을 인용하자면..

strncpy는 null-pading을 하지 않고 수신처 버퍼의 나머지 부분 전체를 null-pading하므로 시간 낭비가 큽니다.독자적인 늘 패딩을 추가하는 것으로, 전자를 회피할 수 있습니다만, 후자는 할 수 없습니다.이것은 "안전 문자열 처리" 함수로 사용하는 것이 아니라 Unix 디렉토리 테이블 및 데이터베이스 파일의 고정 크기 필드를 사용하기 위한 것입니다. snprintf(dest, n, %s, src)는 표준 C에서 유일하게 올바른 "안전 문자열 처리"이지만 훨씬 느릴 수 있습니다.그런데 잘라내는 것 자체가 주요 버그가 될 수 있고 경우에 따라서는 권한 상승이나 DoS가 발생할 수 있으므로, 문제에 대해 출력을 잘라내는 "안전" 문자열 함수를 던지는 것은 "안전"하거나 "안전"하게 만드는 방법이 아닙니다.대신에, 행선지 버퍼의 사이즈가 적절한 것을 확인해, strcpy(또는 송신원스트링의 길이를 이미 알고 있는 경우는 memcpy)를 사용해 주세요.

그리고 Jonathan Leffler로부터

strncat()은 strncpy()보다 인터페이스에서 더 혼란스럽다는 점에 주의해 주십시오.그 길이 인수는 정확히 무엇입니까?strncpy() 등의 제공 내용에 근거하지 않기 때문에 strncpy()보다 오류가 발생하기 쉽습니다.문자열을 복사하는 경우, 항상 미리 모든 크기를 알고 미리 충분한 공간을 확보해야 하기 때문에 memmove()만 필요하다는 의견이 점점 강해지고 있습니다.strcpy(), strcat(), strncpy(), strncpy(), strncat(), memcpy() 중 하나를 우선적으로 사용합니다.

C 스탠다드 도서관은 확실히 낯설어요그래서 저는 다음과 같은 질문을 하고 싶습니다.

보안 문제/코드 결함/비효율을 유발하거나 초래할 수 있는 부적절하게 사용되는 C 표준 라이브러리 기능은 무엇입니까?

객관성을 위해 답변에 대한 몇 가지 기준이 있습니다.

  • 가능하다면 해당 기능의 이면에 있는 설계상의 이유, 즉 의도한 목적을 제시해 주십시오.
  • 현재 코드가 사용되고 있는 오용에 대해 강조 표시해 주세요.
  • 그 오용이 왜 문제를 일으킬 수 있는지 설명해 주세요.나는 그것이 명백해야 한다는 것을 알지만 그것은 부드러운 대답을 방해한다.

피해주세요:

  • 함수의 명명 규칙에 대한 토론(분명히 혼동을 일으키는 것은 제외).
  • "나는 y보다 x가 더 좋다" - 선호도는 괜찮아, 우리 모두 가지고 있지만 나는 실제 예상치 못한 부작용과 그것들을 어떻게 예방할지에 관심이 있어.

이것은 주관적이고 확실한 답이 없기 때문에 나는 즉시 커뮤니티 위키에 관심을 기울일 것이다.

저도 C99에 따라 일하고 있습니다.

보안 문제/코드 결함/비효율을 야기/유발할 수 있는 부적절하게 사용되는 C 표준 라이브러리 기능은 무엇입니까?

난 당연한 걸 택할 거야.

char *gets(char *s);

그것을 적절히 사용하는 것은 불가능할 정도로 특수성이 높다.

공통의 함정strtok()이 함수는 구문 분석된 문자열이 변경되지 않은 상태로 유지된다고 가정하는 것입니다.이 문자열은 실제로 구분문자를'\0'.

또한.strtok()는 문자열 전체가 토큰화될 때까지 후속 콜을 발신함으로써 사용됩니다.일부 라이브러리 구현은 저장strtok()글로벌 변수에서의 내부 상태.이 때문에, 다음과 같은 경우, 불쾌한 놀라움이 생길 가능성이 있습니다.strtok()여러 스레드에서 동시에 호출됩니다.

CERT C Secure Coding Standard에는 문의하신 함정의 대부분이 기재되어 있습니다.

거의 모든 경우에,atoi()사용해서는 안 됩니다(이것은 에도 적용됩니다).atof(),atol()그리고.atoll()).

이는 이러한 함수가 범위를 벗어난 오류를 전혀 감지하지 못하기 때문입니다. 표준에서는 단순히 "결과 값을 나타낼없는 경우 동작이 정의되지 않습니다."라고만 말합니다.따라서 이들 명령어를 안전하게 사용할 수 있는 유일한 방법은 입력이 확실히 범위 내에 있음을 증명할 수 있는 경우(예를 들어 길이가4 이하인 문자열을 전달한 경우 등)입니다.atoi(), 범위를 벗어날 수 없습니다).

대신 다음 중 하나를 사용합니다.strtol()기능 패밀리

질문을 더 넓은 의미에서 인터페이스로 확장해 보겠습니다.

errno:

엄밀히 말하면 변수, 매크로, 암묵적인 함수 호출이 무엇인지조차 명확하지 않다.현대 시스템에서는 스레드 고유의 오류 상태를 갖는 함수 호출로 변환되는 매크로가 대부분입니다.악랄하다.

  • 발신자가 값에 액세스 하는 오버헤드가 발생할 가능성이 있기 때문에, 「에러」를 체크합니다(이것은 예외적인 이벤트일 가능성이 있습니다).
  • 이것은, 발신자가 라이브러리 콜을 발신하기 전에 이 「카운트」를 클리어 하도록 강요하고 있기 때문입니다.
  • 이는 라이브러리의 글로벌 상태를 설정하여 단순한 오류 반환을 구현하기 때문입니다.

다음 표준은 다음과 같은 정의를 얻습니다.errno조금 더 직설적이지만, 이러한 추악한 점들은 여전히 남아 있다.

strtok_r이 있는 경우가 많습니다.

재할당의 경우 이전 포인터를 사용해야 하는 경우 다른 변수를 사용하는 것이 그리 어렵지 않습니다.프로그램이 할당 오류로 인해 실패할 경우 오래된 포인터를 청소할 필요가 없는 경우가 많습니다.

저라면...printf그리고.scanf이 리스트에서 꽤 위에 있어요.포맷 지정자를 정확하게 알아야 하기 때문에 이러한 함수는 사용하기 어렵고 틀리기 쉽습니다.데이터를 읽을 때 버퍼 오버런을 피하는 것도 매우 어렵습니다.게다가 「인쇄 형식의 문자열의 취약성」은, 의도적인 프로그래머가 클라이언트 지정 문자열을 인쇄의 첫 번째 인수로 지정했을 때에 수많은 시큐러티 홀을 초래해 왔지만, 스택이 파손되어 시큐러티가 오랫동안 침해되고 있는 것을 발견했을 가능성이 있습니다.

글로벌 상태를 조작하는 기능 중 하나:gmtime()또는localtime()이러한 기능은 여러 스레드에서 안전하게 사용할 수 없습니다.

편집: rand()보이는 것과 같은 범주에 속합니다.적어도 스레드의 안전성은 보장되지 않으며, Linux 시스템에서는 man 페이지가 리트런트 및 스레드 세이프가 아님을 경고합니다.

제 bétes noire 중 하나는 비반복성이며 처리 중인 스트링을 해킹하기 때문에 분리된 각 토큰 끝에 NUL을 삽입하는 것입니다.이것의 문제들은 매우 많다; 그것은 종종 고통스러울 정도로 어떤 문제에 대한 해결책으로 선전되지만, 종종 문제 그 자체이기도 하다.항상 그렇지는 않습니다. 안전하게 사용할 수 있습니다.하지만 당신이 조심한다면.대부분의 기능에서도 마찬가지입니다.단, 주목할 만한 예외는 다음과 같습니다.gets()안전하게 사용할 수 없습니다.

에 대한 답은 이미 하나 있다.realloc하지만 나는 다른 견해를 가지고 있다.많은 시간 동안, 나는 사람들이 글을 쓰는 글을 봐왔다.realloc그들이 의미할 때free;malloc- 즉, 새로운 데이터를 저장하기 전에 크기를 변경해야 하는 쓰레기로 가득 찬 버퍼가 있는 경우.물론 이는 잠재적으로 대규모 캐시 파괴로 이어집니다.memcpy덮어쓰려고 하는 쓰레기의 종류입니다.

증가하는 데이터와 함께 올바르게 사용되는 경우(최악의 경우를 피하기 위해)O(n^2)물체를 크기에 맞게 키우는 성능n즉, 공간이 부족할 때 버퍼를 선형으로 증가시키지 않고 기하급수적으로 증가시킵니다.realloc단순히 자신의 새로운 것을 하는 것에 대해 의심스러운 이익이 있다malloc,memcpy,그리고.free사이클을 하는 유일한 방법은realloc힙의 맨 위에 있는 단일 개체를 사용하여 작업하는 경우 내부에서 이 작업을 피할 수 없습니다.

새 개체를 0으로 채우려면calloc잊기 쉽다.realloc새 부품이 0으로 채워지지 않습니다.

그리고 마지막으로, 또 하나의 일반적인 용도는realloc필요한 것보다 더 많은 양을 할당한 후 할당된 개체의 크기를 필요한 크기로 줄이는 것입니다.그러나 이는 실제로 유해할 수 있습니다(추가 할당 및memcpy크기별로 청크를 엄격하게 분리하는 구현에서는 (기존의 작은 빈 청크를 사용하는 대신 큰 빈 청크의 일부를 분할하여 새로운 작은 개체를 저장함으로써) 플래그멘테이션을 증가시킬 수 있습니다.

이런 말을 할 수 있을지 모르겠지만realloc 나쁜 관행을 부추기지만, 제가 조심해야 할 기능이죠.

그럼 어떻게 할까요?malloc가족 전체요?제가 본 대부분의 크고 긴 수명 프로그램들은 마치 무료인 것처럼 어디에서나 동적 메모리 할당을 사용합니다.물론 실시간 개발자는 이것이 미신이라는 것을 알고 있습니다.다이나믹 할당을 부주의하게 사용하면 메모리 사용량이 대폭 증가하거나 주소 공간을 메모리 고갈로 단편화할 수 있습니다.

머신 레벨의 포인터가 없는 상위 레벨의 언어에서는, 프로그램의 라이프 타임중에 오브젝트와 디플러그 메모리를 이동할 수 있기 때문에, 이러한 오브젝트에 대한 참조를 최신 상태로 유지할 수 있는 한, 동적인 할당은 그다지 나쁘지 않습니다.비전통적인 C 실장에서도 이 작업을 수행할 수 있지만, 자세한 내용은 중요하지 않으며 모든 포인터 참조에서 상당한 비용이 발생하며 포인터가 상당히 커지기 때문에 실제 목적상 C에서는 불가능합니다.

My suspicion is that the correct solution is usually for long-lived programs to perform their small routine allocations as usual with malloc, but to keep large, long-lived data structures in a form where they can be reconstructed and replaced periodically to fight fragmentation, or as large malloc blocks containing a number of structures that make up a single large unit of data in the application (like a whole web page presentation in a browser), or on-disk with a fixed-size in-memory cache or memory-mapped files.

On a wholly different tack, I've never really understood the benefits of atan() when there is atan2(). The difference is that atan2() takes two arguments, and returns an angle anywhere in the range -π..+π. Further, it avoids divide by zero errors and loss of precision errors (dividing a very small number by a very large number, or vice versa). By contrast, the atan() function only returns a value in the range -π/2..+π/2, and you have to do the division beforehand (I don't recall a scenario where atan() could be used without there being a division, short of simply generating a table of arctangents). Providing 1.0 as the divisor for atan2() when given a simple value is not pushing the limits.

Another answer, since these are not really related, rand:

  • it is of unspecified random quality
  • it is not re-entrant

Some of this functions are modifying some global state. (In windows) this state is shared per single thread - you can get unexpected result. For example, the first call of rand in every thread will give the same result, and it requires some care to make it pseudorandom, but deterministic (for debug purposes).

basename() and dirname() aren't threadsafe.

ReferenceURL : https://stackoverflow.com/questions/4588581/which-functions-in-the-c-standard-library-commonly-encourage-bad-practice

반응형