Анализ статического кода для обнаружения прохождения wchar_t * в BSTR
Так как a BSTR
является только typedef
для wchar_t*
, наша база кода имеет несколько (много?) мест, где строковые литералы передаются методу, ожидающему BSTR
, это может испортить маршаллеры или кого-либо, кто пытается использовать любой специальный метод BSTR
(например, SysStringLen
).
Есть ли способ статически обнаружить этот тип неправильного использования?
Я попробовал компиляцию с VC10 /Wall
и с анализом статического кода Microsoft All Rules, но следующий фрагмент кода не может быть отмечен ни одним из них.
void foo(BSTR str)
{
std::cout << SysStringLen(str) << std::endl;
}
int _tmain()
{
foo(L"Don't do that");
}
Обновление:. После попытки аннулировать wtypes.h
для обнаружения таких видов нарушений я отказался.
Я пробовал два пути, оба из которых я получил, чтобы работать с моей примерной программой выше, но как только я попробовал реальный проект, они потерпели неудачу.
- создайте класс с именем
BSTR
, но поскольку VARIANT
имеет BSTR
в качестве члена объединения, новый класс не может иметь никаких конструкторов или операторов присваивания, которые были разбиты на все места, NULL
рассматривался как BSTR
. Я попытался заменить NULL
на тип, который имеет операторы преобразования, но после добавления десятков новых операторов (сравнение, преобразование и т.д.) Я начал сталкиваться с неоднозначными вызовами и сдавался.
- Затем я попробовал способ, предложенный @CashCow и @Hans (make
BSTR
a typedef
для другого типа указателя). Это также не сработало, добавив методы toBSTR
и fromBSTR
и засорив comutil.h(_bstr_t
) и другие места с конверсиями. Наконец, я дошел до того момента, когда компилятор задохнулся в заголовках, созданных из IDL (значения по умолчанию переводятся в буквальные широкие строки).
Короче говоря, я отказался от попыток добиться этого самостоятельно, если кто-нибудь знает инструмент анализа кода, который может помочь, я был бы очень рад услышать об этом.
Ответы
Ответ 1
Я считаю, Coverity утверждает, что обнаруживает эти виды уязвимостей. Я помню, как они упоминали о COM-материалах, когда они демонстрировали компанию, в которой я работал.
Их datasheet, несомненно, подразумевают, что они проверяют классы неправильного использования BSTR. У них есть демо-период; вы можете попробовать его и посмотреть, помещает ли он ваш образец ввода.
Ответ 2
Можете ли вы изменить свои методы, чтобы вместо этого использовать _bstr_t или CComBSTR?
Если нет, то в качестве литерала есть технически константа wchar_t *, если есть параметр компилятора, чтобы не разрешать преобразование literal- > non-const, тогда вы можете это сделать.
В противном случае существует возможность изменить определение BSTR как unsigned short *. Затем, если вы построите весь свой источник, вы получите ошибки компилятора везде, где передается литерал, и вы можете исправить весь этот код. Тогда я бы предложил изменить его обратно...
Ответ 3
Вы можете попробовать скомпилировать Clang, статический/динамический анализ может найти то, что вы ищете.
Ответ 4
Перегрузите все функции с помощью BSTR и переместите их с соответствующим преобразованием.
void foo( BSTR str )
{
std::cout << SysStringLen(str) << std::endl;
}
void foo( const WCHAR *str )
{
foo( SysAllocString( str ));
}
int _tmain()
{
foo( L"don't do this" );
return 0;
}
Или, чтобы сгенерировать ошибки компилятора, измените все типы параметров из BSTR на что-то еще и найдите ошибки:
typedef UINT bar;
void foo( bar _str )
{
// make the compiler happy below
BSTR str = (BSTR)_str;
std::cout << SysStringLen(str) << std::endl;
}
int _tmain()
{
foo( L"don't do this" );
foo( (bar)42 );
return 0;
}
ошибка C2664: 'foo': невозможно преобразовать параметр 1 из 'const wchar_t [14]' в 'bar'
Я предполагаю, что ошибка C2664 и тип 'const wchar_t []', идентифицированный компилятором, - это то, что вы хотите, чтобы компилятор обнаружил для каждого внутреннего вызова, выполняемого с помощью функции BSTR?