LINUX.ORG.RU

Не знаю по поводу стандарта, но логика и здравый смысл подсказывает что тут должно быть UB. Ведь если дескриптор представляет из себя (FILE *), то где-то внутри fclose запросто может быть (а может и не быть) free. А второй вызов free на невалидном указателе...

P.S. IMHO

Deleted
()

стандарт (7.19.5.1) это не регламентирует, видимо implementation defined. В Linux - 

The behaviour of fclose() is undefined if the stream parameter is an illegal pointer, or is a descriptor already
passed to a previous invocation of fclose().

alex_custov ★★★★★
()
Ответ на: комментарий от Deleted

> Ведь если дескриптор представляет из себя (FILE *), то где-то внутри fclose запросто может быть (а может и не быть) free.

Если есть free, то будет double free со всеми вытекающими. А если нет free, то вторым fclose можно грохнуть какой-нибудь файл, открытый после первого fclose. От текущей реализации libc зависит, насколько неожиданным и фееричным будет падение приложения :D

const86 ★★★★★
()
Ответ на: комментарий от iBliss

> А как же контрольный выстрел ?

void fdshred(FILE *f)
{
    fclose(f);
    fclose(f); // на случай, если в первый раз не получилось
    fclose(f + 1); fclose(f - 1); // на случай, если дескриптор намусорил вокруг
    free(f); // а вдруг libc забыла очистить память?
    free(f); // на случай, если у libc склероз
    free(f); // на случай, если у libc ещё и старческий маразм
    memset(f, 0, sizeof(*f)); // чтобы врагам не достались даже остатки нашего дескриптора!
    memset(fdshred, 0, 1024); // а исходник распечатать и съесть!
}

Deleted
()
Ответ на: комментарий от Deleted

сермяжная логика подсказывает:
1. перед тем, как закрыть дверь, проверь, а не закрыта ли она уже.
2. а можешь ли ты её закрыть.
3. если уж решил закрыть, закрывай так, чтобы не рухнуло всё здание.

не понятно, как тогда работают такие комбинации

fclose -> reopen 
или
fclose -> closeall

ну, и самое непонятное :
в gccях - всё нормально (могу узнать и в остальных : icc, solaris)
... в VC7 - нормально , а вот уже VC8, VC9 - crash

сдаётся мне, что опять мелко-мягкие что-то там отчудили.

Главное, читаю вчера FAQ ffmpeg
http://www.ffmpeg.org/faq.html#SEC37

"Microsoft Visual C++ is not compliant to the C99 standard"

и тут, одновременно, обнаруживается такой "side effect"

Valeriy_Onuchin ★★
() автор топика
Ответ на: комментарий от Valeriy_Onuchin

> fclose -> reopen

Поидее тут такое же UB. freopen сама должна закрывать поток и ассоциировать существующую внутреннюю структуру *(FILE *) с новым потоком (т.е. сам указатель (FILE *) при этом не меняется, в этом и есть весь смысл freopen). А после fclose файловый дескриптор становится невалидным, а упадёт ли программа - это зависит от реализации libc. Если как я говорил память под структуру выделяется динамически, то упадёт, если статически - не упадёт и возможно даже будет работать нормально (т.е. может быть проверка что дескриптор уже закрыт).

Хотя в man freopen написано:

The freopen() function opens the file whose name is the string pointed to by path and associates the stream pointed to by stream with it. The original
stream ***(if it exists)*** is closed. The mode argument is used just as in the fopen() function. The primary use of the freopen() function is to change the
file associated with a standard text stream (stderr, stdin, or stdout).

Не совсем понятно что подразумевается под "if it exists". Как оно например узнает что я передал ей уже закрытый дескриптор, а не указатель 0xdeadbeaf, который указывает на случайный участок памяти с мусором?

> fclose -> closeall


libc держит что-то типа списка открытых дескрипторов и закрывает всё что не было закрыто явно. Вроде никаких противоречий...

> сдаётся мне, что опять мелко-мягкие что-то там отчудили.


Они могут =).

> "Microsoft Visual C++ is not compliant to the C99 standard"


В принципе это логично, так как у M$ нет компилятора для Си как такового, только C++. После С89 Си и C++ основательно разделились и современный C++ уже не включает в себя новшества C99. AFAIK Микрософт решил просто забить на Си без плюсов.

Deleted
()
Ответ на: комментарий от Deleted

> Они могут =).

мда, оказывается с VC2005 началась борьба за безопасность в CRT:
http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx
http://msdn.microsoft.com/ru-ru/magazine/cc163794(en-us).aspx
http://msdn.microsoft.com/en-us/library/ms235384.aspx
http://msdn.microsoft.com/en-us/library/wd3wzwts.aspx

как, я ейтот момент прозевал

Valeriy_Onuchin ★★
() автор топика
Ответ на: комментарий от Valeriy_Onuchin

> мда, оказывается с VC2005 началась борьба за безопасность в CRT:

Оно же вроде не по умолчанию. Просто компилятор начинает орать что используемые функции deprecated, не безопасны и вообще в будущем будут удалены и надо использовать православные с суффиксом _s.

Кстати это уже несколько лет как. Там ещё STL со включенным "безопасным режимом" по умолчанию и из-за большого количества лишних проверок очень сильно тормозит по сравнению с тем же STLport'ом. Это лечится каким-то злым define'ом (точно уже не помню).

Deleted
()
Ответ на: комментарий от Deleted

>void fdshred(FILE *f) >{ > fclose(f); > fclose(f); // на случай, если в первый раз не получилось > fclose(f + 1); fclose(f - 1); // на случай, если дескриптор намусорил вокруг > free(f); // а вдруг libc забыла очистить память? > free(f); // на случай, если у libc склероз > free(f); // на случай, если у libc ещё и старческий маразм > memset(f, 0, sizeof(*f)); // чтобы врагам не достались даже остатки нашего дескриптора! > memset(fdshred, 0, 1024); // а исходник распечатать и съесть! >}

засуну в подпись!!!

erfea ★★★★★
()
Ответ на: комментарий от erfea

прикола ради, сравнил исходники (хоть здесь/CRT у них Open Source)
fclose, close (VC7 vs VC8).
Везде вроде есть проверка на "закрыт ли файл?", т.е. всёб должно работать адекватно.


Valeriy_Onuchin ★★
() автор топика
Ответ на: комментарий от Deleted

Еще раз перечитал описание

Вот мио 5 копеек.

freopen может принимать только валидный указатель на FILE*

Не какой проверки не происходит. Происходит просто переассоциация дискрипторов.

То есть можно передать только валидную структуру FILE*. Как я понимаю, получить такую валидную структору можно например при fclose, если он вернул ошибку, но фаил уже закрыл, но структуру удалил.

Так же я думаю это будет работать с stdin, stdout, stderr, потому что живут не на куче

Может быть еще есть способы это сделать.

-----------------------------------

В общем вывод: libc не обязан обеспечить работу связки fclose -> freopen

namezys ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.