简体   繁体   English

访问说明符不是万无一失的?

[英]Access-specifiers are not foolproof?

If I've a class like this, 如果我是这样的一个班级,

class Sample
{
private:
      int X;
};

Then we cannot access X from outside, so this is illegal, 然后我们无法从外部访问X,所以这是非法的,

    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 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> , 这意味着,我们可以通过在类定义之前或在#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)? 这不是C ++的问题(宏/访问说明符/什么)?

Anyway, the point of this topic is: 无论如何,这个主题的重点是:

Using macros, we can easily violate encapsulation. 使用宏,我们很容易违反封装。 Access-specifiers are not foolproof! 访问说明符并非万无一失! Am I right? 我对吗?

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; private是一个关键字,您不能将其用作宏中的标识符; 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.) :)(他们在那里帮助你保持安全,无论你怎么做,他们都不会帮助你安全并阻止他们访问它们.C ++可以防止Murphy,而不是Machiavelli。)

Note that you can access privates in a well-formed and well-defined manner, as demonstrated here . 请注意,您可以以格式良好且定义明确的方式访问private,如此处所示 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. 再一次,这不是语言的问题,只是语言的工作不仅仅是为了保持窥探而不必要。

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() : 您也可以通过在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. C ++中的访问说明符不是安全功能它们不能防止黑客攻击,并且它们不会防止人们故意试图将错误引入代码中。

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 . 正如@Gman所说,重新定义C ++语言中的关键字是未定义的行为 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. 它可能似乎适用于您的编译器,但它不再是一个定义良好的C ++程序,编译器原则上可以做任何它喜欢的事情。

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? 换句话说:你能否看到这是真正负责任的软件开发中的一个问题?

@Nawaz, your post is interesting, I never thought of this before. @Nawaz,你的帖子很有意思,我以前从没想过这个。 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. 但是,我相信您的问题的答案很简单:将C ++(或可能是任何语言)安全性视为组织代码的一种方式,而不是警察。

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. 基本上,由于所有变量都是在您自己的代码中定义的,因此无论您在何处定义它们,都应该能够访问它们ALL。 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?!! 那个怎么样?!!

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM