2012-01-24 9 views
13

Поскольку BSTR лишь typedef для wchar_t* наш код базы имеет несколько (много?) Места, где строковые литералы передаются методу, ожидающей BSTR это может испортить с marshallers или любой, кто пытается использовать какой-либо конкретный метод BSTR (например, SysStringLen).Статический анализ кода для обнаружения прохождения wchar_t * в BSTR

Есть ли способ статического обнаружения такого рода злоупотреблений?

Я попытался компиляции с VC10 /Wall и статического анализа кода Microsoft Все правила но следующий обижая часть кода не получает помечено либо из них.

void foo(BSTR str) 
{ 
    std::cout << SysStringLen(str) << std::endl; 
} 

int _tmain() 
{ 
    foo(L"Don't do that"); 
} 

Update: После попытки хулиганить wtypes.h в обнаружении такого рода проступки я отказавших.

Я пробовал два пути, оба из которых я получил, чтобы работать с моей примерной программой выше, но как только я попробовал настоящий проект, они потерпели неудачу.

  1. создать класс с именем BSTR, но так как VARIANT имеет BSTR в качестве члена профсоюза нового класс не может иметь никаких конструкторов или оператор присваивания это нарушившие каждое место было NULL трактовалось как BSTR. Я попытался заменить NULL на тип, в котором есть операторы преобразования, но после добавления десятков новых операторов (сравнение, преобразование и т. Д.) Я начал сталкиваться с неоднозначными вызовами и сдавался.
  2. Затем я попробовал путь, предложенный @CashCow и @Hans (составление BSTR a typedef другому типу указателя). Это также не сработало, после добавления методов toBSTR и fromBSTR и засорения comutil.h (_bstr_t) и в других местах с конверсиями. Я, наконец, дошел до того момента, когда компилятор подавился в заголовках, созданных из IDL (значения по умолчанию переводятся в буквальные широкие струны).

Вкратце я отказался от попыток достичь этого самостоятельно, если кто-нибудь знает инструмент анализа кода, который может помочь, я был бы очень рад услышать об этом.

+2

BSTR может быть такой typedef, но это не означает, что это строка с нулевым символом. Его строковое представление фактически существа с третьим символом wchar_t, причем первые 2 являются префиксом длины (таким образом, длина до 0xFFFF). Они могут содержать встроенные нули. Я думаю, что они, как правило, заканчиваются нулями. – CashCow

+3

@CashCow, а не точно, длина помещается * перед * фактическими данными (это то, что ищет 'SysStringLen'), поэтому неправильно рассматривать' wchar_t * 'как' BSTR'. – Motti

+0

Да, длина перед данными. Когда вы вызываете SysAllocString, он возвращает вам 5-й байт. Когда вы проходите в BSTR, вы передаете адрес 5-го выделенного байта. – CashCow

ответ

3

Я считаю, что Coverity утверждает, что обнаруживает такие уязвимости. Я помню, как они упоминали о COM-материалах, когда они демонстрировали компанию, в которой я работал.

Их datasheet, несомненно, подразумевают, что они проверяют классы неправильного использования BSTR. У них есть демо-период; вы можете попробовать его и посмотреть, помещает ли он ваш образец ввода.

+0

После проверки этого я вижу, что 'COM.BSTR.CONV' обнаруживает этот шаблон, спасибо! – Motti

1

Вы можете изменить свои методы, чтобы вместо этого использовать _bstr_t или CComBSTR?

Если нет, то в качестве литерала является технически константа wchar_t *, если есть параметр компилятора, чтобы не допускать преобразования литерала-> неконстантного указателя, тогда вы можете это сделать.

В противном случае существует возможность изменить определение BSTR как unsigned short *. Затем, если вы построите весь свой источник, вы получите ошибки компилятора везде, где передается литерал, и вы можете исправить весь этот код. Тогда я бы предложил изменить его обратно ...

+0

Нет, поскольку многие из них являются чистыми COM-методами. – Motti

+0

Вариант 2 (запретить преобразование из 'const wchar_t *') недостаточно, поскольку не все экземпляры являются буквальными строками. Вариант 3 ('typedef unsigned short * BSTR') не будет работать, поскольку мы иногда передаем' BSTR' в 'wcscmp' (и др.), Который не принимает' unsigned short * ' – Motti

0

Перегрузить все функции с помощью 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 from 'const wchar_t [14]' to 'bar'

Я предполагаю, что ошибка C2664 и тип 'const wchar_t []', идентифицированный компилятором, - это то, что вы хотите, чтобы компилятор нашел для каждого внутреннего вызова, сделанного в функции с использованием BSTR?

1

Вы можете попробовать компилировать с помощью Clang, это статический/динамический анализ может найти то, что вы ищете.

+0

Поддерживает ли Clang компиляцию Microsoft специфического C++ ? – Motti

+0

Довольно уверен, что это происходит сейчас, и постоянно улучшается. – ticktock