Use Local Classes for Proper Cleanup in Exception-enabled Apps

Use Local Classes for Proper Cleanup in Exception-enabled Apps

Exceptions enable you to detect and handle anomalous runtime conditions promptly. However, they also complicate the design of your program as they increase the number of possible execution paths. In most cases, implementing the “resource acquisition is initialization” idiom guarantees that data isn’t destroyed and that resources are always released. However, this idiom isn’t always an ideal solution. The following sections present a more refined technique for ensuring proper cleanup in an exception-enabled environment.

How do you ensure that critical cleanup code always executes regardless of whether an exception has occurred?

Use a local class’s destructor to ensure the unconditional execution of cleanup code.

Demonstrating the Problem
An exception-enabled program has at least two execution paths. Consider:

void func(){ try  {  if (something_bad) //#a1    throw X();  // #b1 otherwise continue normally, then jump to #b2 } catch (X& x)//#a2 {  exit(1); }//#b2 we get here only if no exception was thrown}

When an exception occurs, control is transferred to the catch block marked #a2, after which the exit() call terminates the program. If however no exception occurs, the section marked #b1 executes and then control is transferred to the section #b2. Thus, when certain sections of func() execute, others don’t, and vice versa. In real world code, there are more execution paths because the program may throw various types of exceptions from different locations. Additionally, there may be multiple catch blocks. The challenge is to ensure that certain operations (logging, notifying the sysadmin that the process is about to die, etc.) always take place, regardless of whether an exception has occurred.

If you’re familiar with Java you will recognize that this is exactly what the finally keyword does. However, since C++ doesn’t have a similar keyword, you need another mechanism to ensure the unconditional execution of cleanup code.

Introducing Local Classes
C++ has a little known feature called local classes. A local class looks like an ordinary class except that it’s declared inside a function (normally, you declare classes in a namespace scope). For example:

void f(){ class A{ public:   A() {cout<<"I'm a local class!"<

A local class has no linkage. Therefore, you can't refer to it from an outer scope or from other functions, blocks, and translation units:

void f(){ class C {}; C c; //OK, in the scope of C's declaration C * p = new C; // also OK}int main(){ f(); C another_c; //error: undefined symbol 'C'}

Local classes are instrumental in solving this problem.

A Synergic Combination
C++ ensures that destructors of auto objects execute when an exception occurs as part of the stack unwinding process. Take advantage of this behavior and move unconditional cleanup code into a destructor. This technique is hardly new, of course. However, the properties of local classes enable you to refine it.

You want to add cleanup code to func() which will execute unconditionally. More importantly, you want this code to execute upon leaving func(), but not sooner. To achieve these goals, you will combine the deterministic execution of auto objects' destructors and the properties of local classes. This synergic combination imitates the functionality of Java's finally.

First, define a local class before the first throw statement and add cleanup code to its destructor. This class should have only one member: a public destructor. Then, instantiate an object of this class immediately after the class's definition:

void func(){ try  {   struct Finally  {   ~Finally() { cleanup(); SMS_sysadmin("terminating");}  } finalizer;   if (something_bad) //#a1    throw X(); //#b1 otherwise continue normally } catch (X& x) // #a2 {   exit(1); }//#b2 we get here only if no exception was thrown}

That's all! When func() exits, either normally or due to an exception, the destructor of finalizer will execute unconditionally and perform the necessarily process termination procedures.

The Grand Finale
You might argue that there's no need to use a local class to perform this feat: any auto object's destructor will do. However, because Finally is a local class, other programmers won't be able to create instances thereof elsewhere. More importantly, local classes have no linkage. Therefore, you can define classes with the same name in different scopes without risking name clashes:

void func(){ class Local{} loc;//#1}int main(){ class Local {} loc;//#2 OK, doesn't clash with #1}

This property enables you to use a uniform name for such "disposable classes" in all your projects. As a security bonus, neither the local class' name nor the names of its member functions will be stored in an executable/DLL file. Consequently, crackers attempting to decompile your binaries will have a hard time indeed.

Share the Post:
XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes

ransomware cyber attack

Why Is Ransomware Such a Major Threat?

One of the most significant cyber threats faced by modern organizations is a ransomware attack. Ransomware attacks have grown in both sophistication and frequency over the past few years, forcing

data dictionary

Tools You Need to Make a Data Dictionary

Data dictionaries are crucial for organizations of all sizes that deal with large amounts of data. they are centralized repositories of all the data in organizations, including metadata such as