Несоответствия CaptureStackBackTrace с использованием FramesToSkip - PullRequest
0 голосов
/ 25 апреля 2019

В Windows вы можете захватить трассировку стека, используя CaptureStackBackTrace как

void* frames[USHRT_MAX];
USHORT framesCount = CaptureStackBackTrace(0, USHRT_MAX, frames, NULL);

Однако захват его меньшими порциями в цикле, чтобы избежать выделения буфера USHRT_MAX, непредоставить тот же результат.

Этот код

#include <Windows.h>
#include <assert.h>
#include <stdio.h>

__declspec(noinline) void CheckStack(void)
{
    printf("Checking stack...\n");

    void* entireStack[USHRT_MAX];
    USHORT frameCount = CaptureStackBackTrace(0, USHRT_MAX, entireStack, NULL);

    printf("Stack size is: %u\n", frameCount);

    ULONG frameOffset = 1;

    for (;;)
    {
        void* chunk[64];
        USHORT framesFound = CaptureStackBackTrace(frameOffset, 64, chunk, NULL);
        if (framesFound)
        {
            if (memcmp(entireStack + frameOffset, chunk, sizeof(chunk)) != 0)
            {
                printf("Incorrect content\n");
            }

            frameOffset += (ULONG)framesFound; 
        }
        else
        {
            break;
        }
    }

    if (frameCount != frameOffset)
    {
        printf("Incorrect count (%u != %u)\n", frameCount, frameOffset);
    }

    printf("Done\n");
}

__declspec(noinline) void Test(int i)
{
    if (i != 500)
        Test(++i);
    else
        CheckStack();
}

int main()
{
    Test(0);
}

производит следующий вывод

Checking stack...
Stack size is: 507
Incorrect count (507 != 257)
Done

при построении как cl /Od main.c /link /OUT:main.exe.

Использую ли я FramesToSkipпараметр неверен или почему счет не равен?

1 Ответ

0 голосов
/ 26 апреля 2019

Если вы используете Windows Server 2003 и Windows XP,

Сумма параметров FramesToSkip и FramesToCapture должна быть менее 63.

Это в документе.

Иначе, как говорит @RbMm, в исходном коде API есть следующая логика:

if(FramesToSkip>0xfe)
{
    return 0;  //There are too many stack structures skipped, returning directly to 0.
}

Однако это не упоминается для msdn как в CaptureStackBackTrace , так и в RtlCaptureStackBackTrace . Я не собираюсь публиковать здесь исходный код, но докажу это при отладке:

1.Создайте образец:

#include <Windows.h>
#include <assert.h>
#include <stdio.h>

__declspec(noinline) void CheckStack(void)
{
    void* entireStack[USHRT_MAX];
    USHORT frameCount = CaptureStackBackTrace(255, USHRT_MAX, entireStack, NULL);
}

__declspec(noinline) void Test(int i)
{
    if (i != 500)
        Test(++i);
    else
        CheckStack();
}

int main()
{
    Test(0);
}

2. Шаг в CaptureStackBackTrace в разборке: enter image description here Вы можете видеть, что dword ptr[ebp+8] (первый параметр CaptureStackBackTrace помещается в стек) будет сравниваться с 0feh (254). Если true, верните 0.

...