指针为啥是不安全的呢?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了指针为啥是不安全的呢?相关的知识,希望对你有一定的参考价值。

我问过老师,老师说在内存访问中,操作系统不可避免要使用指针的;
那么我就想,那我们使用指针为什么就被称为是不安全的呢?
是不是因为怕我们编程序的时候没有清楚认识到某个指针指向的地址,然后对其操作就可能会造成不可恢复的错误呢?
更想请高手指点!
谢谢!

因为指针数据是可以直接访问内存单元的。如果指针数据被恶意写入一些特定的值,便会出现很多的问题。有可能不想被用户知道的存在于内存中的数据将被指针调用。有可能恶意用户可以通过指针向特定内存单元写入特定的数据,造成缓冲区溢出等等的问题。 造成的后果将有可能是重要数据被窃取,甚至使恶意用户获得系统的高级权限。 参考技术A C指针往往会因误操作会导致有可能指向一空地址,或系统所使用地址这样会影响系统.

常见的内存错误如下:
1,内存分配未成功,却使用了它。(使用assert检查(p == NULL))
2,内存分配虽然成功,但是尚未初始化就引用它。
3,内存分配成功并且已经初始化,但操作越过了内存的边界。(数组下标)
4,忘记了释放内存,造成内存泄露。(delete/free)
5,释放了内存却继续使用它(留下野指针,危险)。
参考技术B 推荐你看看林锐的《高质量c++编程指南》。
指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。
常见的内存错误如下:
内存分配未成功,却使用了它。(使用assert检查(p == NULL))
内存分配虽然成功,但是尚未初始化就引用它。
内存分配成功并且已经初始化,但操作越过了内存的边界。(数组下标)
忘记了释放内存,造成内存泄露。(delete/free)
释放了内存却继续使用它(留下野指针,危险)。
看吧,问题很多吧,所以很危险.呵呵本回答被提问者采纳
参考技术C 指针尖锋利,容易造成意外伤害。
针字属于咸字族。在咸字族里,咸字都是声符兼义符。咸字族汉字都与“酸涩、苦涩”之义有关。针的本义是“一种刺入肌体后会产生酸涩感的金属医具”。
参考技术D 指针不安全,因为程序员总会犯错的,只要你不犯错,指针就是安全的

向上转换函数指针是不是安全?

【中文标题】向上转换函数指针是不是安全?【英文标题】:Is it safe to upcast a function pointer?向上转换函数指针是否安全? 【发布时间】:2013-02-19 15:38:16 【问题描述】:

我有基类ObjectEvent

class Object

//...
;

class Event

;

还有一个函数指针的类型定义

typedef void (Object::*PF) (Event*);

还有一个存储两个指针的无关类

class Dispatcher

public:
    Dispatcher (Object* obj, PF pf) : _obj (obj), _pf (pf)

    void call (Event* event)
    
        _obj->*pf (event);
    

    Object* _obj;
    PF _pf;
;

然后我有一个具体的对象和一个具体的事件

class ConcreteEvent : public Event

;

class ConcreteObject : public Object

public:
   void handle (ConcreteEvent* event)
   
      // Do something specific for ConcreteEvent
   
;

然后这样称呼它

ConcreteObject* obj = new ConcreteObject();
Dispatcher dispatcher (obj, static_cast<PF>(&ConcreteObject::handle));

ConcreteEvent* event = new ConcreteEvent ();
dispatcher.call (event);

我保证调度器总是会被正确的事件调用,即当它封装的函数指针实际上采用SomeOtherConcreteEvent时,我不会调用调度器并传递它ConcreteEvent

问题是:这能保证有效吗?在 linux 和 mingw 上的 gcc 4.7 中肯定可以正常工作。

【问题讨论】:

【参考方案1】:

来自 C++11 标准,第 4.11.2 节:

“指向类型为 cv T 的 B 的成员的指针”类型的纯右值,其中 B 是类类型,可以转换为 类型“指向 cv T 的 D 成员的指针”类型的纯右值,其中 D 是 B 的派生类(第 10 条)。如果 B 是 D 的不可访问(第 11 条)、模棱两可(10.2)或虚拟(10.1)基类,或虚拟的基类 D 的基类,需要这种转换的程序格式错误。转换的结果是指 在转换发生之前指向与指向成员的指针相同的成员,但它指的是基 类成员,就好像它是派生类的成员一样。

所以是的,这应该是安全的。

编辑:因此,如果您实际上是指 向下转换:,根据 C++11 5.2.9.12,这也是合法的:

类型为“指向 cv1 T 的成员的指针”类型的纯右值可以转换为类型为“指向的指针”的纯右值 类型 cv2 T 的 B”的成员,其中 B 是 D 的基类(第 10 条),如果从 “指向T类型B成员的指针”到“指向T类型D成员的指针”存在(4.11),与cv2相同 cv 限定为或大于 cv1。 69

【讨论】:

代码使用了这种转换的逆向,static_cast 明确允许这种转换。结果只能用于成员的实际类类型的对象,但 OP 已经说过他对此很小心。 @aschepler 标准中还有另一节。然而,这就是所谓的“向上转型”。逆向是“向下转换”(从派生类的成员转换为基类的成员时)。 用指向成员的指针调用什么可能会让人感到困惑,但第 4 节描述了可以隐式使用的标准转换,而这段代码需要相反的,不能隐式使用。 @aschepler 但是这里没有人谈论隐式类型转换。 OP 很好奇 cast 是否可行。 我只是指出,OP 中的示例代码包含一个指针到成员的转换,你称之为“向下转换”,而没有指针到成员的转换,你称之为“向上转换”。 【参考方案2】:

我认为它是安全的,有两个原因。

首先是指向成员函数的指针只能安全地向下传播(因为Derived 类必然继承了基类的函数,而反之则不然)。

class Base 
public:
   void foo();
; // class Base

class Derived: public Base 
public:
   void bar();
;

using PBase = void (Base::*)();
using PDerived = void (Derived::*)();

int main() 
   PBase pb = &Base::foo;
   PDerived pd = &Derived::bar;

   pb = pd; // error: cannot convert 'PDerived aka void (Derived::*)()'
            //                    to 'PBase aka void (Base::*)()' in assignment
   pd = pb;

(如here所见)

第二个是你不能像那样改变参数的类型。为了说明这个问题,使用ConcreteObject: public virtual Object,你会发现它并没有像你希望的那样工作。


现在,这并不意味着你想做的事情是不可能的,只是它需要多一点

理想情况下,您只需修复签名以同时获取ObjectEvent,而不是使用成员函数,然后在必要时让它处理手动转换:

using Function = std::function<void(Object*,Event*)>;

void handle(Object* o, Event* e) 
    ConcreteObject* co = dynamic_cast<ConcreteObject*>(o);
    ConcreteEvent* ce = dynamic_cast<ConcreteEvent*>(e);

    if (co and ce)  co->handle(ce); 

或者任何你觉得舒服的施法/检查。

注意:使用 std::function 是为了与 lambdas/functors 兼容。

【讨论】:

或者您可以将Dispatcher 设为模板,将Event 的具体子类作为参数,以在编译时强制执行成员仅与兼容类型的事件对象一起使用的承诺。 @aschepler:实际上,Dispatcher 目前对我来说毫无用处,所以我宁愿不谈论它 :)

以上是关于指针为啥是不安全的呢?的主要内容,如果未能解决你的问题,请参考以下文章

将向量地址转换为本机指针是不是安全?

C# 中是不是有像 C++ 这样的指针?安全吗?

将结构成员指针分配给另一个动态内存分配的指针是不是安全?

检查指针是不是为空,然后在同一个 if 语句中取消引用它是不是安全?

使用无锁指针队列在线程之间移动数据是不是安全

为啥刷新令牌对于 SPA 来说被认为是不安全的?