2017-01-06 12 views
1

Я пытаюсь возиться с некоторым кодом библиотеки, написанным на C++. Довольно сложное приложение находится поверх библиотеки. Чтобы возиться с кодом, мне часто нужно понимать, как функция библиотеки используется во всей кодовой базе, и убедитесь, что я не нарушаю ни один из последующих клиентов.Создание дерева всех возможных стеков вызовов

Предположим, что foo() экспортируется из dll моей библиотеки. В клиентском коде bar() звонки foo() и baz() звонки bar(). Мне нужно убедиться, что bar и baz оба работают после моих изменений. В моем случае стек вызовов на самом деле довольно глубокий и нелегкий для ручной трассировки, поскольку нет одного стека вызовов, существует множество способов, которыми моя библиотечная функция может располагаться в верхней части стека вызовов.

С помощью Visual Studio или g ++ или clang существует способ генерации дерева, так что моя библиотечная функция находится в корне, а ветви - всевозможные способы, которыми моя функция может располагаться в верхней части стек вызовов? Я имею в виду, что такая функция уже существует в одной из популярных инструментальных цепей? Если нет, знаете ли вы какой-либо другой способ создания такого дерева?

ответ

1

Я не думаю, что у кого-либо из компиляторов есть варианты для создания этой информации.

В общем случае, есть много сопутствующих факторов, которые делают это очень трудно:

  • Если есть рекурсии в коде, то дерево вы хотите на самом деле график/сети с циклами.

  • Виртуальные методы, указатели на функции и указатели функций членов, вероятно, делают это эквивалентом проблемы с остановкой. Если у вас есть два конкретных класса A и B, которые имеют общий базовый класс, который предлагает виртуальный метод foo(), вам нужно будет сделать исчерпывающий анализ, чтобы определить, следует ли учитывать конкретный вызов foo() с помощью указателя или ссылки на базовый класс в качестве звонка на A::foo() или B::foo() или обоими. То же самое для указателей функций различных ароматов.

  • Если вы полагаетесь на систему или другие сторонние библиотеки, которые могут перезвонить в ваш код, вам лучше иметь источник для них. Например, программа Windows GUI обычно имеет оконные процедуры, вызываемые из системного кода, возможно, в ответ на вызов вашего кода в систему. Поскольку у вас нет источников Windows, вам придется предположить, что любые вызовы могут быть вызваны в любое время, и, таким образом, ваше «дерево» будет иметь много корней.

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