Непонятное поведение strerror_r

Модератор: Модераторы разделов

_Yuriy_
Сообщения: 344
ОС: OpenSUSE 11 x86_64

Непонятное поведение strerror_r

Сообщение _Yuriy_ »

openSUSE 10.3
gcc v=4.2.1

Есть программа:

#define _REENTRANT
#include <string.h>
#include <stdio.h>

int main()
{
char s[1024];
strerror_r(1, s, 1024);
printf("\ns = \"%s\" len = %d\n\n", s, strlen(s));
return 0;
}

Сохраняем ее как a.c и a.cpp

yura@suse:~/Новая папка> gcc a.c
yura@suse:~/Новая папка> ./a.out

s = "Operation not permitted" len = 23

yura@suse:~/Новая папка> g++ a.cpp
yura@suse:~/Новая папка> ./a.out

s = "H��%S������" len = 13

В чем проблема?
Спасибо сказали:
Аватара пользователя
Attila
Сообщения: 125
Статус: Тролль-Лѣсовичокъ
ОС: Свободная aka ArchLinux

Re: Непонятное поведение strerror_r

Сообщение Attila »

Дело в том что, существуют разные strerror_r: GNU и XSI. В случае с языком С используется XSI-совместимая версия:
The XSI-compliant strerror_r() is preferred for portable applications.
It returns the error string in the user-supplied buffer buf of length
buflen.

В случае с С++ используется
The GNU-specific strerror_r() returns a pointer to a string containing
the error message.


То есть, в случае с С++ такой вод код:

Код: Выделить всё

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

int main()
{
char s[1024];
char *S;
S = strerror_r(1, s, 1024);
printf("\nS = %s\n", S);
return 0;
}

даёт такой вот результат:

Код: Выделить всё

[zigfrid@attila test]$ g++ test.cc -o testcc
[zigfrid@attila test]$ ./testcc

S = Operation not permitted

см. man sterror; man feature_test_macros
Спасибо сказали:
_Yuriy_
Сообщения: 344
ОС: OpenSUSE 11 x86_64

Re: Непонятное поведение strerror_r

Сообщение _Yuriy_ »

The GNU-specific strerror_r() returns a pointer to a string containing
the error message. This may be either a pointer to a string that the
function stores in buf, or a pointer to some (immutable) static string
(in which case buf is unused). If the function stores a string in buf,
then at most buflen bytes are stored (the string may be truncated if
buflen is too small) and the string always includes a terminating null
byte.

Это важно, что функция возвращает статическую строку когда буфер не используется, иначе результат копируется в буфер и возвращается указатель на буфер. Сравните значения S и s. Они будут разными. Тот же результат и тоже значение S будет если использовать strerror_r в виде

S = strerror_r(1, 0, 1024);
S = strerror_r(1, 0, 0);

Тогда зачем нужна такая SAFE THREAD функция если существует точно такая же

S1 = strerror(1);

которая возвращает ту же статическую строку из той же таблицы. Правда РедХат ответил, что всё окей так и должно быть. Но например Троллтех об этом в упор не ведает.
Спасибо сказали:
Аватара пользователя
Attila
Сообщения: 125
Статус: Тролль-Лѣсовичокъ
ОС: Свободная aka ArchLinux

Re: Непонятное поведение strerror_r

Сообщение Attila »

Тогда зачем нужна такая SAFE THREAD функция если существует точно такая же

S1 = strerror(1);


Ну, сами посмотрите. Вот strerror (из файла gcc-4.2.2/libiberty/strerror.c):

Код: Выделить всё

char *
strerror (int errnoval)
{
  const char *msg;
  static char buf[32];

#ifndef HAVE_SYS_ERRLIST

  if (error_names == NULL)
    {
      init_error_tables ();
    }

#endif

  if ((errnoval < 0) || (errnoval >= sys_nerr))
    {
#ifdef EVMSERR
      if (errnoval == evmserr.value)
    msg = evmserr.msg;
      else
#endif
      /* Out of range, just return NULL */
      msg = NULL;
    }
  else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
    {
      /* In range, but no sys_errlist or no entry at this index. */
      sprintf (buf, "Error %d", errnoval);
      msg = buf;
    }
  else
    {
      /* In range, and a valid message.  Just return the message. */
      msg = (char *) sys_errlist[errnoval];
    }

  return (msg);
}

Я, конечно, не силён во многих потоках... Но, по-моему, возращать указатель на статический буфер не безопасно: ведь другой поток может изменить этот буфер и ничего не сказать. То есть, строка неожиданно и непредсказуемо изменяется. Именно поэтому и придуманы SAFE THREAD функции...
Правда РедХат ответил, что всё окей так и должно быть. Но например Троллтех об этом в упор не ведает.

Мну не поняв Вашей мысли. Разве РедХат да и Троллтех имеют какое-то отношение к компиляции и к функциям языков С/С++?..
Спасибо сказали:
_Yuriy_
Сообщения: 344
ОС: OpenSUSE 11 x86_64

Re: Непонятное поведение strerror_r

Сообщение _Yuriy_ »

Attila писал(а):
13.01.2008 15:12
Мну не поняв Вашей мысли. Разве РедХат да и Троллтех имеют какое-то отношение к компиляции и к функциям языков С/С++?..


Самое прямое. Первые занимаются glibc и принимают баги по glibc, а вторые пишут Qt исходя из спецификации работы функций и выглядит это так:

QString qt_error_string(int errorCode)
{
...........
QByteArray buf(1024, '\');
strerror_r(errorCode, buf.data(), buf.size());
ret = QString::fromLocal8Bit(buf.constData());
...........
}

Поэтому qt_error_string не возвращает никаких сообщений если используется glibc 2.6 и выше
Спасибо сказали: