Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Using a Good Parasite Class to Design a Self-Clearing Memory Buffer : Page 2

Your C++ application doesn't have to allocate a new chunk of memory on every loop iteration. Learn how to implement a single raw memory buffer that knows how to clear itself securely.




Full Text Search: The Key to Better Natural Language Queries for NoSQL in Node.js

Date: 1/31/2018 @ 2 p.m. ET

memset() Blues

Without STL containers getting in your way, the main processing loop might look like a good 1970s C textbook:

char sms_buffer[161]={0}; for(;;) //main processing loop { read_data_from_client(sms_buffer); process_message(sms_buffer); memset(sms_buffer, 0, 161); //clear all bytes }

Calling memset() directly in C++ code is a faux pas because passing the size of the buffer on every memset()call is a security hazard. Ideally, you want the buffer to clear itself.

Enter the Good Parasite class!

A Good Parasite

A proper solution to the self-clearing buffer requires an interface with the dual attributes of a low-level char array and the qualities of a high-level C++ class. Why use a class instead of a function? Because a class's constructor is invoked automatically, and that constructor is where the buffer clearing will take place.

How will that class keep track of the buffer's size and address? Simple: both the class and the buffer live at the same address! So you monitor the buffer's size by bundling the size into the class's type—that is, you use a template. Bundling the size into the specialization has another advantage: the class will not contain any data members at all. This is crucial for your design.

First, consider how to bundle the buffer's size into the class's type. This Solution uses a template non-type parameter:

#include <new> //for overriding new and placement new #include <cstring> //for memset template <int N> class Zeroer//template arguments are int { private: void * operator new(unsigned int)=delete; Zeroer(const Zeroer&)=delete; Zeroer& operator=(const Zeroer&)=delete; ~Zeroer()=delete; //.. };

Because clients are not allowed to create Zeroer objects directly or to copy them, the assignment operator, copy constructor, destructor, and overridden operator new are declared as private deletedfunctions.

You can instantiate a Zeroer object only by using placement new. This will ensure that a Zeroer object is constructed on the buffer's address. Notice that you need to override the global placement new(as shown in the Zeroer definition below).

Finally, look at the constructor. Every time you create a Zeroer object, its constructor automatically clears the buffer. Here's the complete definition of Zeroer:

template <int N> class Zeroer { private: //disabled operations void * operator new(unsigned int)=delete; Zeroer(const Zeroer&)=delete; Zeroer& operator=(const Zeroer&)=delete; ~Zeroer()=delete; public: Zeroer(){ memset(this, 0, N); } //clear the buffer void* operator new(unsigned int n, char* p) {return p; } };

Here is Zeroer in action:

int main() { char buff[512]; for(;;) { new (buff) Zeroer<512>; //Zeroer ctor clears buff strcpy(buff,"hello"); //fill the buffer with data new (buff) Zeroer<512>; //clear the buffer again strcpy(buff,"world"); //fill the buffer again } }

Zeroer objects are never destroyed because they have nothing to destroy. They don't own the buffer; they merely "iron" it after every use. Every time you want to clear buff, you construct a new instance of Zeroer<512> on top of buff using placement new. In real world code, constants and typedefs will eliminate the use of hard-coded numbers:

const int PAGE_SIZE=512; typedef Zeroer<PAGE_SIZE> ZP; int main() { Zeroer<52> z; //error, destructor is inaccessible new Zeroer<1024> ; // error, new is inaccessible //handle two different buffers at once char buff[PAGE_SIZE]; char sms_buff[161]; //process and recycle new (sms_buff) Zeroer<161>; //clear sms_buffer new (buff) ZP; //clear buff strcpy(buff,"hello"); new (buff) ZP; //clear buff again strcpy(sms_buffer,"call me"); new (sms_buffer) Zeroer<161>; //clear sms_buffer again }

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date