8

It's easy to make noncopyable class with private copy construcor and assignment operator, boost::noncopyable or the C++11 delete keyword:

class MyClass {
private:
    int i;
public:
    MyClass(const MyClass& src) = delete;
    MyClass& operator=(const MyClass& rhs) = delete;    
    int getI() {
        return i;
    }
    MyClass(int _i) : i(_i){}
};

int main() {
    MyClass a(1), b(2);
    a = b; // COMPILATION ERROR
}

However this doesn't prevent obiect from being deep copied as a pack of bytes:

int main() {
    MyClass a(1), b(2);   
    std::memcpy(&a, &b, sizeof(MyClass));
    std::cout << a.getI() << std::endl; // 2
}

Even if try to prevent it by declaring operator& private, it's still possible to make copy using implementations of address-of idiom:

int main() {
    MyClass a(1), b(2);   
    std::memcpy(std::addressof(a), std::addressof(b), sizeof(MyClass));
    std::cout << a.getI() << std::endl; // 2
}

Is there any method to completely prevent an instance from being copied byte per byte?

Nykakin
  • 8,657
  • 2
  • 29
  • 42
  • 5
    I seriously doubt it's possible. – Jerry Coffin Apr 20 '15 at 21:55
  • 7
    The memcpy knows nothing about C++ objects and doesn't care. It is a bull in a china shop -- you can't stop it from doing what it does. There comes a time when you have to trust that the programmer(s) using your classes know what they're doing. – PaulMcKenzie Apr 20 '15 at 21:55
  • 1
    The question is: why do you want to prevent it? – MikeMB Apr 20 '15 at 22:06
  • Is this done from the same program or are you afraid of ring-0 attacks? You could use built in encryption capabilities if your CPU supports them – Leeor Apr 20 '15 at 22:12
  • As noted in [N4460](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4460.html), if you declare the copy ctor/`operator=` private and do not define them (i.e., the C++03 approach), then the class would not be trivially copyable. – T.C. Apr 20 '15 at 22:46
  • The usual way to "hide" objects like this is to have a "C" API, implemented in a DLL, where the API functions deal with merely a pointer to the object. – Dan Korn Apr 20 '15 at 23:15
  • This brings to mind the old saying about Murphy vs. Machiavelli. – T.C. Apr 20 '15 at 23:20
  • @DanKorn: If you want to "hide" the object, return a key to an internal global data structure (could be as simple as an array index), not a pointer. (For bonus points, the caller is prevented by the memory protection unit from accessing the "internal global data structure" even if it figured out what the key meant.) – Ben Voigt Apr 21 '15 at 00:11
  • If you hate memcpy, just find a way to prevent using it. :) – douyw Apr 21 '15 at 01:29
  • @Ben Voigt: That's another way it could be done. But my statement that the "usual" way to "hide" objects like this is to have an API which deals with opaque pointers is based on many existing libraries, such as the Adobe Acrobat SDK, the SpiderMonkey API for JavaScript, Python, and many others. It's a very common practice. – Dan Korn Apr 21 '15 at 16:06
  • @DanKorn: And returning an array index which is not a pointer is even more prevalent, especially when security boundaries are concerned: (Posix file descriptors, Win32 `HANDLE`, Win32 `HWND`, Win32 `HGLOBAL`, .NET `GCHandle`). The pointers are opaque for convenience (the client doesn't have to recompile if the internal data structure changes), not for information hiding. – Ben Voigt Apr 21 '15 at 16:12
  • @Ben Voigt: According to the header winnt.h in VS2005, HANDLE is indeed a typedef for a void pointer. Your other assertions, that "returning an array index which is not a pointer is even more prevalent," and that the Windows types are "opaque for convenience" are also unsubtantiated, though I don't have any evidence to directly refute those statements. – Dan Korn Apr 21 '15 at 16:45
  • https://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx HANDLE: A handle to an object. This type is declared in WinNT.h as follows: `typedef PVOID HANDLE;` – Dan Korn Apr 21 '15 at 16:47
  • @DanKorn: It is a pointer type, but it is not a pointer (memory address). `void*` is ideal for an opaque type because the language rules prohibit arithmetic. – Ben Voigt Apr 21 '15 at 17:30
  • Sorry Ben, but your assertion is incorrect. When I look at the value of an HWND in a Windows program, it usually has a value something like 0x001537b6, which is right around the range of other memory address pointers in the program. That's pretty good evidence that, at least for an HWND, yes, it actually is a pointer to a memory address. I'm not sure what evidence you have to the contrary. At any rate, I know for a fact that opaque pointer values in the PDF Library and Acrobat SDK, such as PDDoc, are indeed pointers to objects in memory, as are types such as JSContext in SpiderMonkey. – Dan Korn Apr 21 '15 at 20:50
  • The same is true of a HANDLE returned from a function such as FindFirstFile(): It's in the same range as pointers to other actual objects in my program. I suppose it could be a pointer to something simple like an array index, but it's pretty clearly a pointer. – Dan Korn Apr 21 '15 at 20:54
  • Oh, and by the way, language rules prohibit arithmetic on a pointer to a forward-declared type as well. That's not a feature that's unique to void pointers. – Dan Korn Apr 21 '15 at 20:59

2 Answers2

10

Can I prevent object from being copied by std::memcpy?

The simple answer is "No".

R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

This is not bullet-proof but you can implement your own memcpy_safe that behaves similarly but accepts something else than void*. Then you create an include file that contains

#define memcpy memcpy_old
#include <cstring>
#undef memcpy
#define memcpy memcpy_safe

And tell people to use this include file instead. What it does is to hide the declaration of memcpy, and replaces all calls to memcpy with calls to memcpy_safe. The new function needs to be implemented in its own translation unit, so you can call the old memcpy.

user877329
  • 6,717
  • 8
  • 46
  • 88