Почтовый клиент Mozilla Thunderbird
Mozilla Thunderbird — бесплатная кроссплатформенная свободно распространяемая программа для работы с электронной почтой и группами новостей, разработанная компанией Mozilla Foundation. Основными преимуществами использования Thunderbird считаются простота и гибкость программы. Пользователь сам может настроить интерфейс, меняя, добавляя или удаляя кнопки. В добавок к этому поддерживается установка расширений и новых тем оформлений. Программа может использовать цифровые подписи, шифрование сообщений и проверку сертификатов.
Об анализаторе PVS-Studio
PVS-Studio — статический анализатор кода для С и С++ программ. PVS-Studio предоставляется как плагин к системе разработки Visual Studio, но может быть использован и через утилиту Standalone. Эта утилита имеет функцию мониторинга, которая отслеживает вызовы компилятора и передает нужные файлы анализатору. Таким образом PVS-Studio не зависит от сборочной системы проекта.
Инструмент прост в использовании, поэтому вместо многих слов, лучше скачать и попробовать демонстрационную версию на своем собственном коде.
Сборка и проверка Thunderbird
Mozilla имеет свою собственную сборочную систему. Инструкцию, описывающую основные шаги для сборки проекта можно найти здесь. Сама сборка сделана максимально удобно для пользователя. Mozilla предоставляет бинарный инсталлятор всех необходимых для установки под windows утилит, например, 7zip, msys, mercurial и т.п.
Проверка была осуществлена с помощью упомянутой выше системы мониторинга вызовов компилятора, которой обладает утилита Standalone, входящая в комплект PVS-Studio.
Предупреждения анализатора
Thunderbird является крупным проектом и использует множество сторонних библиотек. Большинство предупреждений пришлось именно на их код. Для статьи я постарался отсеять эти предупреждения и оставить только те, которые выдавались на исходный код почтовой программы.
Кроме того, для описания багов в проектах Mozilla есть страница с описанием ключевых слов. Среди них можно найти такие как coverity, klocwork, valgrind и clang-anazyler. Похоже, что эти средства анализа кода уже используются в Mozilla. Так что будет интересно посмотреть на то, что не заметили эти анализаторы.
Подозрительные условия
Предупреждение PVS-Studio: V501 There are identical sub-expressions 'aStatus == NS_ERROR_OFFLINE' to the left and to the right of the '||' operator. nsdocshell.cpp 7606
nsresult
nsDocShell::EndPageLoad(nsresult aStatus, ....)
{
if(....)
{
....
}
else if (aStatus == NS_ERROR_NET_TIMEOUT ||
....
aStatus == NS_ERROR_OFFLINE ||
aStatus == NS_ERROR_MALWARE_URI ||
aStatus == NS_ERROR_PHISHING_URI ||
aStatus == NS_ERROR_UNWANTED_URI ||
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
aStatus == NS_ERROR_REMOTE_XUL ||
aStatus == NS_ERROR_OFFLINE ||
....)
}
Этот код содержит лишнюю проверку «NS_ERROR_OFFLINE». Список значений, на которые нужно проверить переменную 'aStatus' большой, поэтому легко можно ошибиться и случайно продублировать проверку. Вторым вариантом может быть то, что программист после копирования вставлял одну и ту же строчку, чтобы не переписывать одинаковую часть, и забыл поменять название константы «NS_ERROR_OFFLINE». В таком случае в коде не хватает одной нужной проверки.
Предупреждение PVS-Studio: V590 Consider inspecting the 'type != (1) && type == (2)' expression. The expression is excessive or contains a misprint. nswindowsregkey.cpp 313
#define REG_SZ ( 1 )
#define REG_EXPAND_SZ ( 2 )
#define REG_MULTI_SZ ( 7 )
NS_IMETHODIMP
nsWindowsRegKey::ReadStringValue(const nsAString& aName,
nsAString& aResult)
{
....
if (type != REG_SZ &&
type == REG_EXPAND_SZ &&
type == REG_MULTI_SZ)
{
return NS_ERROR_FAILURE;
}
....
}
Условие «type == REG_EXPAND_SZ && type == REG_MULTI_SZ» всегда ложно, так как одна переменная не может иметь два значения одновременно. Как результат, функция никогда не вернет статус ошибки NS_ERROR_FAILURE.
Предупреждение PVS-Studio: V616 The 'eBorderStyle_none' named constant with the value of 0 is used in the bitwise operation. nswindow.cpp 2318
enum nsBorderStyle
{
eBorderStyle_none = 0,
....
}
NS_IMETHODIMP nsWindow::SetNonClientMargins(....)
{
if (!mIsTopWidgetWindow ||
mBorderStyle & eBorderStyle_none)
return NS_ERROR_INVALID_ARG;
....
}
При проверке условия используется константа со значением 0, которая участвует в побитовой операции «И» с переменной. Результатом операции, разумеется, тоже будет ноль. Таким образом условие не зависит от переменной «mBorderStyle».
Подобное предупреждение:
- V616 The 'nsIDocShell::BUSY_FLAGS_NONE' named constant with the value of 0 is used in the bitwise operation. presentationcallbacks.cpp 105
Предупреждение PVS-Studio: V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. nsnativethemewin.cpp 924:
nsresult
nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame,
uint8_t aWidgetType,
int32_t& aPart,
int32_t& aState)
{
....
{
....
if (!aFrame) {
aState = TS_NORMAL;
} else {
if (GetCheckedOrSelected(aFrame, !isCheckbox)) {
inputState = CHECKED;
} if (isCheckbox && GetIndeterminate(aFrame)) {
inputState = INDETERMINATE;
}
....
} ....
}
Возможно, что перед последним «if» пропущено слово else. Код к текущем виде подразумевает, что могут выполниться оба условия if, и тогда значение «CHECKED» в переменной «inputState» будет изменено на «INDETERMINATE». Если бы в этом коде выполнялось либо одно условие, либо другое, то логичней было бы использовать «if — else», как во внешней конструкции.
Еще одна похожая конструкция располагается здесь:
- V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. debugger.cpp 4794
Предупреждение PVS-Studio: V713 The pointer mHTMLEditor was utilized in the logical expression before it was verified against nullptr in the same logical expression. nshtmleditrules.cpp 6593:
nsHTMLEditor* mHTMLEditor;
nsresult
nsHTMLEditRules::SplitParagraph(...)
{
if (mHTMLEditor->IsTextNode(child) ||
!mHTMLEditor ||
mHTMLEditor->IsContainer(child))
....
}
Функция «SplitParagraph» в своей проверке содержит ошибочный порядок аргументов. Если в данном коде указатель mHTMLEditor будет нулевым, то перед обнаружением этого он уже будет разыменован, что приведет к неопределенному поведению. Чтобы исправить код, нужно поменять местами "!mHTMLEditor" и «mHTMLEditor->IsTextNode(child)».
Две аналогичных ошибки располагаются здесь:
- V713 The pointer mHTMLEditor was utilized in the logical expression before it was verified against nullptr in the same logical expression. nshtmleditrules.cpp 7392
- V713 The pointer mHTMLEditor was utilized in the logical expression before it was verified against nullptr in the same logical expression. nshtmleditrules.cpp 7413
Предупреждение PVS-Studio: V522 Dereferencing of the null pointer 'aStyleValues' might take place. sdnaccessible.cpp 252:
STDMETHODIMP sdnAccessible::get_computedStyle(
BSTR __RPC_FAR* aStyleProperties,
BSTR __RPC_FAR* aStyleValues,
unsigned short __RPC_FAR* aNumStyleProperties)
{
if (!aStyleProperties || aStyleValues || !aNumStyleProperties)
return E_INVALIDARG;
....
aStyleValues[realIndex] = ::SysAllocString(value.get());
....
}
Как говорится, заметь проказника.
Анализатор обнаружил разыменование нулевого указателя. При проверке программист забыл поставить "!" перед «aStyleValues». Дальнейший код получает управление только тогда, когда этот указатель будет равен нулю, и приводит к его разыменованию.
Предупреждение PVS-Studio: V547 Expression is always false. Probably the '||' operator should be used here. nsmsgdbview.cpp 3014:
class NS_NO_VTABLE nsMsgViewCommandType
{
enum
{
....
junk = 27,
unjunk = 28,
....
};
};
nsresult nsMsgDBView::
ApplyCommandToIndices(nsMsgViewCommandTypeValue command, ....)
{
....
if ((command == nsMsgViewCommandType::junk) &&
(command == nsMsgViewCommandType::unjunk))
....
}
Код, соответствующий блоку if никогда не будет выполняться, поскольку переменная command не может одновременно иметь два значения. Более логичным здесь кажется использование оператора «ИЛИ» — "||".
Проблемы с указателями
Предупреждение PVS-Studio: V579 The HashBytes function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the second argument. nsdisplaylist.h 929:
struct AnimatedGeometryRootLookup
{
....
PLDHashNumber Hash() const
{
return mozilla::HashBytes(this, sizeof(this));
}
....
}
Анализатор счел подозрительным, что в функцию «HashBytes» первым аргументом передается указатель, а вторым — размер указателя. Если поискать в исходных файлах по названию функции, то в файле «hashfunctions.h» можно найти следующий комментарий:
/* Utilities for hashing. */
/*
* This file exports functions for hashing data down
* to a 32-bit value, including:
....
* - HashBytes Hash a byte array of known length.
....
*/
Комментарий подсказывает, что вторым аргументом должен быть размер объекта, располагающегося по указателю. Скорее всего правильный код должен выглядеть так:
return mozilla::HashBytes(this, sizeof(*this));
Перейдем к следующему предупреждению.
Предупреждение PVS-Studio: V611 The memory was allocated using 'new' operator but was released using the 'free' function. Consider inspecting operation logics behind the 'instanceData' variable. nptest.cpp 971:
NPError NPP_New(....)
{
....
InstanceData* instanceData = new InstanceData;
....
free(instanceData);
....
}
Ошибка заключается в том, что память выделяется с помощью оператора «new», а освобождается с помощью «free». Функция «free» не вызывает деструктор объекта, располагающегося по этому указателю. Это значит, что если объект содержал в себе еще указатели с выделенной памятью, то она не будет освобождена и произойдет утечка.
Да и вообще так делать нельзя. Подобный код приводит к неопределенному поведению программы.
Предупреждение PVS-Studio: V614 Potentially uninitialized pointer 'hOldFont' used. progressui_win.cpp 168:
static void InitDialog(....)
{
....
HFONT hInfoFont, hOldFont;
hInfoFont = (HFONT)SendMessage(hWndInfo, WM_GETFONT, 0, 0);
if (hInfoFont)
hOldFont = (HFONT)SelectObject(hDCInfo, hInfoFont);
....
if (hOldFont)
SelectObject(hDCInfo, hOldFont);
....
}
Если функция «SendMessage» вернет ноль, то результат следующей проверки будет false, а значит переменная hOldFont не будет инициализирована. Переменная будет иметь случайное значение, которое может быть не равно нулю. Если оно не равно 0, то это случайное значение будет передано в функцию SelectObject.
Еще одна подобная ситуация может возникнуть здесь:
- V614 Potentially uninitialized pointer 'queryD3DKMTStatistics' used. gfxwindowsplatform.cpp 206
Ошибки copy-paste
Предупреждение PVS-Studio: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 1060, 1062. nsstylestruct.cpp 1060:
nsStyleClipPath::nsStyleClipPath(const nsStyleClipPath& aSource)
{
if (aSource.mType == NS_STYLE_CLIP_PATH_URL) {
SetURL(aSource.mURL);
} else if (aSource.mType == NS_STYLE_CLIP_PATH_SHAPE) {
SetBasicShape(aSource.mBasicShape, aSource.mSizingBox);
} else if (aSource.mType == NS_STYLE_CLIP_PATH_SHAPE) {
SetSizingBox(aSource.mSizingBox);
}
}
Блок «if — else if» содержит повторяющуюся проверку на равенство, вызванную copy-paste методом. Это означает, что последняя часть кода, соответствующая второй проверке на «NS_STYLE_CLIP_PATH_SHAPE», никогда не будет выполнена.
Предупреждение PVS-Studio: V523 The 'then' statement is equivalent to the 'else' statement.
mozspelli18nmanager.cpp 34:
NS_IMETHODIMP
mozSpellI18NManager::GetUtil(mozISpellI18NUtil **_retval, ....)
{
....
nsAutoString lang;
....
if(lang.EqualsLiteral("en"))
{
*_retval = new mozEnglishWordUtils;
}
else
{
*_retval = new mozEnglishWordUtils;
}
NS_IF_ADDREF(*_retval);
return NS_OK;
}
Анализатор обратил внимание на то, что блокам if и else соответствуют одинаковые действия. Это может быть ошибкой при копировании, лишним условием или просто недописанным кодом. Так или иначе в данном виде условие не имеет смысла.
Еще несколько подобных ошибок:
- V523 The 'then' statement is equivalent to the 'else' statement. jemalloc.c 6504
- V523 The 'then' statement is equivalent to the 'else' statement. nsnativethemewin.cpp 1007
- V523 The 'then' statement is equivalent to the 'else' statement. msgmapihook.cpp 677
Неопределенное поведение
Предупреждение PVS-Studio: V595 The 'aParent' pointer was utilized before it was verified against nullptr. Check lines: 511, 518. nsgenericdomdatanode.cpp 511:
#define NS_ADDREF(_ptr) (_ptr)->AddRef()
nsresult
nsGenericDOMDataNode::BindToTree(nsIContent* aParent, ....)
{
....
ShadowRoot*
parentContainingShadow = aParent->GetContainingShadow();
....
if (aParent)
{
if (!GetParent())
{
NS_ADDREF(aParent);
}
mParent = aParent;
}
....
}
Проверка указателя «aParent» подсказывает, что он может быть нулевым. Это значит, что при первом его разыменовании, которое происходит до проверки, мы рискуем получить неопределенное поведение.
Предупреждение V595 является одним из самых распространенных среди проверяемых проектов, и Thunderbird — не исключение. Всего анализатор выдал 95 предупреждений, касающихся непосредственно кода Thunderbird.
Предупреждение PVS-Studio: V610 Undefined behavior. Check the shift operator '<<'. The left operand '~0L' is negative. nsprotocolproxyservice.cpp 336:
static void
proxy_MaskIPv6Addr(PRIPv6Addr &addr, uint16_t mask_len)
{
....
addr.pr_s6_addr32[3] = PR_htonl(
PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len)));
....
}
Когда один из параметров смещения влево является отрицательным числом, поведение не определено. Вот что сказано об этом в стандарте:
The shift operators << and >> group left-to-right. shift-expression << additive-expression, shift-expression >> additive-expression.
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. 1. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand. 2.… If E1 has an unsigned type, the value of the result is E1 * 2^E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1*2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined. ...
Еще 3 случая неопределенного поведения:
- V610 Undefined behavior. Check the shift operator '<<'. The left operand '~0L' is negative. nsprotocolproxyservice.cpp 341
- V610 Undefined behavior. Check the shift operator '<<'. The left operand '~0L' is negative. nsprotocolproxyservice.cpp 347
- V610 Undefined behavior. Check the shift operator '<<'. The left operand '~0L' is negative. nsprotocolproxyservice.cpp 354
Предупреждения с функциями
Предупреждение PVS-Studio: V597 The compiler could delete the 'memset' function call, which is used to flush 'ctx' object. The RtlSecureZeroMemory() function should be used to erase the private data. gmploader.cpp 166:
bool GMPLoaderImpl::Load(....)
{
SHA256Context ctx;
....
// Overwrite all data involved in calculation as it could
//potentially identify the user, so there's no chance a GMP
//can read it and use it for identity tracking.
memset(&ctx, 0, sizeof(ctx));
....
}
Здесь анализатор обратил внимание, что вызов функции 'memset' может быть удалён. Так как переменная 'ctx' в дальнейшем не используется, компилятор имеет полное право при оптимизации убрать вызов «memset». В Windows можно воспользоваться функцией «RtlSecureZeroMemory».
Предупреждение PVS-Studio: V530 The return value of function 'getenv' is required to be utilized.
nswindowswmain.cpp 134
int wmain(int argc, WCHAR **argv)
{
....
// Force creation of the multibyte _environ variable.
getenv("PATH");
int result = main(argc, argvConverted, _environ);
....
}
Здесь мы имеем дело с вызовом функции «getenv», результат которой не используется и даже не записывается в переменную. Вот как описана эта функция на сайте cplusplus.com.
Retrieves a C-string containing the value of the environment variable whose name is specified as argument. If the requested variable is not part of the environment list, the function returns a null pointer.
UPD: habrahabr.ru/company/pvs-studio/blog/267663/#comment_8589575
Прочие предупреждения
Предупреждение PVS-Studio: V609 Divide by zero. Denominator range [0..8]. ionbuilder.cpp 10922:
static inline size_t UnboxedTypeSize(JSValueType type)
{
switch (type) {
....
default: return 0;
}
}
MInstruction*IonBuilder::loadUnboxedProperty(size_t offset,
JSValueType unboxedType, ....)
{
size_t index = offset / UnboxedTypeSize(unboxedType);
....
}
Так как функция «UnboxedTypeSize» может вернуть ноль, то потенциально мы имеем дело с делением на ноль. Если в функцию «UnboxedTypeSize» будет передан новый тип, то она вернёт дефолтное нулевое значение, что приведёт к возникновению исключительной ситуации. Лучше перестраховаться и добавить проверку перед делением.
Еще одно потенциальное деление на ноль:
- V609 Divide by zero. Denominator range [0..8]. ionbuilder.cpp 11844
Предупреждение PVS-Studio: V621 Consider inspecting the 'for' operator. It's possible that the loop will be executed incorrectly or won't be executed at all. nsmsgdbfolder.cpp 4501:
NS_IMETHODIMP
nsMsgDBFolder::GetDisplayRecipients(bool *displayRecipients)
{
....
// There's one FCC folder for sent mail, and one for sent news
nsIMsgFolder *fccFolders[2];
int numFccFolders = 0;
for (int i = 0; i < numFccFolders; i++)
{
....
}
....
}
Анализатором было найдено подозрительное место, в котором цикл не проходит ни одной итерации. Причиной этого является переменная «numFccFolders», значение которой равно нулю. Возможно, это присваивание сделано с какой-то целью, но также возможно, что это опечатка. Комментарий и объявление указателя выше подсказывают, что переменная должна иметь значение 2.
Предупреждение PVS-Studio: V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'Assign' function. nsgenerichtmlelement.h 411:
class nsGenericHTMLElement : public nsGenericHTMLElementBase,
public nsIDOMHTMLElement
{
....
NS_IMETHOD GetItemId(nsAString& aId) final override {
nsString id;
GetItemId(id);
aId.Assign(aId);
return NS_OK;
}
....
}
Само по себе использование объекта «aId» как аргумента в своем же методе не является ошибкой. Но этот код подозрителен тем, что в функции используется переменная с похожим названием «id». Это наводит на мысль, что здесь содержится опечатка и аргументом функции «aId.Assign» должна быть переменная «id».
Предупреждение PVS-Studio: V670 The uninitialized class member 'mWorkerConnection' is used to initialize the 'mWorkerStatements' member. Remember that members are initialized in the order of their declarations inside a class. domstoragedbthread.cpp 50
DOMStorageDBThread::DOMStorageDBThread()
: mWorkerStatements(mWorkerConnection)
, ....
{}
class DOMStorageDBThread final : public DOMStorageDBBridge
{
private:
....
StatementCache mWorkerStatements; //<=line 304
....
nsCOMPtr<mozIStorageConnection> mWorkerConnection; //<=line 309
....
}
При использовании списка инициализации следует помнить об одном нюансе: переменные инициализируется в том порядке, в каком они объявлены в классе, а порядок в списке инициализации значения не имеет. В этом коде переменная «mWorkerStatements» инициализируется объектом «mWorkerConnection» другого класса. Но на момент инициализации для этого объекта еще не был вызван конструктор, так как в классе он объявлен позже, чем переменная «mWorkerStatements». Чтобы исправить это, достаточно поменять местами объявление этих двух объектов в классе.
В этом классе прячется еще одна такая же ошибка:
- V670 The uninitialized class member 'mReaderConnection' is used to initialize the 'mReaderStatements' member. Remember that members are initialized in the order of their declarations inside a class. domstoragedbthread.cpp 51
Заключение
Подводя итог хочу заметить, что PVS-Studio нашел много подозрительных мест в проекте Mozilla Thunderbird. Большинство из них относятся к сторонним библиотекам. Тем не менее и в самом Thunderbird нашлись интересные ошибки.
Написать большой проект без ошибок не под силу даже самым опытным и внимательным программистам. Для таких целей и существуют статические анализаторы кода. Их использование поможет вам сэкономить время на поиск старых ошибок и не допустить новых. Предлагаю попробовать PVS-Studio на вашем проекте: http://www.viva64.com/ru/pvs-studio-download/.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Igor Shtukarev. Static Analysis of Mozilla Thunderbird's Code by PVS-Studio.
Комментарии (34)
amarao
24.09.2015 18:30+11Зарепортили?
poxu
25.09.2015 12:55amarao
25.09.2015 14:07+2Ну вы пишите на хабр. Не то, чтобы меня ваш софт интересовал — лучше такие вещи писать в самом посте. Ещё круче, если с ссылкой на багрепорт, чтобы можно было посмотреть на то, как его фиксят.
poxu
26.09.2015 14:11В конце самой статьи есть ссылка на FAQ. Копировать его в каждую статью странно.
Что касается ссылок на багрепорт, наверное было бы круче. Но это, увы не ко мне, я к PVS Studio никакого отношения не имею.
clogic
24.09.2015 19:41-7Уважаемые авторы PVS-Studio, я прочел много ваших сататей на хабре и на вашем сайте. Интересная и, главное, полезная информация. Но, у меня есть небольшая просьба. Я понимаю что вы пишете в своем блоге так, как сами сочтете нужным, но тем не менее. Мы с вами находимся на техническом ресурсе, среди специалистов которым интересны поднятые вами темы. Было бы чудесно, если бы в ваших статьях было меньше рекламы и маркетинговых слоганов, копируемых вами из статьи в статью. Ваши читатели не умственно отсталые и уже успели выучить название продукта, как и его назначение. Обидно когда интересная статья смешана с маркетинговой копипастой. Все мы любим хабр за технические подробности а не за маркетинг. Еще раз повторюсь, мне интересны поднятые вами темы. Благодарю за ваш труд.
Andrey2008
24.09.2015 23:40-3Предлагаю тогда обратить внимание на наш проект C++Hints. Я здесь не стараюсь его рекламировать (не даю ссылки), так как судьба ресурса ещё не определена. Слишком мало подписчиков и возможно мы так и не соберем аудиторию. Тогда придётся придать его забвению.
clogic
25.09.2015 08:06+6Предлагаю тогда обратить внимание на наш проект C++Hints.
Уже успел там побывать, думаю выбран правильный формат. На подобии цитатника ошибок. Вы уже упоминали ранее данный ресурс, в посте или комментарии. Но речь не о том.
За последнее время ваш вклад в наполнение хаба C++ наибольший и любой подписанный на него хабрапользователь давно знает кто вы, чем занимаетесь и что такое статический анализ. А я как пользователь языка С++ благодарен вам за его популяризацию.
Вы же и сами понимаете что читают вас на хабре одни и те же люди. Вам надо повышать качество статей. Посмотрите как пишет Milfgard — темы затронутые в его постах не входят в круг моих интересов, но читать его посты просто удовольствие. И представьте если бы в каждый свой пост он приписывал какие хорошие игры они продают и надо всем бежать скорее покупать… Попробуйте делать сравнение с другими статическими анализаторами. К примеру, вот мы взяли и проверили Thunderbird открытым анализатором и нашли столько-то подозрительных мест, а потом проверили PVS-Studio и нашли больше ошибок. Выводы мы сделаем сами, всегда интересно читать статьи своих коллег, так сказать — «от разработчиков для разработчиков». Повторение ключевых слов и слоганов скорее отталкивает читателя и более уместно в англоязычных версиях статей.fingoldo
25.09.2015 08:44+5Пусть рекламируют, имеют право. Я бы делал на их месте точно так же…
А насчёт того, что на Хабре одни и те же люди — я пропустил новость о моратории на новых пользователей?
Думал, они сотнями в месяц прибывают.clogic
25.09.2015 08:48Пусть рекламируют, имеют право.
Где вы увидели что я им это запрещаю? Я просто высказал свое мнение и указал пути улучшения качества статей.
А насчёт того, что на Хабре одни и те же люди — я пропустил новость о моратории на новых пользователей?
Думал, они сотнями в месяц прибывают.
О да, программисты активно использующие C++ прибывают на хабр сотнями в месяц.
nckma
25.09.2015 08:51+2я даже думаю, что все что публикуется на хабре имеет скрытый подтекст рекламы.
Человек конечно может на энтузиазме написать одну-две статьи. Но если он публикуется регулярно, то он однозначно рекламирует себя, свой продукт, программу, идею… а как иначе?
artspb
03.10.2015 20:43+1Посмотрите как пишет Milfgard — темы затронутые в его постах не входят в круг моих интересов, но читать его посты просто удовольствие.
C++ не входит в круг моих интересов, но я всегда с удовольствием читаю статьи Andrey2008 сотоварищи. И нет, мне не кажется, что в них слишком много маркетинга. Наоборот, по моим ощущениям, они написаны программистами для программистов.
ComodoHacker
25.09.2015 11:21+2По сравнению с другими
копро-корпо-блогами количество маркетинга в этом — абсолютно терпимое. Грех жаловаться.clogic
25.09.2015 11:26+2Всегда стараюсь сравнивать с лучшим. Если сравнивать с худшим то пропадает смысл развиваться (а зачем, ведь есть же и хуже?!).
grechnik
24.09.2015 19:42+3Здесь мы имеем дело с вызовом функции «getenv», результат которой не используется и даже не записывается в переменную. Вот как описана эта функция на сайте cplusplus.com.
Retrieves a C-string containing the value of the environment variable whose name is specified as argument. If the requested variable is not part of the environment list, the function returns a null pointer.
Использование «getenv» в таком виде бессмысленно и только смущает при чтении кода.
Это не так. msdn.microsoft.com/ru-ru/library/windows/desktop/stxk41x1%28v=vs.80%29.aspx:
In a program that uses the wmain function, _wenviron is initialized at program startup according to settings taken from the operating-system environment. [...] Similarly, in a program that uses wmain, _environ is initially NULL because the environment is composed of wide-character strings. On the first call to _getenv or _putenv, a corresponding multibyte-character string environment is created and is pointed to by _environ.
Чтобы из W-версии wmain использовать A-версию _environ, как раз и нужен A-вызов getenv, возвращаемое значение которого можно выбросить.
ASD2003ru
24.09.2015 21:15+7Что бы PVS-Studio не показало бы, но это последний адекватный почтовый клиент. Надеюсь разработчики учтут найденные огрехи и поправят.
Mithgol
26.09.2015 09:30Поведение версий последнего релиза Thunderbird не выглядит адекватным, потому что ошибка 1196662, патч для которой
есть в бета-версии, но из беты пойдёт в релиз недель через шесть. Долго, уныло ждать.
asm0dey
24.09.2015 22:22+1А вы случайно не планируете (или уже?) проверку OpenJDK?
Andrey2008
24.09.2015 22:35+1Запишем в список пожеланий. Спасибо.
asm0dey
24.09.2015 22:58И вам спасибо. Было бы очень интересно. Я понимаю, что ребята практически лишают вас части рынка и наверняка и так проверяются тонной анализаторов — но всё равно очень интересно!
apangin
25.09.2015 01:02+3О! Как раз это же хотел предложить!
Только уточню, что не сам OpenJDK (который на 95% состоит из Java кода), а его конкретную часть — HotSpot JVM. На мой вкус, это один из самых замысловатых и любопытных проектов на C/C++, где грань между ошибкой и умыслом разработчика порой очень тонкая :)asm0dey
25.09.2015 08:52Да, спасибо за уточнение. Понятно, что Java код проверят не надо и не получится :)
Andrey2008
24.09.2015 23:30+1Не забываем сделать себе кружку у майку с единорогом: www.viva64.com/ru/merchandise Внимание со стороны коллег будет гарантировано.
itforge
А проверьте третий питон, пожалуста! Тут не нашёл его: www.viva64.com/ru/a/0084