未经授权的私有类成员访问会产生编译时错误而不是运行时错误?

Unauthorized private Class-member access yields a compile-time error rather than a run-time error?

本文关键字:编译时错误 运行时错误 访问 授权 成员      更新时间:2023-10-16

这是我最近尝试从类成员的上下文中摆弄private调用时遇到的问题:

#include <iostream>
#include <exception>
class TestClass {  
private: int var;    
};
int main() {  
TestClass test;  
try {  
test.var;  
}
catch( std::exception& e) {  
std::cout << "why does this not occur ?";  
}  
return 0; 
}

该错误是合理的error: ‘int TestClass::var’ is private within this context test.var;因此我尝试将调用包装在模板类中以避免错误被智能感知。

#include <iostream>
#include <exception>
class TestClass {
private:
int var;
};
template <class t>
void foo() {
t cl;
try {
cl.var;
}
catch (std::exception& e) {
std::cout << "why does this not occur ?";
}
return;
}
int main() { 
foo<TestClass>();
return 0;
}

这种对这个糟糕的私有变量区域的蹩脚访问尝试总是会导致一些编译时违规错误,SFINAEgetarround 似乎没有解决任何问题,我试图远程嗅探Class::var类型的可访问性总是使用模板:

#include <iostream>
#include <exception>
#include <type_traits>
#include <cstdint>

class TestClass
{
private:
int var;
};
template <class C>
int hasmember() { 
int ret=0;
try {
ret= std::is_same<decltype(C::var), int>::value;
}
catch (std::exception& e)
{
std::cout << "why does this not occur ?";
}
return ret; 
}
int main() {
TestClass cl;
printf("%s", hasmember<TestClass>()?"yes":"no");
}

错误控制台是苍白的,程序输出"yes",不会在异常上下文中捕获任何内容。

虽然它在try/exception子句中的不可拦截性对我来说不能很好地解释,为什么编译器不允许代码执行,并且是否有任何标志可以引发g ++强制它运行?

很少使用SFINAE进行射击和试验,extern没有导致任何光明的迹象,但一会儿我想如果我使用一些老式的 C hack 来尝试在这个私人区域的周边强制一个赛格故障怎么办?

这是我尝试过的:

class Class_
{
private:
int b = 10;
public:
int a ;
};
int main()
{
Class_ Class_;
try {
printf("%dn", *((&Class_.a) - 1));
}
catch (void* exc) {
printf("yet, will this ever be caught? n");
};
}

惊喜!

不,原始的"所谓的"私有值是不受限制地访问的,我只是试图将地址向后跟踪一个字节以获得其前身,一旦您检查它们的成员资格class::var并投射它们的类型信息,使用不同类型的变量并不难实现,这里的问题是这无论如何C++类结构中的安全效率低下?C 在与 C++ 一起使用时是否被认为是不安全的,以及如何保护这个私有区域,强制将 EIP 传导到异常处理程序的分段错误?

注意:在这种情况下,valgrind 报告崩溃的可能性更大,我没有尝试,但我希望有人确认。


模拟类型:

通过类类型模拟,我可以访问另一个类的私有成员,其核心略有不同,没有任何证据表明抛出异常,体验如下:

#include <stdio.h>
class foo {
public:
int var=0;
int val=1;
};
class bar {
int var=2;
public:
int val=3;
};
int main()
{
bar* cl;
cl = new bar();
printf("%dn",cl->val);
try {
printf("%dn", ((foo*)(cl))->var);
}
catch (void* e) {
printf("Will this ever be caught ?");
}
return 0;
}

输出:

3
2

结论:C++ 编译器禁止编译对私有成员的传统未经授权的访问,但如果在运行时从其容器外部访问此成员,它不会引发异常。

总结一下你可能误解的地方:privateprotected实质上限制了对后面变量、函数等名称的访问。这意味着,(在C或任何friend之外C)您将无法访问(名称)C::var。如果decltype(C::var)工作,那可能是编译器中的错误(gcc 和 clang 都不允许这样做)。

通常,C++中没有内置内存保护之类的东西(我确信可以使用底层操作系统的某些功能)。您将始终可以投射指向对象的指针,以char*和访问对象的各个字节。这意味着,如果(你认为)你知道你在做什么,你可以访问一个类的单个成员(我猜调用私有成员函数具有挑战性)。换句话说,如果你想搬起石头砸自己的脚,C++不会阻止你这样做。