2020#include < optional>
2121#include < string>
2222#include < utility>
23+ #include < variant>
2324#include < vector>
2425
2526#include " absl/container/flat_hash_set.h"
27+ #include " absl/functional/overload.h"
2628#include " absl/log/log.h"
2729#include " absl/status/status.h"
2830#include " absl/status/statusor.h"
@@ -61,8 +63,10 @@ constexpr absl::string_view kWrapperPrefix = "sapi_wrapper_";
6163// This can be used to strip the annotations from the input string.
6264std::string StripAnnotations (const std::string& input) {
6365 static const auto * macros_no_args = new std::vector<std::string>{
64- " SANDBOX_IN_PTR" , " SANDBOX_OUT_PTR" , " SANDBOX_INOUT_PTR" ,
65- " SANDBOX_OPAQUE_PTR" , " SANDBOX_HOST_OPAQUE_PTR" , " SANDBOX_HOST_STATE_VAR" ,
66+ " SANDBOX_IN_PTR" , " SANDBOX_OUT_PTR" ,
67+ " SANDBOX_INOUT_PTR" , " SANDBOX_OPAQUE_PTR" ,
68+ " SANDBOX_HOST_OPAQUE_PTR" , " SANDBOX_HOST_STATE_VAR" ,
69+ " SANDBOX_NULL_TERMINATED" ,
6670 };
6771 std::string output = input;
6872 for (const auto & macro : *macros_no_args) {
@@ -339,6 +343,29 @@ struct StringViewArg : SandboxedLibraryEmitter::Arg {
339343 }
340344};
341345
346+ // A null-terminated C string. These are always "input" to the library.
347+ struct ConstCStrArg : SandboxedLibraryEmitter::Arg {
348+ ConstCStrArg (absl::string_view name, PointerDir ptr_dir)
349+ : Arg(name, " const char*" ) {
350+ if (ptr_dir != PointerDir::kIn ) {
351+ LOG (FATAL) << " ConstCStrArg pointer direction must be kIn" ;
352+ }
353+ }
354+
355+ std::string EmitHostPreCall () const override {
356+ return absl::Substitute (" sapi::v::ConstCStr sapi_tmp_$0($0);\n " , name_);
357+ }
358+ std::string EmitHostArgs () const override {
359+ return absl::Substitute (" sapi_tmp_$0.PtrBefore()" , name_);
360+ }
361+ std::string EmitSandboxeeParams () const override {
362+ return absl::Substitute (" $0 $1" , type_, name_);
363+ }
364+ std::string EmitSandboxeeArgs () const override {
365+ return absl::Substitute (" $0" , name_);
366+ }
367+ };
368+
342369// Handles in/out/inout pointers (singular and arrays).
343370struct PointerArg : SandboxedLibraryEmitter::Arg {
344371 PointerArg (absl::string_view name, absl::string_view type, PointerDir ptr_dir,
@@ -1090,8 +1117,14 @@ SandboxedLibraryEmitter::ConvertImpl(absl::string_view name,
10901117 // Check whether this pointer even needs syncing or is an opaque handle.
10911118 if (annotations.ptr_dir == PointerDir::kSandboxOpaque ||
10921119 annotations.ptr_dir == PointerDir::kHostOpaque ) {
1120+ // Shouldn't be elem_sized_by or null_terminated.
1121+ if (!std::holds_alternative<std::monostate>(annotations.size_type )) {
1122+ return absl::InvalidArgumentError (absl::Substitute (
1123+ " pointer argument $0 is opaque and should not be sized (kind $1)" ,
1124+ name, annotations.size_type .index ()));
1125+ }
10931126 return std::make_unique<PointerArg>(name, type_name, *annotations.ptr_dir ,
1094- annotations. elem_sized_by );
1127+ std:: nullopt );
10951128 }
10961129
10971130 if (!type->getPointeeType ()->isArithmeticType ()) {
@@ -1109,8 +1142,36 @@ SandboxedLibraryEmitter::ConvertImpl(absl::string_view name,
11091142 return absl::InvalidArgumentError (
11101143 absl::Substitute (" pointer argument $0 has unknown direction" , name));
11111144 }
1112- return std::make_unique<PointerArg>(name, type_name, *ptr_dir,
1113- annotations.elem_sized_by );
1145+ return std::visit (
1146+ absl::Overload{[&](const std::monostate&)
1147+ -> absl::StatusOr<SandboxedLibraryEmitter::ArgPtr> {
1148+ return std::make_unique<PointerArg>(
1149+ name, type_name, *ptr_dir, std::nullopt );
1150+ },
1151+ [&](const ElemSizedBy& elem_sized_by)
1152+ -> absl::StatusOr<SandboxedLibraryEmitter::ArgPtr> {
1153+ return std::make_unique<PointerArg>(
1154+ name, type_name, *ptr_dir, elem_sized_by.expr );
1155+ },
1156+ [&](const NullTerminated&)
1157+ -> absl::StatusOr<SandboxedLibraryEmitter::ArgPtr> {
1158+ if (ptr_dir != PointerDir::kIn ) {
1159+ return absl::InvalidArgumentError (absl::Substitute (
1160+ " pointer argument $0 is null-terminated but not "
1161+ " an input pointer ($1)" ,
1162+ name, *ptr_dir));
1163+ }
1164+ // For now only handle `const char*` (vs `char*`)
1165+ if (!type->getPointeeType ()->isCharType () ||
1166+ !type->getPointeeType ().isConstQualified ()) {
1167+ return absl::InvalidArgumentError (absl::Substitute (
1168+ " pointer argument $0 is null-terminated but not "
1169+ " a const char*" ,
1170+ name));
1171+ }
1172+ return std::make_unique<ConstCStrArg>(name, *ptr_dir);
1173+ }},
1174+ annotations.size_type );
11141175 }
11151176 return nullptr ;
11161177}
@@ -1173,9 +1234,19 @@ SandboxedLibraryEmitter::ParseAnnotations(absl::string_view name,
11731234 annotations.ptr_dir = PointerDir::kHostOpaque ;
11741235 } else if (ann.name == " elem_sized_by" ) {
11751236 num_args = 2 ;
1237+ if (!std::holds_alternative<std::monostate>(annotations.size_type )) {
1238+ return absl::InvalidArgumentError (absl::Substitute (
1239+ " arg $0: cannot be both null-terminated and elem_sized_by" , name));
1240+ }
11761241 if (!ann.args .empty ()) {
1177- annotations.elem_sized_by = ann.args [0 ];
1242+ annotations.size_type = ElemSizedBy{ann.args [0 ]};
1243+ }
1244+ } else if (ann.name == " null_terminated" ) {
1245+ if (!std::holds_alternative<std::monostate>(annotations.size_type )) {
1246+ return absl::InvalidArgumentError (absl::Substitute (
1247+ " arg $0: cannot be both null-terminated and elem_sized_by" , name));
11781248 }
1249+ annotations.size_type = NullTerminated{};
11791250 } else {
11801251 num_args = 0 ;
11811252 }
0 commit comments