Оптимизация компилятора по параметрам неиспользуемой функции - PullRequest
1 голос
/ 17 марта 2019

У меня была странная проблема в течение пары дней с использованием Windows RPC.Теперь я нашел решение, но я хочу знать, как правильно предотвратить эту проблему.

Так что в принципе у меня возникла проблема с вызовом NdrClientCall2 функции.Как видно из документов, третий параметр этой функции - указатель на стек вызовов на стороне клиента.Я изменил midl.exe сгенерированный код C на свою собственную версию C ++, чтобы мой вызывающий абонент выглядел так:

void CppRpc::InternalCommand(int pSize, char buffer[1000000]) const
{
    RpcTryExcept
    {
        NdrClientCall2(PMIDL_STUB_DESC(&m_rpc_stup_description),
            PFORMAT_STRING(&MIDL_PROCFORMAT_STRING.Format[0]),
            reinterpret_cast<unsigned char *>(&pSize));
    }
    RpcExcept(1)
    {
        std::cerr << "Runtime reported exception " << RpcExceptionCode()
            << std::endl;
    }
    RpcEndExcept
}

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

Однако мне нужно, чтобы этот параметр был в стеке, чтобы NdrClientCall2 мог передавать его на сервер.Если я добавлю какое-либо использование для buffer, например, char dummy = buffer[0]; к функции buddy, тогда оно будет работать нормально.

Итак, мой вопрос здесь, как предотвратить оптимизацию в этом случае?Я использую visual studio 2017.

1 Ответ

2 голосов
/ 17 марта 2019

Я бы не рекомендовал делать это.Поскольку InternalCommand является вашей внутренней функцией, компилятор может изменить макет своих параметров.Принимая во внимание, что (как я понимаю) вам нужна конкретная компоновка, в которой есть переменная int, за которой следует буфер, зарезервированный для стека.

Кроме того, эта компоновка может измениться, если вы измените свои соглашения о вызовах функций (т.е. cdecl vs stdcall).

Я бы определил структуру (POD) с одним полем int, передал бы указатель на нее своей функции, тогда как фактическая структура, выделенная вызывающей стороной, имеет больший размер.

Примерно так:

struct StackFrame
{
    int pSize;
    char pStack[1000000]; // stack goes here
};

// ...

void CppRpc::InternalCommand(StackFrame* pStack) const
{
    RpcTryExcept
    {
        NdrClientCall2(PMIDL_STUB_DESC(&m_rpc_stup_description),
            PFORMAT_STRING(&MIDL_PROCFORMAT_STRING.Format[0]),
            reinterpret_cast<unsigned char *>(pStack));
    }
    RpcExcept(1)
    {
        std::cerr << "Runtime reported exception " << RpcExceptionCode()
            << std::endl;
    }
    RpcEndExcept
}
...