2012-01-24 36 views
13

Desde un BSTR es sólo una typedef para wchar_t* nuestra base de código tiene varios (muchos?) Los lugares donde se pasan los literales de cadena a un método esperando un desastre BSTR esta lata con señaleros o cualquiera que intente utilizar cualquier método específico BSTR (por ejemplo, SysStringLen).análisis de código estático para detectar pasando un wchar_t * a BSTR

¿Hay alguna forma de detectar estáticamente este tipo de uso indebido?

he intentado compilar con VC10 /Wall y con el análisis de código estático Microsoft Todas las reglas pero el siguiente fragmento de código que no quede marcado por uno de ellos.

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

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

Actualización: Después de tratar de destrozar wtypes.h en la detección de este tipo de transgresiones que he dado por vencido.

Intenté dos rutas, ambas de las cuales comencé a trabajar con mi programa de ejemplo anterior, pero una vez que probé un proyecto real fallaron.

  1. crear una clase llamada BSTR pero desde un VARIANT tiene un BSTR como un miembro de un sindicato de la nueva clase no podían tener ningún constructor o los operadores de asignación Esto rompió todos los lugares se NULL fue tratado como un BSTR. Traté de reemplazar NULL con un tipo que tiene operadores de conversión pero después de agregar docenas de nuevos operadores (comparación, conversión, etc.) comencé a encontrarme con llamadas ambiguas y desistí.
  2. Probé de la manera sugerida por @CashCow y @Hans (haciendo BSTR a typedef a otro tipo de puntero). Eso tampoco funcionó, después de agregar los métodos toBSTR y fromBSTR y tirar basura comutil.h (_bstr_t) y otros lugares con conversiones finalmente llegué al punto en que el compilador se atascó en los encabezados producidos a partir de IDL (los valores predeterminados se traducen al literal cuerdas anchas).

En resumen, he dejado de tratar de lograr esto por mi cuenta, si alguien sabe de una herramienta de análisis de código que pueda ayudar, estaría encantado de saberlo.

+2

BSTR puede ser un typedef pero eso no significa que sea una cadena terminada en nulo. Su representación de cuerdas en realidad se forma con el tercer carácter wchar_t, el primero de los cuales es un prefijo de longitud (lo que permite una longitud de hasta 0xFFFF). Pueden contener nulos incorporados. Creo que generalmente son terminados en nulo. – CashCow

+3

@CashCow, no exactamente, la longitud se coloca * antes * de los datos reales (esto es lo que 'SysStringLen' busca) es por eso que es incorrecto tratar un' wchar_t * 'como un' BSTR'. – Motti

+0

Sí, la longitud es anterior a los datos. Cuando llamas a SysAllocString, te devuelve el quinto byte. Cuando pasa en un BSTR, pasa la dirección del quinto byte asignado. – CashCow

Respuesta

3

Creo que Coverity afirma que detecta este tipo de vulnerabilidades. Recuerdo que mencionaron cosas de COM específicamente cuando demostraron a una empresa para la que trabajaba.

Su datasheet ciertamente parece implicar que verifican las clases de uso incorrecto de BSTR. Tienen un período de demostración; podrías intentarlo y ver si marca tu entrada de muestra.

+0

Después de verificarlo, veo que 'COM.BSTR.CONV' detecta este patrón, ¡gracias! – Motti

1

¿Puede cambiar sus métodos para tomar _bstr_t o CComBSTR en su lugar?

Si no, entonces como un literal es técnicamente un const wchar_t *, si hay una configuración del compilador para no permitir la conversión del puntero literal-> no const, entonces puede hacerlo.

De lo contrario, existe la posibilidad de modificar la definición de BSTR para que sea unsigned short *. Entonces, si construyes toda tu fuente, obtendrás errores de compilación siempre que se transmita un literal y podrás corregir todo este código. Entonces sugeriría que lo cambie de nuevo ...

+0

No, ya que muchos de ellos son métodos COM puros. – Motti

+0

La opción 2 (evitar conversiones de 'const wchar_t *') no es suficiente, ya que no todas las instancias son cadenas literales. La opción 3 ('typedef unsigned short * BSTR') no funcionaría, ya que a veces pasamos un' BSTR' a 'wcscmp' (et al.) Que no acepta' unsigned short * ' – Motti

0

Sobrecargue todas las funciones con el BSTR y reenvíelas con la conversión adecuada.

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; 
} 

O, para generar errores de compilación, cambiar todos los tipos de parámetros de BSTR a otra cosa y buscar los errores:

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; 
} 

error C2664: 'foo': No se puede convertir el parámetro 1 de 'const wchar_t [14]' a 'bar'

Supongo que el error C2664 y el tipo 'const wchar_t []' identificado por el compilador es lo que quiere que el compilador encuentre para cada llamada interna realizada al función usando el BSTR?

1

Puede intentar compilar con Clang, su análisis estático/dinámico puede encontrar lo que está buscando.

+0

¿Clang admite la compilación de Microsoft C++ específico? ? – Motti

+0

Bastante seguro que lo hace ahora, y mejorando continuamente. – ticktock

Cuestiones relacionadas