c++dlldllexport

C++ DLL - Prevent Access To Items After Compilation?


I really don't like the idea of putting lots of effort into carefully developing & designing a C++ library only for it to be the case that the only thing stopping those who link the DLL from accessing data they shouldn't be accessing even accidentally being the hand-written access modifiers provided in the .h files that go along with the DLL.

What solutions can I consider for recreating the concept of an access modifier after the DLL has been compiled that can't be changed as simply as re-writing access modifiers in the .h files packed-in with distribution versions of the DLL?

A solution I've considered but don't fully understand is having __declspec(dllexport) specified only on public API methods, classes, etc. such that rewriting some item in an .h file to become public when it is supposed to be private won't matter since the LIB file won't be populated with that item and therefore it cannot be used by those who link the DLL. I don't fully understand this solution like I said and therefore cannot say with confidence if this will be an answer to my question (seems to be just a simpler version of a .def file which is a file that was explained to me yesterday) but I just wanted to bring up my awareness of it, if you think it'd work just let me know before I get invested into bloating an existing library with it only to find out it doesn't work at all (I suppose I should just set up an MRE but now I'm just rambling).


Solution

  • As mentioned by you and others in the comments, one of the main motivations behind the PIMPL pattern is exactly to solve the problem you describe.

    A simplified implementation might look like this :

    // 'Foo.h'
    // Forward declare FooImpl here, but no definition in public header !
    // What it is or does is not accessible to the user of this header.
    class FooImpl; 
    
    class Foo
    {
    public:
      Foo();
      ~Foo();
    
      // bar() works some magic that we don't want to leak to the outside.
      int bar();
    
    private:
      FooImpl* pImpl;
    
    };
    
    
    // 'Foo.cpp'
    #include Foo.h
    
    // Define FooImpl here or in a separate and private (not distributed) header,
    // so that it won't be visible to consumers of this lib.
    class FooImpl
    {
    public:
      void FooImpl(){};
    
      int bar()
      {     
          return someMagic;
      };
    
    private:
      int someMagic{42};
    
    };
    
    void Foo::Foo()
    {
      pImpl = new FooImpl{};
    }
    
    void Foo::~Foo()
    {
      delete pImpl;
    }
    
    int Foo::bar()
    {
      return pImpl->bar();
    }
    
    

    In essence, only the external interface of the class Foo remains visible in its header, the functions and definitions the consumer needs to actually use the class. All implementation details (including private functions and member variables) are hidden under a second layer, which is the FooImpl class.

    Note that while this will hide implementation details for users of your library, it is of course not a security measure against de-compilation or other such hacker tools in any sense.