Здравствуйте, adontz, Вы писали:
ДД>>Для быстрой и дешевой разработки ПО, некритичного к кривости рук программиста, существуют соответствующие технологии и языки. A>Кривизна рук тут ни при чём. Ошибки делают все. Я не очень понимаю, зачем надо гордится тем, что "язык на котором я программирую позволяет совершать более изощерённые ошибки" и тем более лелеять это как святыню.
Потому что это, может быть, и приводит к более "изощренным" (а если уж быть честным — глупым) шибкам, но позволяет в массе своей избежать ошибок, причина которых возникла полгода назад во время исполнения софта.
Здравствуйте, MaximE, Вы писали:
>> Раз они юзают malloc, free то пусть будут добры не попадать в условия когда >> портится heap (например повторное закрытие файла)
ME>Лучше пусть они маскируют ошибки в твоем коде, так?
Маскируют ? Если бы во время повторного закрытия валился аналог Debug Break, это было бы неплохо, а так валится хип. Увидел программист, что хип повалился, что ему дальше делать ?
Здравствуйте, pavel_turbin, Вы писали:
КВА>>А возмутило меня другое Анализ лога valgrind показал что библиотечные КВА>>функции fprintf, fclose вовсю юзают malloc, free
_>а вы думаете под Windows API функции не используют HeapAlloc? вы ошибаетесь. Однако, если память не выделена, CreateFile обломится.
Все правильно, только дескриптор закрывай сколько хочешь, худа от этого не будет. Тебе вернется код ошибки и все.
Tanker wrote: > Все правильно, только дескриптор закрывай сколько хочешь, худа от этого > не будет. Тебе вернется код ошибки и все.
Ошибаетесь.
Во-первых, дескриптор внутри себя ведет счетчик ссылок. Соответственно,
при лишнем закрытии может полететь другой код, который использует этот
дескриптор.
Во-вторых, количество номеров дескрипторов — конечно. И в интервале
между закрытиями дескриптора может быть создан еще один
дескриптор с совпадающим номером.
Здравствуйте, Cyberax, Вы писали:
C>Во-первых, дескриптор внутри себя ведет счетчик ссылок. Соответственно, при лишнем закрытии может полететь другой код, который использует этот дескриптор.
Это детали и особенности реализации конкретных дескрипторов.
C>Во-вторых, количество номеров дескрипторов — конечно.
+1
C>И в интервале между закрытиями дескриптора может быть создан еще один дескриптор с совпадающим номером.
Это никак не мешает отслеживать ошибку. Правда она обнаружится немного позже, но это всё таки лучше чем вылящееся приложение.
adontz wrote: > C>Во-первых, дескриптор внутри себя ведет счетчик ссылок. > Соответственно, при лишнем закрытии может полететь другой код, который > использует этот дескриптор. > Это детали и особенности реализации конкретных дескрипторов.
Ну как бы это не отменяет ошибок, которые могут быть получены из-за этого.
> C>И в интервале между закрытиями дескриптора может быть создан *еще > один* дескриптор с совпадающим номером. > Это никак не мешает отслеживать ошибку. Правда она обнаружится немного > позже, но это всё таки лучше чем вылящееся приложение.
Во время отладки такая ошибка элементарно обнаруживается по backtrace'у
из fclose.
adontz wrote:
> Здравствуйте, ДимДимыч, Вы писали: > > ДД>Может. Не спорю. Но нужно ли это? В некоторых случаях, таких как > отладка — нужно. Для этого есть glibc-debug, например, которая проверяет > валидность указателей, реализация собственных оберток и т.д. В остальных > случаях — не нужно, потому как: 1) неразумно используется память и > процессорное время; 2) это способствует распространению некачественного > кода и таких же программистов. > > Память не будет неразумно использоватся, потому что список и так уже есть. > Процессорное время да — но поиск в списке из нескольких десятков элементов > мелочи по сравнению со скоростью ввода-вывода. > > Дело в том что в релизе тоже есть ошибки, но там glibc-debug не > используют. И ИМХО лучше если библиотека вернёт тебе некоторый код ошибки, > который будет обработан, чем если приложение просто рухнет. Лучше не для > тебя (dump был бы весьма полезен), а для конечного пользователя. Заметь в > первом сообщении речь шла о программе, которую портировали. То есть > когда-то её написали и она работала себе и работала с этой ошибкой, но > потом её решили портировать и версия LIBC на новой платформе уже от старой > ошибки рушит программу. Так что рассуждать о том, что мол "не надо два > раза закрывать файл" это конечно хорошо, но к реальности не имеет > отношения. Бывает, что и закрывают. И я бы предпочёл, что бы такие вещи из > разряда error перешли в warning. На самом деле мои слова тоже на ветер. > LIBC никто не препишет, стандарт не изменят, а файлы будут по прежнему > закрывать по два раза.
C>Во-первых, дескриптор внутри себя ведет счетчик ссылок. Соответственно, C>при лишнем закрытии может полететь другой код, который использует этот C>дескриптор.
adontz wrote: > C>Во время отладки такая ошибка элементарно обнаруживается по > backtrace'у из fclose. > Блин, ну читайте всю ветку, я же уже раза 3 это объяснял. > *А что если ошибка проявляется только на клиентской машине?* Что, не > бывает так?
Пусть шлют coredump, по которому можно посмотреть stacktrace.
Здравствуйте, Pzz, Вы писали:
Pzz>pavel_turbin wrote: >> >> я обычно проверяю что венул close >> типа >> >> ret = CloseHanlde(h); >> assert(ret);
Pzz>А UNIX'овский close() Вы тоже будете проверять assert'ом?
почему бы и нет?
int close(int fildes);
RETURN VALUES
Upon successful completion, 0 is returned. Otherwise, -1 is
returned and errno is set to indicate the error.
ERRORS
ret = close(fd);
assert( ret == 0 );
ret = close(fd);
assert( ret == 0 ); // должен сработать
Здравствуйте, Pzz, Вы писали:
Pzz>close() может вернуть -1 по внешним причинам. Например, из-за того, что Pzz>не удалось отлить на диск отложенную запись.
Pzz>Разве тот факт, что на диске кончилось место, может считаться Pzz>уважительной причиной упасть по assert'у?
естественно, если вы обрабатываете специальным образом ошибку из close, например, повторяете вызов через несколько секунд, то assert не нужен. НО если вы просто игнорируете его код возврата:
int myfunction()
{
int fh = open(...);
if( fh < 0 )
return -1;
read(...);
close(fh); // часто можно видет такой кодreturn 0;
}
то хорошо бы и хотя бы про-assert-ить.
Еще один момент, я обычно сохраняю assert-ы в релизе. Они пишут в error-log, тогда можно было отследить ошибки и в release.
pavel_turbin wrote: > > Pzz>Разве тот факт, что на диске кончилось место, может считаться > Pzz>уважительной причиной упасть по assert'у? > > естественно, если вы обрабатываете специальным образом ошибку из close, > например, повторяете вызов через несколько секунд, то assert не нужен.
К сожалению, close(), это навсегда. Даже если Вы получили -1, дескриптор
уже закрыт.
> НО если вы просто игнорируете его код возврата: > > int myfunction() > { > int fh = open(...); > if( fh < 0 ) > return -1; > > read(...); > > close(fh); // часто можно видет такой код > return 0; > }
Можно еще сознательно игнорировать результат close(). Например, если я
закрываю временный файл, который уже отслужил свое, зачем мне знать код
возврата? Сделать-то с ним ничего осмысленного я все равно не смогу...
Кстати, и в приведенном Вами примере, ну какая Вам разница, чем кончился
close, если Вы прочли то, что собирались? Если он кончился чем-то не
тем, это (в данном случае, не вообще!) уже проблема системы, а не Ваша.
> Еще один момент, я обычно сохраняю assert-ы в релизе. Они пишут в > error-log, тогда можно было отследить ошибки и в release.
Я тоже сохраняю. Но еще раз, assert это для _внутренних_ ошибок в
программе. Внешние ошибки 1) должны обрабатываться, кроме тех случаев,
когда факт возможной ошибки _сознательно_ игнорируется 2) должны
обрабатываться по-другому, чем внутренние.
Здравствуйте, Pzz, Вы писали:
Pzz>pavel_turbin wrote:
Pzz>Можно еще сознательно игнорировать результат close(). Например, если я Pzz>закрываю временный файл, который уже отслужил свое, зачем мне знать код Pzz>возврата? Сделать-то с ним ничего осмысленного я все равно не смогу...
тут в другом дело. Задача избежать 2-го закрытия того же handle-a. handle может принять значение какого-нибудь уже существующего handle-a, т.к после close его значение может быть вновь использовано.
в multy-thread приложении (и не только!) 2-ое закрытие иногда может быть успешным, т.к. старое значение fh может случайно совпасть с только что открытым новым файлом в параллельном потоке. assert от результата close помогает найти такие ошибки.
pavel_turbin wrote: > > Pzz>Можно еще сознательно игнорировать результат close(). Например, если я > Pzz>закрываю временный файл, который уже отслужил свое, зачем мне знать код > Pzz>возврата? Сделать-то с ним ничего осмысленного я все равно не смогу... > > тут в другом дело. Задача избежать 2-го закрытия того же handle-a. > handle может принять значение какого-нибудь уже существующего handle-a, > т.к после close его значение может быть вновь использовано.
Ну, на все случаи жизни соломки не подстелишь. Причем Вы, ради борьбы с
воображаемой проблемой создали вполне реальную проблему: Ваше приложение
может упасть по внешним причинам.
Кстати, обратите внимание, что:
1) close не того файла все равно не пройдет незамеченным — попытка
поработать с закрытым файлом вернет ошибку
2) в Вашем случае assert сработает слишком поздно, и из него трудно
будет понять, что произошло
3) как только вместо read'а будет написан write, использование
assert'а сразу станет некорректным, а это совершенно неочевидно. Первый
же индус, который добавит в фаш код запись в файл, не обратит никакого
внимания на assert.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, Cyberax, Вы писали:
C>>Пусть шлют coredump, по которому можно посмотреть stacktrace.
A>Я рыдаю. Ты хоть раз работал с пользователями? ИМХО за такие выходки PM настучит по голове, а support team добавит.
а как иначе дебужить? Просить логи или эксперементальную версию запускать?