Botan  2.18.1
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  T* p = o->unsafe_get();
86  if(p == nullptr)
88 
89  return ffi_guard_thunk(func_name, [&]() { return func(*p); });
90  }
91 
92 #define BOTAN_FFI_DO(T, obj, param, block) \
93  apply_fn(obj, __func__, \
94  [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; })
95 
96 /*
97 * Like BOTAN_FFI_DO but with no trailing return with the expectation
98 * that the block always returns a value. This exists because otherwise
99 * MSVC warns about the dead return after the block in FFI_DO.
100 */
101 #define BOTAN_FFI_RETURNING(T, obj, param, block) \
102  apply_fn(obj, __func__, \
103  [=](T& param) -> int { do { block } while(0); })
104 
105 template<typename T, uint32_t M>
106 int ffi_delete_object(botan_struct<T, M>* obj, const char* func_name)
107  {
108  try
109  {
110  if(obj == nullptr)
111  return BOTAN_FFI_SUCCESS; // ignore delete of null objects
112 
113  if(obj->magic_ok() == false)
115 
116  delete obj;
117  return BOTAN_FFI_SUCCESS;
118  }
119  catch(std::exception& e)
120  {
121  return ffi_error_exception_thrown(func_name, e.what());
122  }
123  catch(...)
124  {
125  return ffi_error_exception_thrown(func_name, "unknown exception");
126  }
127  }
128 
129 #define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, __func__)
130 
131 inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len)
132  {
133  if(out_len == nullptr)
135 
136  const size_t avail = *out_len;
137  *out_len = buf_len;
138 
139  if((avail >= buf_len) && (out != nullptr))
140  {
141  Botan::copy_mem(out, buf, buf_len);
142  return BOTAN_FFI_SUCCESS;
143  }
144  else
145  {
146  if(out != nullptr)
147  {
148  Botan::clear_mem(out, avail);
149  }
151  }
152  }
153 
154 template<typename Alloc>
155 int write_vec_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf)
156  {
157  return write_output(out, out_len, buf.data(), buf.size());
158  }
159 
160 inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str)
161  {
162  return write_output(out, out_len,
163  Botan::cast_char_ptr_to_uint8(str.data()),
164  str.size() + 1);
165  }
166 
167 inline int write_str_output(char out[], size_t* out_len, const std::string& str)
168  {
169  return write_str_output(Botan::cast_char_ptr_to_uint8(out), out_len, str);
170  }
171 
172 inline int write_str_output(char out[], size_t* out_len, const std::vector<uint8_t>& str_vec)
173  {
175  out_len,
176  str_vec.data(),
177  str_vec.size());
178  }
179 
180 }
181 
182 #endif
int ffi_guard_thunk(const char *func_name, std::function< int()> thunk)
Definition: ffi.cpp:89
#define BOTAN_UNSTABLE_API
Definition: compiler.h:44
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:115
int(* final)(unsigned char *, CTX *)
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:190
int write_vec_output(uint8_t out[], size_t *out_len, const std::vector< uint8_t, Alloc > &buf)
Definition: ffi_util.h:155
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:160
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:133
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:106
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:131