Последовательное внедрение ошибок в бинарный код

This post is also available in: Английский

Цель — покрыть ветви кода, обрабатывающие ошибки выделения памяти. Ограничение — исследуем бинарный код.

Тестируем программу, полученную путем компиляции следующего кода:

int foo( unsigned int size )
{
void *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e =NULL;

a = malloc( size );
if( !a )
{
LogErr( "error allocating a\n" );
return -1;
}

LogDbg( "%u bytes allocated\n", size );

b = malloc( size * 2 );
if( !b )
{
LogErr( "error allocating b\n" );
return -1;
}

LogDbg( "%u bytes allocated\n", size * 2 );

c = malloc( size * 3 );
if( !c )
{
LogErr( "error allocating c\n" );
return -1;
}

LogDbg( "%u bytes allocated\n", size * 3 );

d = malloc( size * 4 );
if( !d )
{
LogErr( "error allocating d\n" );
return -1;
}

LogDbg( "%u bytes allocated\n", size * 4 );

e  = malloc( size * 5 );
if( !e )
{
LogErr( "error allocating e\n" );
return -1;
}

LogDbg( "%u bytes allocated\n", size * 5 );

free( a );
free( b );
free( c );
free( d );
free( e );

return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
LogInfo( "Press enter, please ...\n" );
getchar();
if( foo( 100 ) )
{
LogErr( "Can't call foo with parameter 100\n" );
return -1;
}

LogDbg( "First call. Parameter 100\n" );

if( foo( 200 ) )
{
LogErr( "Can't call foo with parameter 100\n" );
return -1;
}

LogDbg( "Second call. Parameter 200\n" );

if( foo( 500 ) )
{
LogErr( "Can't call foo with parameter 100\n" );
return -1;
}

LogDbg( "Third call. Parameter 500\n" );

LogInfo( "\nPress enter, please ..\n" );
getchar();

return 0;
}

С помощью Dataflow вызываем функцию foo( 10 ).

faulttest_sub_1000( 10 )

Код функции покрыт. Получены следующие цифры по покрытию.

На картинке ниже желтым цветом показаны покрытые участки кода.

Белым цветом показаны блоки, которые вызываются только тогда, когда выделение памяти завершается неудачей. В других ситуациях код исполнен не будет. Выполнить эти участки кода поможет версия maiway для бинарного кода. Обернем вызов макросом, который будет вызывать функцию пока не будут покрыты все ветки, обрабатывающие сбои.

CHECK_WITH_FAULT_INJECT( !faulttest_sub_1000( 10 ) );

Получаем незначительное, но очень важное увеличение покрытия.

Непокрытые прежде блоки окрасились желтым.

Цель достигнута.

В приведенной выше программе неправильно реализована обработка ошибок. Если в определенный момент память  не выделилась, то предыдущие участки памяти не освобождаются. Это приводит к утечке памяти. Maiway умеет выявлять такие ошибки. После каждой итерации внедрения ошибки он проверят освобождена ли память. Если имеется не освобожденный участок, то выводится информация о нем.

Press enter, please …

Dataflow:FaultFuzzee, (-,22) foo(): 100 bytes allocated
Dataflow:FaultFuzzee, (-,31) foo(): 200 bytes allocated
Dataflow:FaultFuzzee, (-,40) foo(): 300 bytes allocated
Dataflow:FaultFuzzee, (-,49) foo(): 400 bytes allocated
Dataflow:FaultFuzzee, (-,58) foo(): 500 bytes allocated
Dataflow:FaultFuzzee, (-,24) DllMain(): Need start faulttest_sub_1000
Dataflow:MaiwayDataflow, (-,73) SetupFaultInjectors(): functionAddress: 10001290, processID: 0xbc8, functionName: malloc, moduleName: C:\Work\svn\build\Release\bin\test\FaultTest.exe
Memory allocation. 10 bytes in no file at 1379074(0x150b02)
Dataflow:FaultFuzzee, (-,22) foo(): 10 bytes allocated
Memory allocation. 20 bytes in no file at 1379138(0x150b42)
Dataflow:FaultFuzzee, (-,31) foo(): 20 bytes allocated
Memory allocation. 30 bytes in no file at 1379234(0x150ba2)
Dataflow:FaultFuzzee, (-,40) foo(): 30 bytes allocated
Memory allocation. 40 bytes in no file at 1379330(0x150c02)
Dataflow:FaultFuzzee, (-,49) foo(): 40 bytes allocated
Memory allocation. 50 bytes in no file at 1379426(0x150c62)
Dataflow:FaultFuzzee, (-,58) foo(): 50 bytes allocated
g_mode 1
g_currentIteration 0
g_totalCounter 5
g_currentAllocation 0
Memory allocation. 10 bytes in no file at 1379074(0x150b02)
Make fault inject in
File: no file, line 1379074
Dataflow:FaultFuzzee, (-,18) foo(): Error! error allocating a
g_mode 1
g_currentIteration 1
g_totalCounter 5
g_currentAllocation 1
Memory allocation. 10 bytes in no file at 1379074(0x150b02)
Dataflow:FaultFuzzee, (-,22) foo(): 10 bytes allocated
Memory allocation. 20 bytes in no file at 1379138(0x150b42)
Make fault inject in
File: no file, line 1379138
Dataflow:FaultFuzzee, (-,27) foo(): Error! error allocating b
Memory chunk:
begin from 003F2CD0 size 10
allocated at line 1379074 in file:
no file
Dataflow:FaultFuzzee, (-,33) DllMain(): Fault! Assertion failed: !FreeAllMemory()
g_mode 1
g_currentIteration 2
g_totalCounter 5
g_currentAllocation 2
Memory allocation. 10 bytes in no file at 1379074(0x150b02)
Dataflow:FaultFuzzee, (-,22) foo(): 10 bytes allocated
Memory allocation. 20 bytes in no file at 1379138(0x150b42)
Dataflow:FaultFuzzee, (-,31) foo(): 20 bytes allocated
Memory allocation. 30 bytes in no file at 1379234(0x150ba2)
Make fault inject in
File: no file, line 1379234
Dataflow:FaultFuzzee, (-,36) foo(): Error! error allocating c
Memory chunk:
begin from 003F42D8 size 20
allocated at line 1379138 in file:
no file
Memory chunk:
begin from 003F2CD0 size 10
allocated at line 1379074 in file:
no file
Dataflow:FaultFuzzee, (-,33) DllMain(): Fault! Assertion failed: !FreeAllMemory()
g_mode 1
g_currentIteration 3
g_totalCounter 5
g_currentAllocation 3
Memory allocation. 10 bytes in no file at 1379074(0x150b02)
Dataflow:FaultFuzzee, (-,22) foo(): 10 bytes allocated
Memory allocation. 20 bytes in no file at 1379138(0x150b42)
Dataflow:FaultFuzzee, (-,31) foo(): 20 bytes allocated
Memory allocation. 30 bytes in no file at 1379234(0x150ba2)
Dataflow:FaultFuzzee, (-,40) foo(): 30 bytes allocated
Memory allocation. 40 bytes in no file at 1379330(0x150c02)
Make fault inject in
File: no file, line 1379330
Dataflow:FaultFuzzee, (-,45) foo(): Error! error allocating d
Memory chunk:
begin from 003F4430 size 30
allocated at line 1379234 in file:
no file
Memory chunk:
begin from 003F42D8 size 20
allocated at line 1379138 in file:
no file
Memory chunk:
begin from 003F2CD0 size 10
allocated at line 1379074 in file:
no file
Dataflow:FaultFuzzee, (-,33) DllMain(): Fault! Assertion failed: !FreeAllMemory()
g_mode 1
g_currentIteration 4
g_totalCounter 5
g_currentAllocation 4
Memory allocation. 10 bytes in no file at 1379074(0x150b02)
Dataflow:FaultFuzzee, (-,22) foo(): 10 bytes allocated
Memory allocation. 20 bytes in no file at 1379138(0x150b42)
Dataflow:FaultFuzzee, (-,31) foo(): 20 bytes allocated
Memory allocation. 30 bytes in no file at 1379234(0x150ba2)
Dataflow:FaultFuzzee, (-,40) foo(): 30 bytes allocated
Memory allocation. 40 bytes in no file at 1379330(0x150c02)
Dataflow:FaultFuzzee, (-,49) foo(): 40 bytes allocated
Memory allocation. 50 bytes in no file at 1379426(0x150c62)
Make fault inject in
File: no file, line 1379426
Dataflow:FaultFuzzee, (-,54) foo(): Error! error allocating e
Memory chunk:
begin from 003F4590 size 40
allocated at line 1379330 in file:
no file
Memory chunk:
begin from 003F4430 size 30
allocated at line 1379234 in file:
no file
Memory chunk:
begin from 003F42D8 size 20
allocated at line 1379138 in file:
no file
Memory chunk:
begin from 003F2CD0 size 10
allocated at line 1379074 in file:
no file
Dataflow:FaultFuzzee, (-,33) DllMain(): Fault! Assertion failed: !FreeAllMemory()
g_mode 1
g_currentIteration 5
g_totalCounter 5
g_currentAllocation 5
Dataflow:FaultFuzzee, (-,35) DllMain(): Done
Dataflow:FaultFuzzee, (-,36) DllMain(): faulttest_sub_1000 called
Dataflow:MaiwayDataflow, (-,115) CleanupFaultInjectors(): functionAddress: 78AB0233, processID: 0xbc8, functionName: malloc, moduleName: C:\Work\svn\build\Release\bin\test\FaultTest.exe