source

strerror_r은 어떤 사이즈를 허용해야 합니까?

manycodes 2023. 11. 2. 21:54
반응형

strerror_r은 어떤 사이즈를 허용해야 합니까?

OpenGroup POSIX.1-2001은 Linux Standard Base Core Specification 3.1과 마찬가지로 strerror_r을 정의합니다.그러나 오류 메시지에 대해 합리적으로 예상할 수 있는 최대 크기에 대한 참조를 찾을 수 없습니다.코드에 넣을 수 있는 정의를 기대했지만 찾을 수 있는 정의가 없습니다.

코드는 스레드 세이프여야 합니다.그렇기 때문에 strererror_r이 사용되고 strererror는 사용되지 않습니다.

제가 사용할 수 있는 기호를 아는 사람이 있습니까?나만의 것을 만들어야 할까요?


int result = gethostname(p_buffy, size_buffy);
int errsv = errno;
if (result < 0)
{
    char buf[256];
    char const * str = strerror_r(errsv, buf, 256);
    syslog(LOG_ERR,
             "gethostname failed; errno=%d(%s), buf='%s'",
             errsv,
             str,
             p_buffy);
     return errsv;
}

문서에서:

오픈 그룹 베이스 사양 6호:

오류

strererror_r() 함수는 다음과 같은 경우 실패할 수 있습니다.

  • [ERANGE] strerrbuff 및 buflen을 통해 생성된 메시지 문자열을 포함할 수 있는 저장소가 부족합니다.

출처:

glibc-2.7/glibc-2.7/ 문자열/ strerror.c:41:

    char *
    strerror (errnum)
         int errnum;
    {
        ...
        buf = malloc (1024);

정적 한계치가 충분히 큰 것은 모든 상황에 충분히 적합할 것입니다.전체 오류 메시지를 꼭 받아야 한다면 gnu 버전의 strererror_r을 사용하거나 표준 버전을 사용하여 필요한 것을 얻을 때까지 연속적으로 더 큰 버퍼로 폴링할 수 있습니다.예를 들어, 아래의 코드와 같은 것을 사용할 수 있습니다.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Call strerror_r and get the full error message. Allocate memory for the
 * entire string with malloc. Return string. Caller must free string.
 * If malloc fails, return NULL.
 */
char *all_strerror(int n)
{
    char *s;
    size_t size;

    size = 1024;
    s = malloc(size);
    if (s == NULL)
        return NULL;

    while (strerror_r(n, s, size) == -1 && errno == ERANGE) {
        size *= 2;
        s = realloc(s, size);
        if (s == NULL)
            return NULL;
    }

    return s;
}

int main(int argc, char **argv)
{
    for (int i = 1; i < argc; ++i) {
        int n = atoi(argv[i]);
        char *s = all_strerror(n);
        printf("[%d]: %s\n", n, s);
        free(s);
    }

    return 0;
}

저는 그것에 대해 걱정하지 않을 것입니다. 버퍼 사이즈 256은 충분하고도 1024는 오버킬입니다.당신은 사용할 수 있습니다.strerror()대신에strerror_r(), 그리고 선택적으로strdup()오류 문자열을 저장해야 할 경우의 결과입니다.하지만 이건 안전하지 않습니다.꼭 사용해야 할 경우strerror_r()대신에strerror()나사산의 안전을 위해서, 256의 사이즈를 사용하세요. 인glibc-2.7, 가장 긴 오류 메시지 문자열은 50자("잘못되거나 불완전한 멀티바이트 또는 와이드 문자")입니다.향후 오류 메시지가 크게 길어지지는 않을 것으로 예상됩니다(최악의 경우에는 몇 바이트가 더 길어집니다).

이 프로그램(온라인(여기서는 C++로 실행):

#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(){
        const int limit = 5;
        int unknowns = 0;
        int maxlen = 0;
        int i=0; char* s = strerror(i);
        while(1){
            if (maxlen<strlen(s)) maxlen = strlen(s);
            if (/*BEGINS WITH "Unknown "*/ 0==strncmp("Unknown ", s , sizeof("Unknown ")-1) )
                unknowns++;
            printf("%.3d\t%s\n", i, s);
            i++; s=strerror(i);
            if ( limit == unknowns ) break;
        }
        printf("Max: %d\n", maxlen);
        return 0;
}

는 시스템의 모든 오류를 나열하고 인쇄하며 최대 길이를 추적합니다.보기에 길이는 49자를 넘지 않습니다(순수).strlen의 결승전이 없는\0) 따라서 어느 정도 여유가 있다면 64–100 정도면 충분합니다.

구조물 반송만으로 버퍼 사이즈 협상 전체를 피할 수 없는 것인지, 구조물 반송을 하지 않는 근본적인 이유가 있는지 궁금했습니다.그래서 벤치마킹을 했습니다.

#define _POSIX_C_SOURCE 200112L //or else the GNU version of strerror_r gets used
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

typedef struct { char data[64]; } error_str_t;
error_str_t strerror_reent(int errn) __attribute__((const));
error_str_t strerror_reent(int errn){
    error_str_t ret;
    strerror_r(errn, ret.data, sizeof(ret));
    return ret;
}


int main(int argc, char** argv){
    int reps = atoi(argv[1]);
    char buf[64];
    volatile int errn = 1;
    for(int i=0; i<reps; i++){
#ifdef VAL
        error_str_t err = strerror_reent(errn);
#else
        strerror_r(errn, buf, 64);
#endif
    }
    return 0;
}

그리고 -O2에서 두 가지 성능 차이는 최소입니다.

gcc -O2 : The VAL version is slower by about 5%
g++ -O2 -x c++ : The VAL version is faster by about 1% than the standard version compiled as C++ and by about 4% faster than the standard version compiled as C (surprisingly, even the slower C++ version beats the faster C version by about 3%).

어쨌든, 제 생각에 그 일이 정말 이상한 것 같아요.strerror스레드가 안전하지 않을 수도 있습니다.반환된 문자열은 문자열 리터럴에 대한 포인터여야 합니다. (깨달아주세요. 하지만 런타임에 합성해야 하는 경우는 생각나지 않습니다.)또한 문자열 리터럴은 정의상 읽기 전용이며 읽기 전용 데이터에 대한 액세스는 항상 스레드 안전합니다.

아직 아무도 확실한 답을 주지 않아서 이 부분을 더 알아봤는데 그 일에 더 좋은 기능이 있습니다.perror(3), 아마도 이 오류를 어딘가에 표시하고 싶을 것이기 때문에, 요구 사항에 따라 사용하지 않는 한 이 오류를 사용하는 것이는 것입니다.

완전한 답은 아니지만 사용하는 이유는 모든 로케일에 적합한 적절한 크기의 버퍼를 사용하기 때문입니다.내부적으로 사용합니다.strerror_r(3), 이 두 기능은 POSIX 표준에 부합하고 널리 사용할 수 있으므로 제 눈에는 이 문제에 대한 권위 있는 진리의 원천입니다.

glibc 구현에서 발췌:

static void
perror_internal (FILE *fp, const char *s, int errnum)
{
  char buf[1024];
  const char *colon;
  const char *errstring;
  if (s == NULL || *s == '\0')
    s = colon = "";
  else
    colon = ": ";
  errstring = __strerror_r (errnum, buf, sizeof buf);
  (void) __fxprintf (fp, "%s%s%s\n", s, colon, errstring);
}

이로부터, 나는 지금 이 순간, 그리고 그러한 것들의 안정성을 고려할 때, 가까운 미래에, 당신은 결코 실수하지 않을 것이라고 추론할 수 있습니다.1024촤스

언급URL : https://stackoverflow.com/questions/423248/what-size-should-i-allow-for-strerror-r

반응형