Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile time warning about memset on non plain old data

I'm working on a large code base, converting some old C modules into C++. I want to add a C++ object to a struct, but some users of this struct memset it, which is unfortunate for the object that I want to put in the struct.

How can I detect at compile time that this is being done, so that I can eliminate all use of memset on such a struct that is no longer POD?

like image 800
Henrik Avatar asked Jul 30 '13 11:07

Henrik


2 Answers

I'm not sure if compiler will help you there by directly providing some compilation flags. If it does, good for you. Use that. End of story.

If it doesn't, then maybe this will help you. Since you're converting your code from C to C++, that means all the usage of memset is without std:: namespace. So take advantage of this fact and #define memset as:

 #define memset memset_if_pod_else_error() 

Here memset_if_pod_else_error is a function written by you (i.e you have to implement it). You could make it template so as to deduce the type of argument and then detect whether the type is POD or not. If it is POD, then that is fine and call std::memset internally, else raise error.

Metafunctions like std::enable_if and std::is_pod will help you to implement this function.

Here is a minimal demo of this idea:

#include <iostream>
#include <type_traits>
#include <cstring>

auto ptr_memset =  std::memset; //store this a pointer

template<typename T>
using VoidPtr = typename std::enable_if<std::is_pod<T>::value, void*>::type;

#define memset memset_if_pod_else_error

template<typename T>
VoidPtr<T> memset_if_pod_else_error(T *data, int ch, size_t count) 
{
      return ptr_memset(data, ch, count);
}

struct pod {};
struct nonpod { nonpod() {} };

int main()
{
    pod p;
    nonpod np;

    memset(&p, 0, sizeof(p));

    memset(&np, 0, sizeof(np));  //this is error!
}

The second call to memset generates this error:

error: no matching function for call to 'memset_if_pod_else_error'
memset(&np, 0, sizeof(np));
^~~~~~

Online Demo.

Hope that helps.

like image 187
Nawaz Avatar answered Sep 21 '22 00:09

Nawaz


How about this:

auto orig_memset =  std::memset;
#define memset checked_memset

template <class T>
void* checked_memset(T* ptr, int value, size_t num) {
  static_assert(std::is_pod<T>::value, "memset on non-POD");
  return original_memset(data, value, num);
}

Or, if you're interested only in finding violations for your particular struct:

auto original_memset =  std::memset;
#define memset checked_memset

template <class T>
void* checked_memset(T* ptr, int value, size_t num) {
  static_assert(!std::is_same<T, YOUR_STRUCT_HERE>::value, "memset used on YOUR_STRUCT_HERE");
  return original_memset(data, value, num);
}
like image 37
JoeG Avatar answered Sep 20 '22 00:09

JoeG