Last active
December 22, 2023 12:43
-
-
Save Blaisorblade/cf27cdb540f6d14963f8e875cd3237f5 to your computer and use it in GitHub Desktop.
C++ compilation does not preserve abstraction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct A { | |
int x; // | |
void print() const; | |
}; | |
void break_encapsulation(A& a) { | |
a.print(); | |
a.x = 1; | |
a.print(); | |
} | |
int main() { | |
A a; | |
break_encapsulation(a); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CXX := g++ | |
CXXFLAGS := -std=c++11 | |
prog: evil_client.o module.o | |
$(CXX) $(CXXFLAGS) -o $@ $^ | |
# Redundant, but included for completeness | |
%.o: %.cpp | |
$(CXX) $(CXXFLAGS) -c -o $@ $^ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
using namespace std; | |
class A { | |
int x{0}; // | |
public: | |
int getX() const { return x; } | |
void print() const; | |
}; | |
void break_encapsulation(A& a); | |
void A::print() const { | |
printf("this.x: %d\n", getX()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This example shows (one reason that)
private:
in C++ does not protect when linking against arbitrary external code — so any privacy guarantees given byprivate
are not preserved by compilation.Of course, this code is undefined behavior (because it has conflicting definitions of
A
, which violates the one-definition rule), but typical implementations will indeed break encapsulation, and the UB can be avoided by movingbreak_encapsulation
to C or assembly, or replacinga.x = 1;
with*reinterpret_cast<int&>(&a) = 1;
and sharing the definition ofA
.