掌桥专利:专业的专利平台
掌桥专利
首页

一种内存访问方法及相关设备

文献发布时间:2024-05-31 01:29:11


一种内存访问方法及相关设备

技术领域

本申请实施例涉及计算机领域,尤其涉及一种内存访问方法及相关设备。

背景技术

随着计算机领域的发展,C++语言的应用也越来越广泛。

C++语言通过内存分配回收机制访问内存,其中可访问的内存区域包括栈区、堆区、共享内存区、全局变量区(含静态变量)和常量区。

但对上述部分内存区域的访问是不安全的,会导致内存错误和漏洞的产生。

发明内容

本申请实施例提供一种内存访问方法及相关设备,用于禁止直接访问不安全的内存区域,避免导致内存错误和漏洞的产生。本申请实施例还提供了相应的计算机设备、计算机可读存储介质、芯片系统及计算机程序产品等。

本申请第一方面提供一种内存访问方法,该方法包括:获取第一组件,第一组件包括第一对象,第一组件的可用内存区域包括安全内存区域和托管内存区域;将第一对象分配在安全内存区域,得到第一安全对象,并将第一对象分配在托管内存区域,得到第一托管对象,第一安全对象为第一托管对象的访问接口;基于第一安全对象对第一托管对象进行访问。

本申请中的第一组件为C++二进制程序,可以理解为一个功能模块,第一组件包括第一对象,第一对象和可以为第一组件中的一个类的实例、栈或者容器等,第一组件的可用内存区域包括安全内存区域和托管内存区域(不安全内存区),其中安全内存区域包括栈区和常量区,托管内存区域包括堆区、共享内存区和全局变量区。

本申请中的第一安全对象分配在计算机设备的安全内存空间中,具体可以为真实的物理栈(栈区)上。第一托管对象分配在计算机设备的托管内存区域中,具体可以为堆区。

本申请中,需要访问第一托管对象时,必须基于第一安全对象对第一托管对象进行访问,第一托管对象管理第一对象的实际内存分配,第一安全对象可以理解为指针,第一托管对象的生成、销毁和访问均需经过第一安全对象。

该第一方面,将组件中的对象分配至安全内存区域,得到安全对象,并将对象分配在托管内存区域,得到托管对象,其中安全对象为托管对象的访问接口,当对象需要访问不安全的托管内存区域时,只能通过安全对象对托管对象进行访问,从而禁止直接访问不安全的内存区域,避免导致内存错误和漏洞的产生。

在第一方面的一种可能的实现方式中,上述步骤:获取第一组件包括:获取用户代码,用户代码中定义有安全托管类型,安全托管类型用于表示允许访问托管内存区域;基于用户代码生成第一组件;将第一对象分配在托管内存区域包括:当第一对象为安全托管类型时,将第一对象分配在托管内存区域。

该种可能的实现方式中,在获取第一组件时,通过要求工作人员在编译用户代码时,必须从内存安全角度限制内存使用方式,满足内存安全托管库的内存托管限制,对于托管内存区域的使用场景,需将组件中的对象定义为安全托管类型来实现,最终得到第一组件,提升了方案的可实现性。

在第一方面的一种可能的实现方式中,该方法还包括:存在不为安全托管类型的用户代码用于访问托管内存区域时,发出编译错误提示。

该种可能的实现方式中,在工作人员编译用户代码时,还可以进行扫描,对不满足内存安全托管库的内存托管限制的场景发出提示,要求重新编译,提升了方案的可实现性。

在第一方面的一种可能的实现方式中,上述步骤:将第一对象分配在托管内存区域,得到第一托管对象包括:在托管内存区域为第一组件分配出第一隔离区;将第一对象分配在第一隔离区,得到第一托管对象。

该种可能的实现方式中,基于组件生成独立的隔离区,对隔离区内存进行保护限制,其他组件无法跨越隔离区访问,避免了踩内存和故障传播的问题。

在第一方面的一种可能的实现方式中,第一组件还包括第二对象,上述步骤:将第一对象分配在第一隔离区,得到第一托管对象之后,该方法还包括:将第二对象分配在安全内存区域,得到第二安全对象,并将第二对象分配在第一隔离区,得到第二托管对象;其中,第二安全对象为第二托管对象的访问接口,第二托管对象的生命周期小于第一托管对象的生命周期,第二对象的访问权限大于第一对象。

该种可能的实现方式中,第一组件中可以包括多个对象,同一组件的托管对象分配在一个隔离区,且后分配的托管对象的生命周期更短,访问权限更大,通过限制对象的分配回收顺序、限制对象的访问权限,避免了提前释放、双重释放和释放后使用的问题。

在第一方面的一种可能的实现方式中,该方法还包括:当第二托管对象需要回收时,回收第二托管对象并释放第二托管对象占用的空间;当第一托管对象需要回收,且第一隔离区中只存在第一托管对象时,回收第一托管对象并释放第一隔离区占用的空间。

该种可能的实现方式中,因后分配的托管对象的生命周期更短,在托管对象访问结束需要回收时,后分配的托管对象会先被回收,且隔离区不存在托管对象时,隔离区也会被释放,节省了内存空间,保障了对象的分配回收顺序,提升了方案的可实现性。

在第一方面的一种可能的实现方式中,第一隔离区包括第一子隔离区,第一子隔离区中分配有第一子托管对象,第一子托管对象的生命周期和访问权限与第一托管对象的生命周期和访问权限相同。

该种可能的实现方式中,对象为容器时,因容器的分配回收更为复杂,还会为容器分配出子隔离区,子隔离区中的子托管对象的生命周期和访问权限与对应的托管对象相同,且允许传递托管对象的所有权,提升了方案的可实现性。

在第一方面的一种可能的实现方式中,该方法还包括:获取第二组件,第二组件包括第三对象;将第三对象分配在安全内存区域,得到第三安全对象,并在托管内存区域为第二组件分配出第二隔离区,将第三对象分配在第二隔离区,得到第三托管对象;其中,第二隔离区与第一隔离区相互隔离,第三安全对象为第三托管对象的访问接口。

该种可能的实现方式中,还可以获取第二组件,第二组件的本质与第一组件相同,但功能可能不同,第二组件需要在托管内存区域分配出新的隔离区,且与第一组件的隔离区相互隔离,避免了踩内存和故障传播的问题,提升了方案的可实现性。

在第一方面的一种可能的实现方式中,第一托管对象的生命周期与第一安全对象的生命周期相同。

该种可能的实现方式中,通过限定托管对象和安全对象的生命周期,避免了野指针的问题。

在第一方面的一种可能的实现方式中,第一安全对象具有第一托管对象的所有权变更权限。

该种可能的实现方式中,所有权变更权限包括所有权改变权限(Move)所有权借用权限(Borrow),保障了对象非共享模式操作,避免了并发安全的问题。

本申请第二方面,提供了一种计算机设备,用于执行上述第一方面或第一方面的任意可能的实现方式中的方法。具体地,该计算机设备包括用于执行上述第一方面或第一方面的任意可能的实现方式中的方法的模块或单元,如:获取单元、分配单元、访问单元、提示单元和回收单元。

本申请第三方面提供一种计算机设备,该计算机设备包括处理器、内存和存储有计算机程序的计算机可读存储介质;处理器与计算机可读存储介质耦合,处理器上运行的计算机执行指令,当计算机执行指令被处理器执行时,处理器执行如上述第一方面或第一方面任意一种可能的实现方式的方法。可选地,该计算机设备还可以包括输入/输出(input/output,I/O)接口,该存储有计算机程序的计算机可读存储介质可以是存储器。

本申请第四方面提供一种存储一个或多个计算机执行指令的计算机可读存储介质,当计算机执行指令被处理器执行时,处理器执行如上述第一方面或第一方面任意一种可能的实现方式的方法。

本申请第五方面提供一种存储一个或多个计算机执行指令的计算机程序产品,当计算机执行指令被处理器执行时,处理器执行如上述第一方面或第一方面任意一种可能的实现方式的方法。

本申请第六方面提供了一种芯片系统,该芯片系统包括至少一个处理器和接口,该接口用于接收数据和/或信号,至少一个处理器用于支持计算机设备实现上述第一方面或第一方面任意一种可能的实现方式中所涉及的功能。在一种可能的设计中,芯片系统还可以包括存储器,存储器,用于保存计算机设备必要的程序指令和数据。该芯片系统,可以由芯片构成,也可以包含芯片和其他分立器件。

本申请实施例中,将组件中的对象分配至安全内存区域,得到安全对象,并将对象分配在托管内存区域,得到托管对象,其中安全对象为托管对象的访问接口,当对象需要访问不安全的托管内存区域时,只能通过安全对象对托管对象进行访问,从而禁止直接访问不安全的内存区域,避免导致内存错误和漏洞的产生。

附图说明

图1为C++语言的编译流程示意图;

图2为本申请实施例提供的内存访问方法一个实施例示意图;

图3为本申请实施例提供的内存访问方法的应用场景的示意图;

图4为本申请实施例提供的内存访问方法的另一实施例示意图;

图5为本申请实施例提供的内存访问方法的应用工具的示意图;

图6为本申请实施例提供的内存访问方法的编译流程示意图;

图7为本申请实施例提供的内存访问方法的另一实施例示意图;

图8为本申请实施例提供的计算机设备的一实施例示意图;

图9为本申请实施例提供的计算机设备的另一实施例示意图。

具体实施方式

下面结合附图,对本申请的实施例进行描述,显然,所描述的实施例仅仅是本申请一部分的实施例,而不是全部的实施例。本领域普通技术人员可知,随着技术发展和新场景的出现,本申请实施例提供的技术方案对于类似的技术问题,同样适用。

本申请的说明书和权利要求书及上述附图中的术语“第一”、“第二”等是用于区别类似的对象,而不必用于描述特定的顺序或先后次序。应该理解这样使用的数据在适当情况下可以互换,以便这里描述的实施例能够以除了在这里图示或描述的内容以外的顺序实施。此外,术语“包括”和“具有”以及他们的任何变形,意图在于覆盖不排他的包含,例如,包含了一系列步骤或单元的过程、方法、系统、产品或设备不必限于清楚地列出的那些步骤或单元,而是可包括没有清楚地列出的或对于这些过程、方法、产品或设备固有的其它步骤或单元。

在这里专用的词“示例性”意为“用作例子、实施例或说明性”。这里作为“示例性”所说明的任何实施例不必解释为优于或好于其它实施例。

另外,为了更好的说明本申请,在下文的具体实施方式中给出了众多的具体细节。本领域技术人员应当理解,没有某些具体细节,本申请同样可以实施。在一些实例中,对于本领域技术人员熟知的方法、手段、元件和电路未作详细描述,以便于凸显本申请的主旨。

本申请实施例提供一种内存访问方法及相关设备,用于禁止直接访问不安全的内存区域,避免导致内存错误和漏洞的产生。本申请实施例还提供了相应的计算机设备、计算机可读存储介质、芯片系统及计算机程序产品等。以下分别进行详细说明。

下面对本申请实施例涉及的应用场景进行举例说明。

如图1所示,随着计算机领域的发展,C++语言的应用也越来越广泛。在C++语言的应用中,需要工作人员通过编译器(编译工具链)进行编译,得到源码程序,即用户代码/用户程序,最后可以生成二进制程序,该二进制程序为可以在硬件平台上执行的机器码,程序功能就是用户需要的C++程序,可以部署在各种终端产品中,例如智能汽车、智能电器或计算机设备等。

C++语言通过动态灵活的内存分配回收机制访问内存,在内存分配回收机制下,可访问的内存区域包括栈区、堆区、共享内存区、全局变量区(含静态变量)和常量区。

其中,内存安全问题发生的概率与使用区域有很大关系,栈区的数据分配由编译器决定,因此是安全的,而常量区不允许修改,访问也是安全的,但堆区、共享内存区和全局变量区访问是不安全的,例如出现越界访问、踩内存、提前释放、双重释放、释放后使用(useafter free,UAF)、野指针、内存碎片、内存泄漏、故障传播和并发安全等问题,导致内存错误和漏洞的产生。

下面结合上述应用场景对本申请实施例提供的内存访问方法进行说明。

如图2所示,本申请实施例提供的内存访问方法的一实施例包括:

201、获取组件,组件包括对象。

本申请实施例以中计算机设备执行为例,该计算机设备可以部署在各种终端产品中,例如智能汽车、智能电器等。

本申请实施例获取第一组件和第二组件,第一组件和第二组件为C++二进制程序(简称二进制程序),可以理解为一个功能模块(即数据和方法的简单封装对象),第一组件包括第一对象和第二对象,第一对象和第二对象可以为第一组件中的一个类(即一种引用数据类型)的实例、栈或者容器等,第二组件包括第三对象,第一组件和第二组件的可用内存区域包括安全内存区域和托管内存区域(不安全内存区),其中安全内存区域包括栈区和常量区,托管内存区域包括堆区、共享内存区和全局变量区。

在获取第一组件时,首先需要获取用户代码,该用户代码为C++用户代码(C++用户程序,简称用户代码),用户代码中定义有安全托管类型,安全托管类型为内存安全托管库定义的,内存安全托管库可以预先建立和编辑规则,安全托管类型用于表示允许访问托管内存区域,因此要求工作人员在编译用户代码时,必须从内存安全角度限制内存使用方式,满足内存安全托管库的内存托管限制,例如无法直接申请内存的全局变量区和共享内存区等,对于托管内存区域的使用场景,需将组件中的对象定义为安全托管类型来实现,或者完全禁止通过全局变量等方式传递信息来设计二进制程序。

进一步的,在生成用户代码后,还可以对用户代码进行扫描,判断是否违反内存托管限制,例如当存在不为安全托管类型的用户代码用于访问托管内存区域时,发出编译错误提示,此时需要工作人员返回修改代码,重新生成用户代码,当用户代码都不违反内存托管限制后,再根据关键字等(例如new、malloc、make_unique、static)识别出安全托管类型,为用户代码中所有用到的安全托管类型生成用于访问不安全内存区的托管指令,只有托管指令可以申请访问托管内存区域,最后基于用户代码生成二进制程序,即第一组件和第二组件。

应理解,第一组件和第二组件的生成方式相同,组件的实现功能可能不同,本申请实施例以对第一组件进行说明为例,第二组件的生成方式可以参照第一组件,第一对象、第二对象和第三对象同理,本申请实施例对部分相同之处不再赘述。此外,还可以采用上述相同的方法生成第三组件或第四组件等,或只生成第一组件,第一组件中可以只包括第一对象,也可以还包括第三对象或第四对象等,本申请实施例对此不作限制。

202、将对象分配在安全内存区域,得到安全对象,并将对象分配在托管内存区域,得到托管对象。

203、基于安全对象对托管对象进行访问。

如图3所示,以计算机设备部署在车载终端上为例,获取到二进制程序后,运行该二进制程序,即运行第一组件(车载软件组件1)和第二组件(车载软件组件2),第一组件和第二组件可以理解为运行在计算机设备的程序空间中。

进一步的,将第一组件的第一对象分配在安全内存区域,得到第一安全对象(安全对象1),将第一组件的第二对象分配在安全内存区域,得到第二安全对象(安全对象2),将第二组件的第三对象分配在安全内存区域,得到第三安全对象(安全对象a)。

具体的,第一安全对象、第二安全对象和第三安全对象分配在计算机设备的安全内存空间中,具体可以为真实的物理栈(栈区)上,每分配一个安全对象,物理栈就从左至右增长。

当第一对象、第二对象和第三对象都为安全托管类型时,还需要执行托管命令,同时将第一对象分配在托管内存区域,得到第一托管对象(对象1),将第二对象分配在托管内存区域,得到第二托管对象(对象3),将第三对象分配在托管内存区域,得到第三托管对象(对象a)。其中,第一安全对象为第一托管对象的访问接口,第二安全对象为第二托管对象的访问接口,第三安全对象为第三托管对象的访问接口。以第一对象为例进行说明,需要访问第一托管对象时,必须基于第一安全对象对第一托管对象进行访问,第一托管对象管理第一对象的实际内存分配,第一安全对象可以理解为指针,第二对象和第三对象同理。

具体的,以第一对象为例进行说明,第一托管对象的生成(分配)、销毁(回收)和访问均需经过第一安全对象(托管接口),且第一安全对象具有第一托管对象的所有权变更权限,允许其传播共享,即借用Rust语言中所有权机制对模拟栈上的对象赋予Move/Borrow所有权机制,允许托管对象的生命周期被改变和传递,允许托管对象的所有权发生变更和借用,其中,所有权机制是对每个托管对象赋予唯一所有者,允许安全对象改变该托管对象的所有者,但是不允许添加或者删除所有者。即任何时刻该托管对象有且仅有一个所有者,借助C++拷贝构造和赋值构造函数实现托管对象的Move操作,借助C++移动构造和移动赋值函数实现托管对象的Borrow操作,其中Move操作可以把所有者切换成另外一个属主,而Borrow操作可以借用托管对象的使用权,但不能改变所有者,从而保障并发安全访问和数据共享等内存安全,实现安全对象的托管接口(指针)功能,让动态对象可感知析构顺序,从而解析UAF等问题。需要说明的是,禁止借用比自身生命周期更短的托管对象,可选的,禁止借用跨模拟栈(不同组件的)的托管对象。

示例性的,第一托管对象、第二托管对象和第三托管对象分配在计算机设备的托管内存区域中,具体可以为堆区,每个对象分配有独立的隔离区,隔离区具体可以为模拟栈。分配第一托管对象时,首先判断托管内存空间中是否存在第一对象的隔离区,若不存在,即第一对象首次分配时,在托管内存区域为第一组件分配出第一隔离区(组件1模拟栈隔离区),并将第一对象分配在第一隔离区,得到第一托管对象,第一托管对象分配在第一隔离区的栈底位置,同理,分配第二托管对象时,判断出存在第一对象的第一隔离区,则将第二对象分配在第一隔离区,得到第二托管对象,第二托管对象分配在第一托管对象的上方,同理,分配第三托管对象时,在托管内存区域为第二组件分配出第二隔离区(组件2模拟栈隔离区),将第三对象分配在第二隔离区,得到第三托管对象,其中,第二隔离区与第一隔离区相互隔离,防止了碎片化分配并且有利于边界检测,可在运行时实时检测越界访问和溢出等问题。

可选的,在二进制程序的编译阶段,可以为每个组件分配一个组件识别(ID)号,在分配第三托管对象时,根据ID号识别出第三对象对应得第二组件与第一对象和第二对象对应得第一组件不同,因此需要重新分配出一个与第一隔离区相互隔离的第二隔离区,借助C++模板机制通过ID号对不同组件的内存进行物理隔离,防止了碎片化分配并且有利于边界检测,可在运行时实时检测越界访问和溢出等问题。

需要说明的是,以第一对象为例进行说明,第一托管对象的生命周期与第一安全对象的生命周期相同,即第一托管对象和第一安全对象同时分配与回收,在安全内存空间,越先分配的安全对象在物理栈中位于越靠左侧的位置,在托管内存空间中,越先分配的托管对象在模拟栈中位于越靠底部的位置,因第二托管对象晚于第一托管对象分配(分配顺序依赖于内存安全托管库中的定义),则在同一个隔离区中,第二托管对象的生命周期一定小于第一托管对象的生命周期,且第二对象的访问权限大于第一对象,可以理解为只允许第二对象访问第一托管对象,但不允许第一对象访问第二托管对象,即对象的安全/托管对象的生命周期越短,其访问权限就越大。在当第二托管对象需要回收时,只回收第二托管对象并释放第二托管对象占用的空间,当第一托管对象需要回收,且第一隔离区中只存在第一托管对象时,回收第一托管对象并释放第一隔离区占用的空间,实现托管内存空间中模拟栈的先入后出机制。

模拟栈的先入后出机制可以保障处在模拟栈底的托管对象有最长的生命周期,处在模拟栈顶的托管对象有最短的生命周期,保证在模拟栈中的托管对象生命周期一定是经过排序的,生命周期短的托管对象在其短暂的生命周期中访问生命周期长的托管对象的内容是安全的,因为对方生命周期比自己长,那么可以确保访问一定是有效的,且对象的析构(死亡)是安全的,生命周期短的托管对象死亡后可以确定不会有对象再去访问它了(不安全),从而解决析构顺序问题和顺序感知问题,防止UAF等问题的发生。

示例性的,第二组件对第一组件存在函数调用,具体为第三对象需要调用第一对象,因第一安全对象的生命周期比第三安全对象的生命周期长,则第三对象的访问权限大于第一对象,第三对象基于第一安全对象来访问第一托管对象,从而实现第一对象的调用。当第一对象需要调用第二对象时,因第一安全对象的生命周期比第二安全对象的生命周期长,则第二对象的访问权限大于第一对象,不允许访问。

可选的,以第一对象为例进行说明,当第一对象为容器时,第一隔离区(此时为容器对象2)包括第一子隔离区(组件1容器内存隔离区),第一子隔离区中分配有第一子托管对象,第一子托管对象的生命周期和访问权限与第一托管对象(位于对象1和对象3之间)的生命周期和访问权限相同,此外,第一子隔离区中的第一子托管对象允许传递第一托管对象的所有权。

如图4所示,总结上述内存访问方法,生成二进制程序的过程可以理解为编译态,在第一计算机设备中执行,运行二进制程序的过程可以理解为运行态,在第二计算机设备中执行,第一计算机设备和第二计算机设备可以为不同的计算机设备,分别部署在不同的终端产品,也可以为同一个计算机设备。

如图5所示,工作人员在编译态的过程中,需要使用内存安全托管库和内存安全编译器,其中内存安全托管库中定义有多种安全托管类型,包括安全对象(safe obj)类型、安全栈(safe stack)类型和安全容器(safe container)类型,安全对象类型采用资源获取即初始化(resource acquisition is initialization,RAII)方式设计,即在一个对象(资源)在物理栈区生成的时候,同时把托管对象在堆区进行分配,并通过指针绑定两者(初始化过程),用于替换原有的C++动态内存申请接口,安全对象是安全内存区域用于访问托管内存区域的托管接口,可以实现对象所有权机制,安全栈类型用于在托管内存区域内实现对安全对象的栈式管理,实现对象生命周期管理和感知,安全容器类型设计为用于替换标准模板库(Standard Template Library,STL)中的容器接口,也是在安全内存区域用于访问不安全内存区的托管接口,实现动态对象管理,安全容器类型具体包括安全数组、安全向量、安全列表和安全哈希等类型。

内存安全编译器用于扫描编译错误的扫描模块包括堆分配扫描、静态变量扫描、全局变量扫描、共享内存扫描等模块。该机制通过安全编译方式防止C++程序代码绕过内存安全托管库接口,而直接使用托管内存区域的内存,内存安全编译器还包括生成的托管指令,托管指令包括安全对象托管指令和安全栈托管指令,内存安全托管库中安全对象、安全栈、安全容器都需要访问托管内存区,内存安全编译器为相应的类型生成托管指令,例如需要为安全对象生成ThreadLocal类型的全局变量SafeStack的索引,并为其构造和析构函数生成托管指令,在托管指令中检查内存分配/回收失败情况并作处理等。

如图6所示,在编译态阶段,工作人员可以使用图5中所示的内存安全编译器(C++编译工具链)和内存安全托管库(运行库),编译生成C++用户程序,其中C++用户程序和C++内存安全编译器都依赖于C++内存安全托管库来实现,并最终生成C++内存安全二进制程序,得到部署在终端产品(如智能汽车)上的程序代码,并可以采用内存预分配的方式,提前分配大块内存后使用,且内存预分配采用整页分配和整页回收,尽量避免采用动态分配内存,满足汽车功能安全要求。其中C++内存安全托管库以接口和二进制程序的方式提供,C++用户程序中对托管内存区域的访问都需要通过调用C++内存安全托管库接口进行替换,C++内存安全编译器会识别C++用户程序中不安全使用托管内存区域的情况并返回编译错误。

如图7所示,再结合一个实例对本申请实施例提供的内存访问方法进行说明。

首先使用内存安全编译器编译组件1和组件2代码,扫描后生成二进制程序并运行,运行后的二进制程序首先在安全内存区域进行安全对象分配,若安全对象为托管内存类型,根据组件ID在托管内存区域分配隔离区(模拟栈),其中相同组件的托管对象将根据生命周期的长短被合理分配在模拟栈的连续空间中,随着物理栈的执行,模拟栈中的托管对象也会被动的分配和回收,相同的组件中的托管对象由于其ID一样,会在同一个模拟栈的栈顶位置为其分配空间并初始化。例如组件1中运行中多个托管对象会根据其安全对象在物理栈中的顺序相应在模拟栈中为其分配,并且会随着物理栈中安全对象的析构动态的回收模拟栈上的内存空间。此外,不同组件的托管对象由于组件ID不同,会判断是否为首次分配,如果是首次分配将重新在托管内存区域分配新的隔离区,并把托管对象分配在栈底空间并进行初始化,如果是非首次分配则找到相应的隔离区后在栈顶空间分配托管对象并进行初始化。模拟栈上托管对象的访问需要通过安全对象的托管接口进行,其数据共享也将由安全对象的Move/Borrow操作发生所有权变更,从而可以安全的访问托管对象。

本申请实施例提供的内存访问方法,把静态检测和运行时改造方案结合,划分安全内存区域和托管内存区域,在静态检测编译时约束工作人员对内存使用区域,通过运行时定制安全内存托管库,强制对托管内存区域使用必须通过托管接口访问,不引入额外的性能开销,合理平衡内存预分配与内存不足的矛盾,规避了绝大多数的内存安全问题。例如:通过内存预分配和隔离区的设置,避免了越界访问、踩内存和故障传播的问题;通过限制对象的分配回收顺序,避免了提前释放和双重释放的问题;通过限制对象的访问权限,避免了UAF的问题;通过限定托管对象和安全对象的生命周期,避免了野指针的问题;通过内存预分配避免了内存碎片和内存泄漏的问题;通过Move/Borrow所有权机制避免了并发安全的问题。

本申请实施例中,将组件中的对象分配至安全内存区域,得到安全对象,并将对象分配在托管内存区域,得到托管对象,其中安全对象为托管对象的访问接口,当对象需要访问不安全的托管内存区域时,只能通过安全对象对托管对象进行访问,从而禁止直接访问不安全的内存区域,避免导致内存错误和漏洞的产生。

以上介绍了本申请实施例提供的内存访问方法,下面结合附图介绍本申请实施例提供的相关设备。

如图8所示,本申请实施例提供的计算机设备800的一实施例包括:

获取单元801,用于获取第一组件,第一组件包括第一对象,第一组件的可用内存区域包括安全内存区域和托管内存区域;该获取单元801可以用于执行上述方法实施例中的步骤201。

分配单元802,用于将第一对象分配在安全内存区域,得到第一安全对象,并将第一对象分配在托管内存区域,得到第一托管对象,第一安全对象为第一托管对象的访问接口;该分配单元802可以用于执行上述方法实施例中的步骤202。

访问单元803,用于基于第一安全对象对第一托管对象进行访问。该访问单元803可以用于执行上述方法实施例中的步骤203。

可选的,获取单元801具体用于获取用户代码,用户代码中定义有安全托管类型,安全托管类型用于表示允许访问托管内存区域;基于用户代码生成第一组件;分配单元802具体用于当第一对象为安全托管类型时,将第一对象分配在托管内存区域。

可选的,该计算机设备800还包括提示单元804,该提示单元804用于存在不为安全托管类型的用户代码用于访问托管内存区域时,发出编译错误提示。

可选的,分配单元802具体还用于在托管内存区域为第一组件分配出第一隔离区;将第一对象分配在第一隔离区,得到第一托管对象。

可选的,第一组件还包括第二对象,分配单元802还用于将第二对象分配在安全内存区域,得到第二安全对象,并将第二对象分配在第一隔离区,得到第二托管对象;其中,第二安全对象为第二托管对象的访问接口,第二托管对象的生命周期小于第一托管对象的生命周期,第二对象的访问权限大于第一对象。

可选的,该计算机设备800还包括回收单元805,回收单元805用于当第二托管对象需要回收时,回收第二托管对象并释放第二托管对象占用的空间;当第一托管对象需要回收,且第一隔离区中只存在第一托管对象时,回收第一托管对象并释放第一隔离区占用的空间。

可选的,第一隔离区包括第一子隔离区,第一子隔离区中分配有第一子托管对象,第一子托管对象的生命周期和访问权限与第一托管对象的生命周期和访问权限相同。

可选的,获取单元801还用于获取第二组件,第二组件包括第三对象;分配单元802还用于将第三对象分配在安全内存区域,得到第三安全对象,并在托管内存区域为第二组件分配出第二隔离区,将第三对象分配在第二隔离区,得到第三托管对象;其中,第二隔离区与第一隔离区相互隔离,第三安全对象为第三托管对象的访问接口。

可选的,第一托管对象的生命周期与第一安全对象的生命周期相同。

可选的,第一安全对象具有第一托管对象的所有权变更权限。

本申请实施例提供的计算机设备800可以参阅前述内存访问方法实施例部分的相应内容进行理解,此处不再重复赘述。

图9所示,为本申请的实施例提供的计算机设备900的一种可能的逻辑结构示意图。计算机设备900包括:处理器901、通信接口902、存储器903以及总线904,该处理器901可以包括CPU,或者,CPU与GPU和NPU和其他类型的处理器中的至少一个。处理器901、通信接口902以及存储器903通过总线904相互连接。在本申请的实施例中,处理器901用于对计算机设备900的动作进行控制管理,例如,处理器901用于执行上述图2至图7部分实施例所描述的内存访问方法和/或用于本文所描述的技术的其他过程。通信接口902用于支持计算机设备900进行通信。存储器903,用于存储计算机设备900的程序代码和数据。

其中,处理器901可以是中央处理器单元,通用处理器,数字信号处理器,专用集成电路,现场可编程门阵列或者其他可编程逻辑器件、晶体管逻辑器件、硬件部件或者其任意组合。其可以实现或执行结合本申请公开内容所描述的各种示例性的逻辑方框,模块和电路。所述处理器也可以是实现计算功能的组合,例如包含一个或多个微处理器组合,数字信号处理器和微处理器的组合等等。总线904可以是外设部件互连标准(PeripheralComponent Interconnect,PCI)总线或扩展工业标准结构(Extended Industry StandardArchitecture,EISA)总线等。所述总线可以分为地址总线、数据总线、控制总线等。为便于表示,图9中仅用一条粗线表示,但并不表示仅有一根总线或一种类型的总线。

在本申请的另一实施例中,还提供一种计算机可读存储介质,计算机可读存储介质中存储有计算机执行指令,当设备的至少一个处理器执行该计算机执行指令时,设备执行上述图2至图7部分实施例所描述的内存访问方法。

在本申请的另一实施例中,还提供一种计算机程序产品,该计算机程序产品包括计算机执行指令,该计算机执行指令存储在计算机可读存储介质中;设备的至少一个处理器可以从计算机可读存储介质读取该计算机执行指令,至少一个处理器执行该计算机执行指令使得设备执行上述图2至图7部分实施例所描述的内存访问方法。

在本申请的另一实施例中,还提供一种芯片系统,该芯片系统包括至少一个处理器和接口,该接口用于接收数据和/或信号,至少一个处理器用于支持实现上述图2至图7部分实施例所描述的内存访问方法。在一种可能的设计中,芯片系统还可以包括存储器,存储器,用于保存计算机设备必要的程序指令和数据。该芯片系统,可以由芯片构成,也可以包含芯片和其他分立器件。

本领域普通技术人员可以意识到,结合本文中所公开的实施例描述的各示例的单元及算法步骤,能够以电子硬件、或者计算机软件和电子硬件的结合来实现。这些功能究竟以硬件还是软件方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本申请实施例的范围。

所属领域的技术人员可以清楚地了解到,为描述的方便和简洁,上述描述的系统,装置和单元的具体工作过程,可以参考前述方法实施例中的对应过程,在此不再赘述。

在本申请所提供的几个实施例中,应该理解到,所揭露的系统,装置和方法,可以通过其它的方式实现。例如,以上所描述的装置实施例仅仅是示意性的,例如,所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间接耦合或通信连接,可以是电性,机械或其它的形式。

所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部单元来实现本实施例方案的目的。

另外,在本申请各个实施例中的各功能单元可以集成在一个处理单元中,也可以是各个单元单独物理存在,也可以两个或两个以上单元集成在一个单元中。上述集成的单元既可以采用硬件的形式实现,也可以采用软件功能单元的形式实现。

所述集成的单元如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本申请的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的全部或部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本申请各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:U盘、移动硬盘、只读存储器(ROM,read-onlymemory)、随机存取存储器(RAM,random access memory)、磁碟或者光盘等各种可以存储程序代码的介质。

相关技术
  • 一种容器集群的应用访问方法、装置及相关设备
  • 一种内存管理方法、内存管理装置及终端设备
  • 一种在多核处理器中提升内存访问效率的方法及系统
  • 一种内存访问方法及相关设备
  • 基于网卡的内存访问方法、内存访问方法、设备及系统
技术分类

06120116623870