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
В чем проблема?
Непонятное поведение strerror_r
Модератор: Модераторы разделов
-
Attila
- Сообщения: 125
- Статус: Тролль-Лѣсовичокъ
- ОС: Свободная aka ArchLinux
Re: Непонятное поведение strerror_r
Дело в том что, существуют разные strerror_r: GNU и XSI. В случае с языком С используется XSI-совместимая версия:
В случае с С++ используется
То есть, в случае с С++ такой вод код:
даёт такой вот результат:
см. man sterror; man feature_test_macros
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
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);
которая возвращает ту же статическую строку из той же таблицы. Правда РедХат ответил, что всё окей так и должно быть. Но например Троллтех об этом в упор не ведает.
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
Тогда зачем нужна такая 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
Самое прямое. Первые занимаются 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 и выше