Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Method Call Interception


Method call interception means executing some code before and after the body of a function or a method is executed. During development, there are many situations where method call interception can come in handy. For instance, you may want to:

  • Trace every method call to follow the flow of your program in a certain scenario in real time.
  • Log every method invocation for later study or audit call patterns in an application.
  • Profile how much time is spent in which method.
  • Ensure that there are no resource leaks on method exit.

Method call interception is in the realm of Aspect-Oriented Programming (AOP), which deals with issues that can't be encapsulated in an object-oriented class or set of classes because these issues cut across the entire software (cross-cutting concerns). Programming these aspects of the program is difficult because they are scattered all over the code. AOP deals with this problem by identifying that you can't properly manage aspects using conventional object-oriented techniques, and then goes on to define language extensions that help in programming aspects (see http://www.aosd.org/ for more information).

In this article, I discuss several ways to perform method call interception, introduce the Method Call Interceptor (MCI) mechanism that enables source-level interception, discuss MCI automation and the overhead incurred by MCI, and finally present the Poor Man's Profiler (PMP), a simple profiler that demonstrates the use of MCI in a real-world scenario.

Intercept Method Calls

There are various ways to intercept method calls, depending on your execution environment, source code access, and expertise. COM+, for example, provides a hooking mechanism that can be used for this purpose. DLL calls can be easily intercepted because the address of all functions is kept in an Import Address Table (IAT), which can easily be modified to call your interception code instead. Another technique is to inject interception code into object files before linking. However, in this article I concentrate on source-level interception. This means modifying the source of a program you typically develop to do the interception.

The naive approach (which works fine in many cases) is just to write some code at the beginning and end of each method body; see Example 1. The problem with this approach is that it is tedious, labor intensive, nothing can enforce it, and across a multideveloper project, inconsistent formats are likely to appear. You are also likely to forget the finish statement, which leads to functions that appear to never exit (at least in the trace output). Yet another problem with this approach is that you often need different types of interception at different times. For example, when trying to locate a difficult resource leak, you may want to track resources on entering/leaving a method; while hunting a stubborn logical bug, you may want a call tree tracing; and while tuning performance, you may want to know how long each method takes and how often it is called. Putting all this code in every method or changing the interception code every now and then is inhuman, if not inhumane.

Example 1: Naive approach.

void Foo(int x, int y)
{   
    cout << endl << "Foo(int x, int y) - start";
    ...
    cout << endl << "Foo(int x, int y) - finish";
}

A somewhat better solution is defining an automatic object that does the "start" thing in its constructor and the "finish" thing in its destructor; see Example 2. The automatic object makes sure you won't forget that closing finish line and keeps all the code in one place so you don't have to edit the code in every method separately. Still, you must pass the name of each method specifically, and if you want to add logging code or profiling, you must put AutoLog and AutoProfiler automatic objects in every method. Again, you have different interception needs in different methods and in different phases of the development process. Enter the Method Call Interceptor mechanism.

Example 2: Class AutoTrace.

class AutoTrace
{
public:
   AutoTrace(const string & s) : m_line(s)
    {
        cout << endl << m_line << " - start";
    }

    ~AutoTrace()
    {
        cout << endl << m_line << " - finish";
    }
private:
    string m_line;  
};

void Foo(int x, int y)
{
    AutoTrace("Foo(int x, int y)");
    ...
}

Method Call Interceptor: The Mechanism

Method Call Interceptor (MCI) is a mechanism that addresses the aforementioned problems. It consists of class Mci, an abstract class (IMciEvents), and a utility class (MethodAnalyzer). The basic idea is this: An instance of the Mci class is placed automatically at the beginning of each method. The constructor of Mci, which is called upon entering each method, collects some information regarding the current method using the MethodAnalyzer and notifies a preregistered events sink (an object that implements the IMciEvents interface).

The motivation behind this observer-style design is separation of concerns. The code that performs the interception (Mci) is totally independent and is actually unaware of the code that performs the actual tracing, logging, profiling, or what have you. This partitioning allows sophisticated implementations such as filtering and performing different actions for different methods without changing the generic method interception code or the method's code.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.