2

If I've a class like this,

class Sample
{
private:
      int X;
};

Then we cannot access X from outside, so this is illegal,

    Sample s;
    s.X = 10; // error - private access

But we can make it accessible without editing the class! All we need to do is this,

#define private public  //note this define!

class Sample
{
private:
      int X;
};

//outside code
Sample s;
s.X = 10; //no error!

Working code at ideone : http://www.ideone.com/FaGpZ

That means, we can change the access-specifiers by defining such macros just before the class definition, or before #include <headerfile.h>,

#define public private //make public private
//or
#define protected private //make protected private
//or
#define so on

Isn't it a problem with C++ (Macros/access-specifiers/whatever)?

Anyway, the point of this topic is:

Using macros, we can easily violate encapsulation. Access-specifiers are not foolproof! Am I right?

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 2
    `#define TRUE FALSE` - you can do much more harm with silly defines – Mchl Dec 26 '10 at 09:17
  • 3
    `*(int*)&s = 10; //no error!` – Hans Passant Dec 26 '10 at 09:28
  • 1
    Your have forgotten the `reinterpret_cast`, unions which also allow to break the encapsulation. C++ is not foolproof, it give you means to express your ides in the code, but it will not forbid you to shoot in your leg, it can only advise that this is not good. – Begemoth Dec 26 '10 at 09:31
  • @Hans Passant and @Begemoth : that's good. I liked that. :-) – Nawaz Dec 26 '10 at 09:36
  • 2
    Access specifiers are not security constraints. Who says your code works anyway. The compiler may change (off the top of my head without looking at the standard) things like the alignment characteristics of the members between public/private sections or many other attributes. – Martin York Dec 26 '10 at 11:26

5 Answers5

7

First of all, it's illegal to do that. private is a keyword, and you can't use it as an identifier in a macro; your program would be ill-formed.

But in any case, it's not a problem with macro's at all. It's with the fool who used them in a silly manner. :) (They're there to help you be safe, they're not there to help you be safe and block all access to them no matter what you try. C++ protects against Murphy, not Machiavelli.)

Note that you can access privates in a well-formed and well-defined manner, as demonstrated here. Again, this isn't a problem with the language, it's just not the job of the language to do more than necessary to keep prying hands out.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • you said *"private is a keyword, and you can't use it as an identifier in a macro; your program would be ill-formed"*... How can you say that? Does the Standard say so? – Nawaz Dec 26 '10 at 09:01
  • 3
    @Nawaz: See http://stackoverflow.com/questions/2726204/c-preprocessor-define-ing-a-keyword-is-it-standards-conforming. – GManNickG Dec 26 '10 at 09:04
  • From what I know, it's not making the program ill-formed. What it does is causing undefined behavior in C++0x. It's well defined in C++03; but not good style anyway and also undefined behavior once you include any standard headers. – Johannes Schaub - litb Dec 26 '10 at 14:10
  • @Johannes : Why is it well defined behaviour in C++03? The implementation is required to issue an error message, could this be the reason? `17.6.3.3/2 says "If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined` – Prasoon Saurav Dec 27 '10 at 03:30
  • @Prasoon I was partially wrong. "well-formed" is defined as "a C++ program constructed according to the syntax rules, diagnosable semantic rules, and the One Definition Rule" - if you redefine the keyword and abuse this to read private members, you break the one definition rule, having a ill-formed program :) But I don't think the mere act of redefining a keyword is ill-formed. And in no case it requires a diagnostic, I think. It's well-defined in C++03 because nothing says it's undefined if you just redefine the keyword without including standard headers :) – Johannes Schaub - litb Dec 27 '10 at 09:00
6

But we can make it accessible without editing the class! All we need to do is this,

Technically, all you've shown is that "we can turn a legal program into Undefined Behavior" without editing one specific class.

That's hardly news. You can also turn it into undefined behavior just by adding a line such as this to the end of main():

int i = 0;
i = ++i;

Access specifiers in C++ are not a security feature They do not safeguard against hacking attempts, and they do not safeguard against people willfully trying to introduce bugs into you code.

They simply allow the compiler to help you maintain certain class invariants. They allow the compiler to inform you if you accidentally try to access a private member as if it were public. All you've shown is that "if I specifically try to break my program, I can". That, hopefully, should be a surprise to absolutely no one.

As @Gman said, redefining keywords in the C++ language is undefined behavior. It may seem to work on your compiler, but it is no longer a well-defined C++ program, and the compiler could in principle do anything it likes.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • I think this post satisfies my query and also tells me the real purpose of access-specifiers. So I accept it as answer to my question. :-) – Nawaz Dec 26 '10 at 14:50
3

But we can make it accessible without editing the class

Not without editing the source file containing the class though.

Yes, macros let you shoot yourself in the foot. This is hardly news... but this is a particularly non-troubling example of it, as to "violate encapsulation" you have to force the class to either define the bone-headed macro itself, or include a header file which does so.

To put it another way: can you see this being an issue in real, responsible software development?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon : If I can access private members, then obviously it is an issue. Don't you think so? I can `#define private public` before `#include` and change the behavior of vector class (if there is not any other twist in the story). – Nawaz Dec 26 '10 at 09:11
  • @Nawaz: Yes you can, but no it's not an issue. Just don't do that. It would be a problem if I could inadvertently access privates, which isn't the case here. – GManNickG Dec 26 '10 at 09:13
  • @GMan : you didn't understand me. What is the purpose of access-specifiers if they cannot prevent me from accessing private members, for example? – Nawaz Dec 26 '10 at 09:16
  • 1
    @Nawaz: You can't really access private members though. You can access members which have the letters "private" in front of them, but they're not private because you've been bone-headed elsewhere. Again: can you see this being an issue in *real* software development? Who on earth would ever include a file which *did* redefine private to public? – Jon Skeet Dec 26 '10 at 09:17
  • @Jon Skeet : you said *"Who on earth would ever include a file which did redefine private to public?"*... not in the file itself, rather you can redefine it in *your* file just before including the headerfile. – Nawaz Dec 26 '10 at 09:31
  • @Nawaz: The purpose of access-specifiers is to allow the compiler to tell you when you screw up. And why on Earth would you redefine something like that before including a header? Unless you're actively trying to sabotage *yourself*, there's just not much point, is there? Most of us spend our times trying to write code that *works'. There are millions of ways in which I can break the code I just wrote. (hitting backspace a few times is a great way to do it). The reason my code still works is that I chose not to break it. Why would you choose differently? – jalf Dec 26 '10 at 09:59
  • @Nawaz no it isn't an issue... these accessibility rules by design guard from accidents, [not from evil programmers](http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html). – Johannes Schaub - litb Dec 26 '10 at 14:41
  • @Johannes : Yup. Now I understand the purpose of access-specifiers. Thanks for the comment.By the way, why did you delete your post from here http://stackoverflow.com/questions/4533758/absence-of-typeof-operator-in-c03 ?? That was good post. I really liked that. :-) – Nawaz Dec 26 '10 at 14:48
  • @jalf : I understand that now. thanks for the explanation. :-) – Nawaz Dec 26 '10 at 14:48
  • @Nawaz i found my implementation sucks and I need to rethink it so it's usable :) – Johannes Schaub - litb Dec 26 '10 at 15:00
  • @Johannes : ohh I see.. but there were some really good tricks that you were using.. Anyway, must post once you're done with your rethinking :-) – Nawaz Dec 26 '10 at 15:02
  • 1
    @Nawaz: Okay, I see what you're saying now. I come back to my position of "Yes, you can shoot yourself in the foot... but why would you ever want to?" – Jon Skeet Dec 26 '10 at 15:03
  • @Jon Skeet : that's a different question altogether. Why I asked this, because from everywhere(introductory books, and tutorials) I got this impression that one cannot access the private members, which now seems to be incorrect. I was just wondering what is the purpose of access-specifiers. – Nawaz Dec 26 '10 at 15:08
  • @Nawaz: They're for the purposes of encapsulation when you're not deliberately shooting yourself in the foot. Just treat the language with respect and everything will be well. – Jon Skeet Dec 26 '10 at 16:20
0

@Nawaz, your post is interesting, I never thought of this before. However, I believe the answer to your question is simple: think of C++ (or probably any language) security as a way to organize your code, rather than a police.

Basically, since all the variables are defined in your own code, you should be able to access them ALL, no matter where you define them. So you shouldn't be surprised you found a way to access a private member.

Actually, there is even an easier method to access private variables. Imagine you have a library with this class:

class VerySecure
{
private:
    int WorldMostSecureCode;
};

And let's say I am using your very secure class in my code. I can easily access the private member this way:

VerySecury a;
int *myhacker = (int*)(&a);
int b = (*myhacker);
printf("Here is your supposed world secret: %d :-) \n", b);

How is that?!!

Rafid
  • 18,991
  • 23
  • 72
  • 108
-1

No. it will break havoc with private methods. if the compiler is able to tell that these private methods cannot be accessed elsewhere, then they can be inlined and optimized-out, and they may not appear in the object file, so they will be inaccessible.

Take this as an example. It either works, can't link or can't run the executable depending on the optimization/stripping flags you use and how you compile the thing (ie, you can put the implementation in a shared library or not)

class A {
// i need this one ...
private:
        void stupid_private();
public:
        void unlock(std::string password);
};

implementation file :

#include <iostream>
#include "a.h++"

// uncomment this for more g++ fun
// __attribute__((visibility("hidden")))
void A::stupid_private() {
        std::cout << "let's output something silly." << std::endl;
}
void A::unlock(std::string password) {
        if (password == "jumbo")
                stupid_private();
}

the user file :

#define private public
#include "a.h++"

int main() {
        A a;
        a.stupid_private();
        return 0;
}
BatchyX
  • 4,986
  • 2
  • 18
  • 17
  • access specifiers have nothing to do with linkage. – jalf Dec 26 '10 at 10:06
  • @jalf by default, yes. But give your compiler some flags or some attributes (see A::stupid_private), and that can change. many optimizations aren't standart compliant. – BatchyX Dec 26 '10 at 13:28