Comments 63
Картинка зачетная!
+5
Ваш проект плох тем, что делает лучше виндовые программы, а не линуксовые =)
Я шучу и желаю проекту успеха и коммерческой успешности. Приятно читать ваши статьи, даже когда уже умер как программист давным давно.
Я шучу и желаю проекту успеха и коммерческой успешности. Приятно читать ваши статьи, даже когда уже умер как программист давным давно.
+28
Спасибо.
0
Спасибо. Не знал про такое. Но по всей видимости какая-то фитюлька. Объем исходного кода проекта 340 килобайт. Для сравнения, объем исходного кода консольной версии PVS-Studio — около 6 мегабайт.
+1
Там в зависимостях google test на 4.5 мб, возможно поэтому
+1
Это больше style-checker, а не статический анализатор кода. Просто посмотрите на заданные правила и сообщения об «ошибках»:
lintWarning(*it, "Protected inheritance is sometimes not a good "
"idea. Read "
"http://stackoverflow.com/questions/6484306/effective-c-discouraging-protected-inheritance "
"for more information.\n");
lintError(*it, "Open Source Software may not include files from "
"other fbcode projects (except folly). "
"If this is not an fbcode include, please use "
"'#include <...>' instead of '#include \"...\"'. "
"You may suppress this warning by including the "
"comment 'nolint' after the #include \"...\".\n");
+1
Вообще, если без шуток порассуждать о данном моменте то получается, что PVS действительно плох отсутствием кроссплатформенности. Однако с учётом размера команды проект развивается очень даже замечательно. А дальше тоже не понятно что делать, ведь если начать сильно увеличивать штат, то можно легко потонуть в бюрократии, и испортить проект. В общем ребята правда молодцы.
Мне в PVS нравится то, что у него довольно мало воды в предупреждениях, и это очень ценно поскольку многие, даже опытные разработчики, обязательно следуют рекомендациям анализатора, не пытаясь понять зачем они это делают, и не понимая всех последствий. Для примера могу привести свой опыт, когда в одном, довольно большом и старом проекте, человек, позиционирующий себя мантейнером и руководителем проекта засрал все конструкторы инициализациями цифровых членов в 0 или какими то другими «безопасными» значениями, только потому что так ему рекомендовал CppCheck, в результате данной «подушки безопасности» провалилась производительность во многих местах поскольку была поломана отложенная инициализация. которую вносили в проект годами. Помимо этого данный руководитель не понимает и не хочет понимать как работает move-semantics и старательно выпиливает её из классов, которые уже были переписана на C++11. Вот такой маразм, уж простите за «крик души», просто наболело :)
Мне в PVS нравится то, что у него довольно мало воды в предупреждениях, и это очень ценно поскольку многие, даже опытные разработчики, обязательно следуют рекомендациям анализатора, не пытаясь понять зачем они это делают, и не понимая всех последствий. Для примера могу привести свой опыт, когда в одном, довольно большом и старом проекте, человек, позиционирующий себя мантейнером и руководителем проекта засрал все конструкторы инициализациями цифровых членов в 0 или какими то другими «безопасными» значениями, только потому что так ему рекомендовал CppCheck, в результате данной «подушки безопасности» провалилась производительность во многих местах поскольку была поломана отложенная инициализация. которую вносили в проект годами. Помимо этого данный руководитель не понимает и не хочет понимать как работает move-semantics и старательно выпиливает её из классов, которые уже были переписана на C++11. Вот такой маразм, уж простите за «крик души», просто наболело :)
+1
Спасибо за комментарий, хочу обратить внимание (прежде всего других людей), что «мало воды в предупреждениях» — это результат очень долгой и сложной доводки анализатора под конкретный компилятор (VisualC++) и конкретную платформу. Как только анализатор запускается без такой доводки, скажем в гипотетическом линуксе — из него вода льется как из дырявого ведра.
+3
* Доп про конструкторы: теперь вообще не возможно узнать отработал ли какой либо функционал или нет, поскольку раньше программа сразу же падала на ошибках в новом коде, а теперь из-за 0 (nullptr) в конструкторах на указателях, и проверок на nullptr везде где только можно программа не падает, но и не пойми что делает. Этот момент заметен по жалобам пользователей у которых постоянно что то начинает глючить, и появляется всё больше и больше гейзенбагов в новых версиях. Вот такая печаль, а проект был хорошим :(
0
Свершилось: PVS-Studio для Linux.
+1
С другой стороны, на glibc можно неплохо тренироваться по устранению ложноположительных срабатываний из гвинпинного мира.
+7
Я бы лучше попробовал поковырять gcc, про который пишут, что кроме пары бородатых программистов никто не понимает как он работает. Ну и заодно что-нибудь из кодовой базы X11, вот там точно код тот еще. Ну и напоследок наверное что-нибудь типа Mesa явно не лишним было бы проверить.
+17
Мы ещё год назад собирали проверяли gcc. Подтверждаю, что разобраться в проекте очень сложно. Там сплошные макросы, которые раскрываются в макросы, которые раскрываются в макросы, которые раскрываются в макросы…
Я сдался и бросил анализ проекта, хотя очень хотелось найти ошибки.
Я сдался и бросил анализ проекта, хотя очень хотелось найти ошибки.
+12
If E1 has a signed type and a negative value, the resulting value is implementation-defined.
implementation-defined это не совсем то же самое, что и undefined. В данном случае «все понимают» (серьезно) что на 2's complement machine будет «правильная» реализация, и это так во всех разумных компиляторах.
Еще есть такой момент, что glibc — это стандартная библиотека языка C, ее интерфейсы описаны в стандарте C. По сути, она частично реализует язык C. Соответственно, она написана не на C, а на чем-то слегка его напоминающем, с кучей нестандартных расширений, платформо-зависимой магии и т.д.
implementation-defined это не совсем то же самое, что и undefined. В данном случае «все понимают» (серьезно) что на 2's complement machine будет «правильная» реализация, и это так во всех разумных компиляторах.
Еще есть такой момент, что glibc — это стандартная библиотека языка C, ее интерфейсы описаны в стандарте C. По сути, она частично реализует язык C. Соответственно, она написана не на C, а на чем-то слегка его напоминающем, с кучей нестандартных расширений, платформо-зависимой магии и т.д.
+17
Вообще между undefined behavior и implementation-defined behavior лежит пропасть. Если вы используете implementation-defined behavior — то вы, всё-таки всё ещё в рамках C и во многих случаях всё ещё в безопасности (скажем если вы использете какой-нибудь int8_t, то вы сразу попадаете в рамки 2's complement machine и можете с лёгостью делать подобные сдвиги).
А вот разъменование указателя, который позже проверяется на NULL — это не просто ошибка, это катастрофа. Дело в том, что компилятор может после этого проверку на NULL просто выкинуть. Именно потому что undefined behavior с точки зрения компилятора «не бывает» и уж если ты указатель разименовал, то ты тем самым «пообещал», что соответствующий указатель — не NULL.
А если после этого он ещё и немного код «пооптимизирует», то всё может кончится чем-нибудь ешё похлеще. Например переменная, которая инициализировалась через этот указатель может оказаться и вообще ненужной и будет выкинута. Получится просто программа, которая игнорирует тот факт, что какой-то указатель может быть равен NULLу.
А вот разъменование указателя, который позже проверяется на NULL — это не просто ошибка, это катастрофа. Дело в том, что компилятор может после этого проверку на NULL просто выкинуть. Именно потому что undefined behavior с точки зрения компилятора «не бывает» и уж если ты указатель разименовал, то ты тем самым «пообещал», что соответствующий указатель — не NULL.
А если после этого он ещё и немного код «пооптимизирует», то всё может кончится чем-нибудь ешё похлеще. Например переменная, которая инициализировалась через этот указатель может оказаться и вообще ненужной и будет выкинута. Получится просто программа, которая игнорирует тот факт, что какой-то указатель может быть равен NULLу.
+5
XDR *xdrs = &clp->xdr_stream;
Это не совсем разыменование указателя, а взятие адреса, по этому код имеет потенциальное право на жизнь. Существуют реализации макроса offsetof точно таким-же образом:
en.wikipedia.org/wiki/Offsetof
habrahabr.ru/company/pvs-studio/blog/198060/#comment_6871226
У меня нет уверенности на счет того, что это точно не UB, но известные мне компиляторы понимают этот код правильно, так как сами используют такое.
+1
Согласен. Я собственно и говорил, что особенных вещей не нашлось. Но надо попридираться то. А то вроде как зря мучился. :)
+2
Согласно стандарту — это UB.
При этом компилятор вправе реализовать offsetof таким образом, потому что реализация стандартной библиотеки привязана к конкретному компилятору, и может спокойно полагаться на его особенности вроде вот этой.
При этом компилятор вправе реализовать offsetof таким образом, потому что реализация стандартной библиотеки привязана к конкретному компилятору, и может спокойно полагаться на его особенности вроде вот этой.
0
С точки зрения компилятора код
эквивалентен коду
Т.е. в этом коде разыменование — это вот это:
А взятие адреса там уже после разыменования.
XDR *xdrs = &clp->xdr_stream;
эквивалентен коду
XDR *xdrs = &((*clp).xdr_stream);
Т.е. в этом коде разыменование — это вот это:
clp->
А взятие адреса там уже после разыменования.
+2
Я не знаю. Возможно. В winnt.h сделано так:
FORCEINLINE PVOID RtlSecureZeroMemory( _Out_writes_bytes_all_(cnt) PVOID ptr, _In_ SIZE_T cnt ) { volatile char *vptr = (volatile char *)ptr; #if defined(_M_AMD64) __stosb((PBYTE )((DWORD64)vptr), 0, cnt); #else while (cnt) { #if !defined(_M_CEE) && defined(_M_ARM) __iso_volatile_store8(vptr, 0); #else *vptr = 0; #endif vptr++; cnt--; } #endif // _M_AMD64 return ptr; }
-1
__builtin_strcmp
Иногда гнать весь код через препроцессор компилятора не самое удачное решение. Именно как раз потому, что это implementation-defined, зависит от используемого компилятора/ОС и не позволяет вычислять ошибки совместимости. Но есть хорошие новости: можно задать параметр оптимизации -O0, когда никаких «левых» inline-подстановок компилятора не возникнет.
Для меня стало открытием наличие такого бреда в препроцессоре. В ассемблерном варианте окажется что-то вроде этого:
movq %rdi, %rax
movq %rsi, %rdi
movq %rax, %rsi
jmp strcmp
+1
Удачное/не удачное — выбора нет. Препроцессинг нужен. И нужно уметь работать, в независимости, от ключей. Как проект собирается, с теми ключами и надо его проверять, подменив собой компилятор. Спасибо за информацию про -O0. Но к сожалению, жизнь разработчикам анализаторов это не упрощает. :)
0
А если учесть что GLibC с -O0 вообще собрать нельзя…
+2
Насколько я знаю, этот анализатор проект не собирает — надо вручную прогнать через препроцессор и потом уже скормить ему полученные i-файлы.
-1
«надо вручную прогнать через препроцессор» — Не надо сбивать с толку людей. А то останется в голове, что это велосипед с ручным приводом. :)
Да, есть и вариант с *.i файлами. А также масса других методов, с которыми можно познакомиться в документации. Например, это интеграция в makefile. Ну а если у Вас Visual C++, так вообще просто надо кнопку нажать и всё проверится.
Да, есть и вариант с *.i файлами. А также масса других методов, с которыми можно познакомиться в документации. Например, это интеграция в makefile. Ну а если у Вас Visual C++, так вообще просто надо кнопку нажать и всё проверится.
+2
Ну а если у Вас Visual C++
Особенно легко и непринуждённо VS запускается в RHEL.
Если статья об анализе ключевой библиотеки Linux, вы привлекли внимание всех читателей хаба Linux — извольте приоткрыть тайну анализа линуксовых библиотек. Сейчас из поста получается «раз! — и результат» — это-то и сбивает с толку людей. А процесс копания в настройках компилятора/препроцессора, а также ковыряние километрового лога остался за кадром. Было бы интересно читать как вы решали эти проблемы, а не как тяжело писать код под Linux.
+1
Как на счёт проверить Transmission?
-1
По поводу
Это не могло быть странной попыткой оптимизации? Например, такая логика автора. Проверка на '\0', если не проходит, сразу вываливаемся из цикла, без проверки на ':'.
while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
Это не могло быть странной попыткой оптимизации? Например, такая логика автора. Проверка на '\0', если не проходит, сразу вываливаемся из цикла, без проверки на ':'.
0
И где оптимизация? :)
0
> 581 /* Make CATEGORYVALUE point to the next element of the list. */
> 582 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
> 583 ++categoryvalue;
И что же такого этот код поясняет, что не пояснил бы
> 582 while (categoryvalue[0] == ':')
> 583 ++categoryvalue;
? Как по мне, наоборот, запутывает.
> 582 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
> 583 ++categoryvalue;
И что же такого этот код поясняет, что не пояснил бы
> 582 while (categoryvalue[0] == ':')
> 583 ++categoryvalue;
? Как по мне, наоборот, запутывает.
+4
А не планируете ли Вы проверить опенсорсный проект Tesseract-OCR?
code.google.com/p/tesseract-ocr/
code.google.com/p/tesseract-ocr/
0
sunrpc/clnt_raw.c это пропиетарное наследие от уже вымерших мамонтов. по умолчанию не компилируется. тут анализатор занимается археологией — в самом деле, поучительно.
там история коммитов выглядит интереснее, чем сам код:
кстати, в текущей ревизии в копирайтах значится Oracle.
там история коммитов выглядит интереснее, чем сам код:
2012-05-10 Andreas Jaeger Make sunrpc code usable again
2011-04-17 Ulrich Drepper Obsolete RPC implementation in libc.
2010-08-19 Ulrich Drepper Once again change RPC copyright notices.
2010-06-28 Ulrich Drepper Revert «Sun agreed to a change of the license for the…
2009-05-21 Ulrich Drepper Sun agreed to a change of the license for the RPC code…
…
1995-02-18 Roland McGrath initial import
кстати, в текущей ревизии в копирайтах значится Oracle.
+1
Как насчёт проверки KPHP HHVM?
0
для nss/getnssent_r.c анализатор написал ерунду, и у вас код отквочен не правильно:
тут видно, что в первом случае (145) присваивается значение, в указатель, пришедший в функцию в качестве параметра. он не может быть NULL по соглашению. в 163 этот указатель передается по ссылке функции DL_CALL_FCT, и в 172 проверяется уже новое значение, возвращаемое этой функцией.
смотрим
127 int
128 __nss_getent_r (const char *getent_func_name,
129 const char *setent_func_name,
130 db_lookup_function lookup_fct,
131 service_user **nip, service_user **startp,
132 service_user **last_nip, int *stayopen_tmp, int res,
133 void *resbuf, char *buffer, size_t buflen,
134 void **result, int *h_errnop)
....
144 if (res && __res_maybe_init (&_res, 0) == -1)
145 {
146 *h_errnop = NETDB_INTERNAL;
147 *result = NULL;
148 return errno;
149 }
150
...
159 while (! no_more)
160 {
161 int is_last_nip = *nip == *last_nip;
162
163 status = DL_CALL_FCT (fct.f,
164 (resbuf, buffer, buflen, &errno, &h_errno));
165
166 /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
167 provided buffer is too small. In this case we should give
168 the user the possibility to enlarge the buffer and we should
169 not simply go on with the next service (even if the TRYAGAIN
170 action tells us so). */
171 if (status == NSS_STATUS_TRYAGAIN
172 && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)
173 && errno == ERANGE)
174 break;
тут видно, что в первом случае (145) присваивается значение, в указатель, пришедший в функцию в качестве параметра. он не может быть NULL по соглашению. в 163 этот указатель передается по ссылке функции DL_CALL_FCT, и в 172 проверяется уже новое значение, возвращаемое этой функцией.
+1
XDR *xdrs = &clp->xdr_stream;
…
if (clp == NULL)
Ложное срабатывание. Разыменовывание не происходит, просто один указатель (xdrs) получает значение другого указателя (cpl) плюс смещение поля xdr_stream.
UPD. А. уже написали выше… habrahabr.ru/company/pvs-studio/blog/213969/#comment_7356737
+1
А можно у вас заказать проверку других опенсорсных библиотек? В частности, интересует ffmpeg
0
Вы еще линукс-ядро не смотрели… Там иногда такое встречается-сомневаешься на С ли это написано
0
А если github.com/zinnschlag/openmw/ проверить?
0
Sign up to leave a comment.
Эксперимент по проверке библиотеки glibc