简介
如概览页面中所述,宿主代码会向沙盒库发出 RPC 调用。沙盒化会导致进程之间的内存分离,因此宿主代码无法直接访问沙盒化库中的内存。
为了确保宿主代码可以访问远程进程中的变量和内存块,并简化主逻辑代码的实现,SAPI 提供了一套全面的 C++ 类。不过,在许多情况下,您也可以使用原生 C 类型。
当将指针传递给简单类型和内存块(结构、数组)时,就需要使用特殊类型(SAPI 类型)。
例如,在调用接受指针的函数时,必须将指针转换为沙盒库内存中的相应指针。以下代码段直观地展示了此情形。系统会创建一个 ::sapi::v::Array<int>
对象,而不是一个包含三个整数的数组,然后该对象可以传递到沙盒库的 API 调用中:
int arr[3] = {1, 2, 3};
sapi::v::Array<int> sarr(arr, ABSL_ARRAYSIZE(arr));
如需全面了解所有可用的 SAPI 类型,请查看 SAPI 项目源代码中的 var_*.h
头文件。这些头文件提供了表示各种类型数据的类和模板,例如:
::sapi::v::UChar
表示常用的无符号字符::sapi::v::Array<int>
表示一个整数数组
SAPI 类型
本部分将介绍主机代码中常见的三种 SAPI 类型。
SAPI 指针
如果需要沙盒化的函数需要传递指针,则应通过以下 PtrXXX()
方法之一获取此指针。这些方法由 SAPI 变量类实现。
指针类型 | |
---|---|
::PtrNone() |
当传递给沙盒 API 函数时,不会在宿主代码进程和沙盒库进程之间同步底层内存。 |
::PtrBefore() |
在沙盒 API 函数调用发生之前,同步其指向对象的内存。 这意味着,在发起调用之前,所指向变量的本地内存将转移到沙盒库进程。 |
::PtrAfter() |
在沙盒 API 函数调用发生后,同步其指向的对象的内存。 这意味着,在调用完成后,所指向变量的远程内存将转移到主机代码进程内存中。 |
::PtrBoth() |
结合了 ::PtrBefore() 和 ::PtrAfter() 的功能。 |
如需查看 SAPI 指针的相关文档,请点击此处。
SAPI 结构体
模板 ::sapi::v::Struct
已在 var_struct.h 中记录。它提供了一个可用于封装现有结构的构造函数。SAPI 结构体提供了 SAPI 指针中概述的所有方法,用于获取可用于沙盒库调用的 ::sapi::v::Ptr
对象。
以下代码段展示了在 zlib 示例中,如何初始化一个结构,然后将其传递给沙盒函数调用:
sapi::v::Struct<sapi::zlib::z_stream> strm;
…
if (ret = api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
version.PtrBefore(), sizeof(sapi::zlib::z_stream));
…
如果现有结构体包含指针,则这些指针将指向 Sandboxee 中的地址。因此,您必须先转移 Sandboxee 数据,然后才能让宿主代码访问该数据。
SAPI 数组
模板 ::sapi::v::Array
的相关文档位于 var_array.h 中。它提供两个构造函数,一个可用于封装现有元素数组,另一个可用于动态创建数组。
以下代码段(摘自 sum 示例)展示了如何使用封装了不归此对象所有的数组的构造函数:
int arr[10];
sapi::v::Array<int> iarr(arr, ABSL_ARRAYSIZE(arr));
以下代码段展示了用于动态创建数组的构造函数示例:
sapi::v::Array<uint8_t> buffer(PNG_IMAGE_SIZE(*image.mutable_data()));
SAPI 数组提供了 SAPI 指针中概述的所有方法,以获取可用于沙盒库调用的 ::sapi::v::Ptr
对象。