Botan  2.9.0
Crypto and TLS for C++11
ffi_util.h
Go to the documentation of this file.
1 /*
2 * (C) 2015,2017 Jack Lloyd
3 *
4 * Botan is released under the Simplified BSD License (see license.txt)
5 */
6 
7 #ifndef BOTAN_FFI_UTILS_H_
8 #define BOTAN_FFI_UTILS_H_
9 
10 #include <cstdint>
11 #include <memory>
12 #include <stdexcept>
13 #include <functional>
14 #include <botan/exceptn.h>
15 #include <botan/mem_ops.h>
16 
17 namespace Botan_FFI {
18 
20  {
21  public:
22  FFI_Error(const std::string& what, int err_code) :
23  Exception("FFI error", what),
24  m_err_code(err_code)
25  {}
26 
27  int error_code() const noexcept override { return m_err_code; }
28 
29  Botan::ErrorType error_type() const noexcept override { return Botan::ErrorType::InvalidArgument; }
30 
31  private:
32  int m_err_code;
33  };
34 
35 template<typename T, uint32_t MAGIC>
37  {
38  public:
39  botan_struct(T* obj) : m_magic(MAGIC), m_obj(obj) {}
40  virtual ~botan_struct() { m_magic = 0; m_obj.reset(); }
41 
42  bool magic_ok() const { return (m_magic == MAGIC); }
43 
44  T* unsafe_get() const
45  {
46  return m_obj.get();
47  }
48  private:
49  uint32_t m_magic = 0;
50  std::unique_ptr<T> m_obj;
51  };
52 
53 #define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \
54  struct NAME final : public Botan_FFI::botan_struct<TYPE, MAGIC> { explicit NAME(TYPE* x) : botan_struct(x) {} }
55 
56 // Declared in ffi.cpp
57 int ffi_error_exception_thrown(const char* func_name, const char* exn,
59 
60 template<typename T, uint32_t M>
62  {
63  if(!p)
64  throw FFI_Error("Null pointer argument", BOTAN_FFI_ERROR_NULL_POINTER);
65  if(p->magic_ok() == false)
66  throw FFI_Error("Bad magic in ffi object", BOTAN_FFI_ERROR_INVALID_OBJECT);
67 
68  if(T* t = p->unsafe_get())
69  return *t;
70 
71  throw FFI_Error("Invalid object pointer", BOTAN_FFI_ERROR_INVALID_OBJECT);
72  }
73 
74 int ffi_guard_thunk(const char* func_name, std::function<int ()>);
75 
76 template<typename T, uint32_t M, typename F>
77 int apply_fn(botan_struct<T, M>* o, const char* func_name, F func)
78  {
79  if(!o)
81 
82  if(o->magic_ok() == false)
84 
85  return ffi_guard_thunk(func_name, [&]() { return func(*o->unsafe_get()); });
86  }
87 
88 #define BOTAN_FFI_DO(T, obj, param, block) \
89  apply_fn(obj, __func__, \
90  [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; })
91 
92 template<typename T, uint32_t M>
93 int ffi_delete_object(botan_struct<T, M>* obj, const char* func_name)
94  {
95  try
96  {
97  if(obj == nullptr)
98  return BOTAN_FFI_SUCCESS; // ignore delete of null objects
99 
100  if(obj->magic_ok() == false)
102 
103  delete obj;
104  return BOTAN_FFI_SUCCESS;
105  }
106  catch(std::exception& e)
107  {
108  return ffi_error_exception_thrown(func_name, e.what());
109  }
110  catch(...)
111  {
112  return ffi_error_exception_thrown(func_name, "unknown exception");
113  }
114  }
115 
116 #define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, __func__)
117 
118 inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len)
119  {
120  if(out_len == nullptr)
122 
123  const size_t avail = *out_len;
124  *out_len = buf_len;
125 
126  if((avail >= buf_len) && (out != nullptr))
127  {
128  Botan::copy_mem(out, buf, buf_len);
129  return BOTAN_FFI_SUCCESS;
130  }
131  else
132  {
133  if(out != nullptr)
134  {
135  Botan::clear_mem(out, avail);
136  }
138  }
139  }
140 
141 template<typename Alloc>
142 int write_vec_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf)
143  {
144  return write_output(out, out_len, buf.data(), buf.size());
145  }
146 
147 inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str)
148  {
149  return write_output(out, out_len,
150  Botan::cast_char_ptr_to_uint8(str.data()),
151  str.size() + 1);
152  }
153 
154 inline int write_str_output(char out[], size_t* out_len, const std::string& str)
155  {
156  return write_str_output(Botan::cast_char_ptr_to_uint8(out), out_len, str);
157  }
158 
159 inline int write_str_output(char out[], size_t* out_len, const std::vector<uint8_t>& str_vec)
160  {
162  out_len,
163  str_vec.data(),
164  str_vec.size());
165  }
166 
167 }
168 
169 #endif
int ffi_guard_thunk(const char *func_name, std::function< int()> thunk)
Definition: ffi.cpp:81
#define BOTAN_UNSTABLE_API
Definition: compiler.h:38
virtual ~botan_struct()
Definition: ffi_util.h:40
int ffi_error_exception_thrown(const char *func_name, const char *exn, int rc)
Definition: ffi.cpp:19
FFI_Error(const std::string &what, int err_code)
Definition: ffi_util.h:22
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:111
int(* final)(unsigned char *, CTX *)
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:160
int write_vec_output(uint8_t out[], size_t *out_len, const std::vector< uint8_t, Alloc > &buf)
Definition: ffi_util.h:142
Botan::ErrorType error_type() const noexcept override
Definition: ffi_util.h:29
int error_code() const noexcept override
Definition: ffi_util.h:27
int write_str_output(uint8_t out[], size_t *out_len, const std::string &str)
Definition: ffi_util.h:147
ErrorType
Definition: exceptn.h:20
T * unsafe_get() const
Definition: ffi_util.h:44
bool magic_ok() const
Definition: ffi_util.h:42
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:122
int apply_fn(botan_struct< T, M > *o, const char *func_name, F func)
Definition: ffi_util.h:77
T & safe_get(botan_struct< T, M > *p)
Definition: ffi_util.h:61
int ffi_delete_object(botan_struct< T, M > *obj, const char *func_name)
Definition: ffi_util.h:93
fe T
Definition: ge.cpp:37
int write_output(uint8_t out[], size_t *out_len, const uint8_t buf[], size_t buf_len)
Definition: ffi_util.h:118