Variables Guide

Introduction

As explained on the Overview page, the Host Code makes RPC calls to the Sandboxed Library. Sandboxing results in a memory separation between the processes, and thus the Host Code cannot directly access memory in the Sandboxed Library.

In order to make sure that the Host Code can access variables and memory blocks in a remote process and to make the implementation of the main logic code simpler, SAPI provides a comprehensive set of C++ classes. However, in many cases you will also be able to use native C-types.

The need for the special types (SAPI Types) arises when passing pointers to simple types and memory blocks (structures, arrays).

For example, when calling a function taking a pointer, the pointer must be converted into a corresponding pointer inside the Sandboxed Library's memory. The below code snippet visualises this scenario. Instead of an array of three integers, a ::sapi::v::Array<int> object is created which can then be passed in the Sandboxed Library's API call:

int arr[3] = {1, 2, 3};
sapi::v::Array<int> sarr(arr, ABSL_ARRAYSIZE(arr));

For a comprehensive overview of all available SAPI Types, review the var_*.h header files in the SAPI project source code. These header files provide classes and templates representing various types of data, e.g.:

  • ::sapi::v::UChar represents well-known unsigned chars
  • ::sapi::v::Array<int> represents an array of integers

SAPI Types

This section introduces three SAPI Types that are commonly seen in Host Code.

SAPI Pointers

If a function to be sandboxed requires passing a pointer, this pointer should be obtained from one of the PtrXXX() methods below. These methods are implemented by the SAPI variable classes.

Pointer Types
::PtrNone() Doesn't synchronize the underlying memory between the Host Code process and the Sandboxed Library process when passed to a sandboxed API function.
::PtrBefore() Synchronizes the memory of the object it points to before the sandboxed API function call takes place. This means the local memory of the pointed variable will be transferred to the Sandboxed Library process before the call is initiated.
::PtrAfter() Synchronizes the memory of the object it points to after the sandboxed API function call takes place. This means the remote memory of the pointed variable will be transferred to the Host Code process memory after the call has been completed.
::PtrBoth() Combines the functionality of ::PtrBefore() and ::PtrAfter().

The documentation for SAPI pointers can be found here.

SAPI Struct

The template ::sapi::v::Struct is documented in var_struct.h. It provides a constructor that can be used to wrap existing structures. SAPI Struct provides all methods outlined in SAPI Pointers to obtain a ::sapi::v::Ptr object that can be used for sandboxed library calls.

The code snippet below shows a structure being initiated and then passed to a sandboxed function call in the zlib example:

sapi::v::Struct<sapi::zlib::z_stream> strm;
…
if (ret = api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
                             version.PtrBefore(), sizeof(sapi::zlib::z_stream));
…

If your existing struct contains pointers, then those pointers will point to addresses in the Sandboxee. In consequence, you will have to transfer Sandboxee data before it becomes accessible to the Host Code.

SAPI Arrays

The template ::sapi::v::Array is documented in var_array.h. It provides two constructors, one that can be used to wrap existing arrays of elements, and another one to dynamically create an array.

This code snippet (taken from the sum example) shows the use of the constructor that wraps around an array which is not owned by this object:

int arr[10];
sapi::v::Array<int> iarr(arr, ABSL_ARRAYSIZE(arr));

This code snippet shows an example of the constructor used to dynamically create an array:

sapi::v::Array<uint8_t> buffer(PNG_IMAGE_SIZE(*image.mutable_data()));

SAPI Array provides all methods outlined in SAPI Pointers to obtain a ::sapi::v::Ptr object that can be used for sandboxed library calls.