Post/Send Event传递指针的危险性分析(转自CSDN MAOXIAODONG)

 

      提前概括:

Event传递数据时,处理不当极易发生Double Free,或者访问无效指针。而且非常难查,是隐藏的很深的, 主要原因是: BREW有自动释放应用上下文环境下分配的内存的默认行为!!!!

 

      方法1A创建数据(普通指针),并SendEventB

    虽然考虑以后的兼容性,仍然不建议使用。但是,目前而言,接收方进行MemoryCopy后使用,仍然是安全的。

 

      方法2A创建Interface Instance,并SendEventB 

    传统的认识是:只要接收方进行AddRef,就没有问题了。但是,如果Instance的创建是在应用环境下,那么,BREW还是会自动回收的。比如:

     A创建了InterfaceA Instance,并通过SendEvent传给BB接收时,使用了AddRef。接着,A退出,此时,AFreeData中的RELEASEIF(InterfaceA)并不会释放InterfaceA Instance,只是Ref1。但是,在A退出后,BREW会自动释放InterfaceA的相关内存,因为InterfaceA是在A的上下文环境创建的。那么,此后B使用的Interface A Instance将是无效的!

 

        方法3A 创建数据(普通指针),A PostEvent to B 

     

      假设A应用Malloc了一块Buffer,通过PostEvent传递给B应用, 假设为了其一直有效,A应用不主动释放它,而是由B应用来释放。

 

          case 1 B应用收到事件前,A应用已经退出。 此时虽然A应用并没有主动释放Buffer,但是,BREW有自动内存回收的行为,会在A应用退出时,自动释放该Buffer。所以,B此时取到的Buffer是无效的,可能引起内存非法操作!!

          case 2 B应用收到事件时,A应用没有退出,但是,在B应用释放该Buffer前,A应用退出了。此时,BREW仍然会当A退出时,自动释放该Buffer。 这样,B使用的将是无效的内存,且当B再释放该Buffer时,就会导致Corrupt Node

          case 3 B应用收到事件时,A应用没有退出,且B应用释放该Buffer后,A应用才退出,此时才是没有任何问题的,因为B应用已经释放该Buffer,所以BREW不会当A退出时再自动释放了,也就不会存在问题了。

 

      总结: 对于方法3,从理论上2/3的概率会导致Memory非法操作,危险至极!! 有兴趣者,可以去模拟case 1 case2 试试看,是不是有问题。

 

 

      方法4A创建Interface Instance,并PostEventB,B接收Instance后调用AddRef

       这从理论上就不可能避免危险,同方法2,并且增加了异步的不可靠性。

 

      方法5A 调用 B接口,B接口 Send/Post Event to B应用:

 

      按照Barton.Li的叙述,很多模块的做法是, A 调用 B接口传递Buffer B接口备份该Buffer(这样A接口就可以释放该Buffer了),B接口将备份的Buffer传递给B应用,B应用处理完后再释放该Buffer

 

      这里需要注意的是,A调用B接口传递的BufferB接口内部备份的Buffer,都是在A应用的环境下分配的。 所以BREW将在A应用退出时,自动回收这两块Buffer(如果没有释放的话)。

 

      case1A调用B接口传递BufferB接口备份该Buffer,并PostBufferB应用,假设,B应用收到事件之前,A应用退出了,那么,A传递的BufferB备份的Buffer都会被释放,前者是A主动释放的,后者是BREW自动释放的。 这样,B应用得到的Buffer是无效的!!

      case2A调用接口传递BufferB接口备份Buffer,并PostBufferB应用,假设B应用收到事件之前,A应用并没有退出,但是,B应用释放Buffer之前,A应用退出了。 这样,当A应用退出时,A传递的BufferB备份的Buffer都会被释放,前者是A主动释放的,后者是BREW自动释放的。这样,B将使用无效Buffer,且当B应用再次释放Buffer时,就会出现Double Free

      case3A调用接口传递BufferB接口备份Buffer,并PostBufferB应用,假设B应用收到事件之前,A应用并没有退出,并且B应用释放Buffer之后,A应用才退出了。 这样,当A应用退出时,BREW不会再主动释放B接口备份的Buffer了,也就没有问题了。

 

      总结:对于方法5, 仍然从理论上2/3的概率会导致Memory非法操作,危险至极!! 有兴趣者,可以去模拟case 1 case2 试试看,是不是有问题。

 

 

      再次总结:

以上的危险性,是由于BREW的默认内存自动回收行为和PostEvent的异步不安全性导致的。 从理论上来说,如果使用PostEvent,就不可能保证数据的安全性。所以,在使用PostEvent时,应该禁止投递指针!!!!!此外,由于Interface的不可Copy性,所以,对于Interface,即便是SendEvent也是不允许的!

 

 

        解决方法:

1.    按照Qualcomm的建议,尽量不使用Event投递指针。

2.    对于Non-Interface Point,如果想使用PostEvent投递,并且没有任何上述的问题,那么就使用PostURL吧!!!!! 最主要的有两点优点: 利用MIME机制进行应用间解耦;安全的异步投递数据(借助Base64编码投递任意Buffer)。

3. 另外有一种方式,可以使得PostEvent时达到数据的安全性。 但是不十分规范,因为应用环境下应该尽量避免分配系统环境下的内存:具体为: 

     需要通过PostEvent投递的Buffer,在系统上下文环境下分配,并由接收者释放。 这样,即便接收者收到事件前发送者已经退出,或者接收者释放Buffer前,发送者已经退出,也不会有任何问题了。 因为该Buffer是在系统环境下分配的,所以应用退出时,BREW不会自动释放它。 所以就不会出现 指针无效,或者内存泄漏,或者Double Free了。 

     其实Post/SendURL的内部,备份数据时,就是在系统环境下分配的内存。

4.禁止投递Interface指针。虽然通过在系统环境下创建Interface可能可以避免,但是为了降低复杂度和潜在危险性,禁止是最好的方法。

上一篇:真的超赞!用systemd命令来管理linux系统!


下一篇:create-react-app 创建的项目添加less支持