Почему я не могу использовать strerror?

Если вы храните свои сессии в БД, то

rake db:sessions:clear
30
задан JamieH 22 May 2009 в 23:18
поделиться

6 ответов

strerror устарел, поскольку он не является потокобезопасным. strerror работает с внутренним статическим буфером, который может быть перезаписан другими параллельными потоками. Вы должны использовать безопасный вариант под названием strerror_s .

Безопасный вариант требует, чтобы размер буфера был передан функции, чтобы проверить, достаточно ли большой буфер перед записью в него, что помогает избежать буфера переполнения, которые могут позволить выполнить вредоносный код.

24
ответ дан 27 November 2019 в 23:36
поделиться

Получив несколько хороших ответов и теперь понимая, что некоторые реализации могут быть достаточно сумасшедшими, чтобы на самом деле писать в общий разделяемый буфер - небезопасно для повторного входа в одном потоке, не говоря уже о между потоками! - мой вопрос перестает быть «Почему я не могу его использовать и какие есть альтернативы?» на «Есть ли достойные, сжатые альтернативы в C и / или C ++?»

Posix указывает strerror_r () , а в Windows вы можете использовать strerror_s () , что является немного отличается, но преследует ту же цель. Я делаю это:

#define BAS_PERROR(msg, err_code)\
  bas_perror(msg, err_code, __FILE__, __LINE__)

void bas_perror (const char* msg, int err_code, const char* filename,
                 unsigned long line_number);


void
bas_perror (const char* usr_msg, int err_code, const char* filename,
            unsigned long line_number)
{
  char sys_msg[64];

#ifdef _WIN32
  if ( strerror_s(sys_msg, sizeof sys_msg, err_code) != 0 )
  {
    strncpy(sys_msg, "Unknown error", taille);
    sys_msg[sizeof sys_msg - 1] = '\0';
  }
#else
  if ( strerror_r(err_code, sys_msg, sizeof sys_msg) != 0 )
  {
    strncpy(sys_msg, "Unknown error", sizeof sys_msg);
    sys_msg[sizeof sys_msg - 1] = '\0';
  }
#endif

  fprintf(stderr, "%s: %s (debug information: file %s, at line %lu)\n",
          usr_msg, sys_msg, filename, line_number);
}

Я написал эту функцию, потому что функции потоков Posix не t изменить errno , вместо этого они возвращают код ошибки. Таким образом, эта функция в основном аналогична perror () , за исключением того, что она позволяет указать код ошибки, отличный от errno , а также отображает некоторую отладочную информацию. Вы можете адаптировать его под свои нужды.

16
ответ дан 27 November 2019 в 23:36
поделиться

strerror сам по себе небезопасен. Раньше, до создания потоков, это не было проблемой. С потоками два или более потока могут вызвать strerror , оставляя возвращенный буфер в неопределенном состоянии. Для однопоточных программ не повредит использовать strerror , если только они не играют в какие-то странные игры в libc, такие как общая память для всех приложений в DLL.

Для решения этой проблемы есть новый интерфейс. та же функциональность:

int strerror_r(int errnum, char *buf, size_t buflen);

Обратите внимание, что вызывающая сторона предоставляет буферное пространство и размер буфера. Это решает проблему. Вы можете использовать его даже для однопоточных приложений. Это нисколько не повредит, и вы можете привыкнуть делать это более безопасным способом.

ПРИМЕЧАНИЕ: приведенный выше прототип является спецификацией XSI. Он может варьироваться в зависимости от платформы, параметров компилятора или символов #define . GNU, например, делает эту или их собственную версию доступной в зависимости от #define

19
ответ дан 27 November 2019 в 23:36
поделиться

Нельзя полагаться на строку, возвращаемую strerror () , потому что она может измениться при следующем вызове функции. В этом случае возвращенные ранее значения могут стать устаревшими. Особенно в многопоточных средах вы не можете гарантировать, что строка действительна при доступе к ней.

Представьте себе это:

Thread #1:
char * error = strerror(1);
                                    Thread #2
                                    char * error = strerror(2);
printf(error);

В зависимости от реализации strerror () , этот код выводит код ошибки для кода ошибки 2, а не для кода ошибки 1.

5
ответ дан 27 November 2019 в 23:36
поделиться

Для сжатой оболочки вы можете использовать STLSoft stlsoft :: error_desc , например:

std::string errstr = stlsoft::error_desc(errno);

Глядя на код, он Кажется, что он реализован в терминах strerror () , что означает, что он будет безопасным для повторного входа в поток (то есть при многократном использовании в данном операторе), но он не решает проблему многопоточности.

Кажется, у них довольно быстрые циклы выпуска дефектов, так что вы можете попробовать запросить мод?

1
ответ дан 27 November 2019 в 23:36
поделиться

Хотя я не знаю причин Microsoft, я отмечаю, что strerror возвращает неконстантный символ *, что означает, что существует риск того, что какой-то веселый шутник вызвал strerror до того, как вы это сделали и изменили сообщение.

0
ответ дан 27 November 2019 в 23:36
поделиться