asherah 1.3.19 → 1.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/cobhan.cc ADDED
@@ -0,0 +1,2 @@
1
+ #include <stddef.h>
2
+ __attribute__((used)) size_t safety_padding_bytes = 0;
package/src/cobhan.h ADDED
@@ -0,0 +1,150 @@
1
+ #ifndef COBHAN_H
2
+ #define COBHAN_H
3
+ #include "logging.h"
4
+ #include <cstdint>
5
+ #include <stddef.h>
6
+ #include <string>
7
+
8
+ extern size_t safety_padding_bytes;
9
+
10
+ const size_t cobhan_header_size_bytes = 64 / 8;
11
+ const size_t canary_size = sizeof(int32_t) * 2;
12
+ const int32_t canary_constant = 0xdeadbeef;
13
+
14
+ __attribute__((always_inline)) inline void
15
+ set_safety_padding_bytes(size_t new_safety_padding_bytes) {
16
+ safety_padding_bytes = new_safety_padding_bytes;
17
+ }
18
+
19
+ __attribute__((always_inline)) inline int32_t
20
+ cbuffer_byte_length(char *cobhan_buffer) {
21
+ return *((int32_t *)cobhan_buffer);
22
+ }
23
+
24
+ __attribute__((always_inline)) inline char *
25
+ cbuffer_data_ptr(char *cobhan_buffer) {
26
+ return cobhan_buffer + cobhan_header_size_bytes;
27
+ }
28
+
29
+ __attribute__((always_inline)) inline size_t
30
+ calculate_cobhan_buffer_allocation_size(size_t data_len_bytes) {
31
+ return data_len_bytes + cobhan_header_size_bytes +
32
+ 1 + // Add one for possible NULL delimiter due to Node string functions
33
+ canary_size // Add space for canary value
34
+ + safety_padding_bytes; // Add safety padding if configured
35
+ }
36
+
37
+ __attribute__((always_inline)) inline void
38
+ configure_cbuffer(char *cobhan_buffer, size_t length) {
39
+ if (unlikely(verbose_flag)) {
40
+ debug_log("configure_cbuffer", "configure_cbuffer(" +
41
+ format_ptr(cobhan_buffer) + ", " +
42
+ std::to_string(length) + ")");
43
+ }
44
+
45
+ *((int32_t *)cobhan_buffer) = length;
46
+ // Reserved for future use
47
+ *((int32_t *)(cobhan_buffer + sizeof(int32_t))) = 0;
48
+
49
+ // Write canary values
50
+ char *data_ptr = cbuffer_data_ptr(cobhan_buffer);
51
+ #ifdef LOG_CANARY_WRITES
52
+ if (unlikely(verbose_flag)) {
53
+ debug_log("configure_cbuffer",
54
+ "Writing first canary at " + format_ptr(data_ptr + length + 1));
55
+ }
56
+ #endif
57
+
58
+ // First canary value is a int32_t 0 which gives us four NULLs
59
+ *((int32_t *)(data_ptr + length + 1)) = 0;
60
+ #ifdef LOG_CANARY_WRITES
61
+ if (unlikely(verbose_flag)) {
62
+ debug_log("configure_cbuffer",
63
+ "Writing second canary at " +
64
+ format_ptr(data_ptr + length + 1 + sizeof(int32_t)));
65
+ }
66
+ #endif
67
+
68
+ // Second canary value is a int32_t 0xdeadbeef
69
+ *((int32_t *)(data_ptr + length + 1 + sizeof(int32_t))) = canary_constant;
70
+ }
71
+
72
+ __attribute__((always_inline)) inline char *
73
+ get_canary_ptr(char *cobhan_buffer) {
74
+ int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
75
+ return cbuffer_data_ptr(cobhan_buffer) + cobhan_buffer_size_bytes + 1;
76
+ }
77
+
78
+ __attribute__((always_inline)) inline bool check_canary_ptr(char *canary_ptr) {
79
+ int32_t zero_value = *((int32_t *)(canary_ptr));
80
+ if (zero_value != 0) {
81
+ std::string error_msg =
82
+ "Canary check failed: " + std::to_string(zero_value) + " != 0";
83
+ error_log("canary_check_cbuffer", error_msg);
84
+ return false;
85
+ }
86
+ int32_t canary_value = *((int32_t *)(canary_ptr + sizeof(int32_t)));
87
+ if (canary_value != canary_constant) {
88
+ std::string error_msg =
89
+ "Canary check failed: " + std::to_string(canary_value) +
90
+ " != " + std::to_string(canary_constant);
91
+ error_log("canary_check_cbuffer", error_msg);
92
+ return false;
93
+ }
94
+ return true;
95
+ }
96
+
97
+ __attribute__((always_inline)) inline std::unique_ptr<char[]>
98
+ heap_allocate_cbuffer(const char *variable_name, size_t size_bytes) {
99
+ size_t cobhan_buffer_allocation_size =
100
+ calculate_cobhan_buffer_allocation_size(size_bytes);
101
+ if (unlikely(verbose_flag)) {
102
+ std::string log_msg =
103
+ "heap_allocate_cbuffer(" + std::to_string(size_bytes) +
104
+ ") (heap) cobhan_buffer_allocation_size: " +
105
+ std::to_string(cobhan_buffer_allocation_size) + " for " + variable_name;
106
+ debug_log("allocate_cbuffer", log_msg);
107
+ }
108
+
109
+ char *cobhan_buffer = new (std::nothrow) char[cobhan_buffer_allocation_size];
110
+ if (unlikely(cobhan_buffer == nullptr)) {
111
+ std::string error_msg = "new[" +
112
+ std::to_string(cobhan_buffer_allocation_size) +
113
+ "] returned null";
114
+ error_log("allocate_cbuffer", error_msg);
115
+ return nullptr;
116
+ }
117
+ std::unique_ptr<char[]> cobhan_buffer_unique_ptr(cobhan_buffer);
118
+ configure_cbuffer(cobhan_buffer, size_bytes + safety_padding_bytes);
119
+ return cobhan_buffer_unique_ptr;
120
+ }
121
+
122
+ #define ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, buffer_size, unique_ptr, \
123
+ function_name) \
124
+ do { \
125
+ if (buffer_size < max_stack_alloc_size) { \
126
+ /* If the buffer is small enough, allocate it on the stack */ \
127
+ size_t cobhan_buffer##_cobhan_buffer_allocation_size = \
128
+ calculate_cobhan_buffer_allocation_size(buffer_size); \
129
+ debug_log_alloca(function_name, #cobhan_buffer, \
130
+ cobhan_buffer##_cobhan_buffer_allocation_size); \
131
+ cobhan_buffer = \
132
+ (char *)alloca(cobhan_buffer##_cobhan_buffer_allocation_size); \
133
+ configure_cbuffer(cobhan_buffer, buffer_size); \
134
+ } else { \
135
+ /* Otherwise, allocate it on the heap */ \
136
+ unique_ptr = heap_allocate_cbuffer(#cobhan_buffer, buffer_size); \
137
+ cobhan_buffer = unique_ptr.get(); \
138
+ } \
139
+ if (unlikely(cobhan_buffer == nullptr)) { \
140
+ log_error_and_throw(function_name, \
141
+ "Failed to allocate " #cobhan_buffer); \
142
+ } \
143
+ } while (0);
144
+
145
+ #define ALLOCATE_CBUFFER(cobhan_buffer, buffer_size, function_name) \
146
+ std::unique_ptr<char[]> cobhan_buffer##_unique_ptr; \
147
+ ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, buffer_size, \
148
+ cobhan_buffer##_unique_ptr, function_name);
149
+
150
+ #endif
@@ -1,11 +1,2 @@
1
1
  #include <stddef.h>
2
- static size_t est_intermediate_key_overhead = 0;
3
- static size_t safety_padding_bytes = 0;
4
-
5
- size_t* get_est_intermediate_key_overhead_ptr() {
6
- return &est_intermediate_key_overhead;
7
- }
8
-
9
- size_t* get_safety_padding_bytes_ptr() {
10
- return &safety_padding_bytes;
11
- }
2
+ __attribute__((used)) size_t est_intermediate_key_overhead = 0;
@@ -1,26 +1,17 @@
1
1
  #ifndef COBHAN_NAPI_INTEROP_H
2
2
  #define COBHAN_NAPI_INTEROP_H
3
+ #include "cobhan.h"
3
4
  #include "hints.h"
4
5
  #include "logging.h"
5
6
  #include <napi.h>
6
7
  #include <string>
7
8
 
8
- // Stupid hack to get around extern issues
9
- size_t *get_est_intermediate_key_overhead_ptr();
10
- size_t *get_safety_padding_bytes_ptr();
11
-
12
- size_t *est_intermediate_key_overhead_ptr =
13
- get_est_intermediate_key_overhead_ptr();
14
- size_t *safety_padding_bytes_ptr = get_safety_padding_bytes_ptr();
9
+ extern size_t est_intermediate_key_overhead;
15
10
 
16
11
  const size_t est_encryption_overhead = 48;
17
12
  const size_t est_envelope_overhead = 185;
18
13
  const double base64_overhead = 1.34;
19
14
 
20
- const size_t cobhan_header_size_bytes = 64 / 8;
21
- const size_t canary_size = sizeof(int32_t) * 2;
22
- const int32_t canary_constant = 0xdeadbeef;
23
-
24
15
  std::string napi_status_to_string(napi_status status) {
25
16
  switch (status) {
26
17
  case napi_ok:
@@ -72,28 +63,6 @@ std::string napi_status_to_string(napi_status status) {
72
63
  }
73
64
  }
74
65
 
75
- __attribute__((always_inline)) inline int32_t
76
- cbuffer_byte_length(char *cobhan_buffer) {
77
- return *((int32_t *)cobhan_buffer);
78
- }
79
-
80
- __attribute__((always_inline)) inline Napi::Value
81
- log_error_and_throw(Napi::Env &env, const char *function_name,
82
- std::string error_msg) {
83
- error_log(function_name, error_msg);
84
- Napi::Error::New(env, function_name + (": " + error_msg))
85
- .ThrowAsJavaScriptException();
86
- return env.Null();
87
- }
88
-
89
- __attribute__((always_inline)) inline size_t
90
- calculate_cobhan_buffer_size_bytes(size_t data_len_bytes) {
91
- return data_len_bytes + cobhan_header_size_bytes +
92
- 1 + // Add one for possible NULL delimiter due to Node string functions
93
- canary_size // Add space for canary value
94
- + *safety_padding_bytes_ptr; // Add safety padding if configured
95
- }
96
-
97
66
  __attribute__((always_inline)) inline size_t
98
67
  estimate_asherah_output_size_bytes(size_t data_byte_len,
99
68
  size_t partition_byte_len) {
@@ -101,9 +70,9 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
101
70
  double est_data_byte_len =
102
71
  (double(data_byte_len + est_encryption_overhead) * base64_overhead) + 1;
103
72
 
104
- size_t asherah_output_size_bytes = size_t(
105
- est_envelope_overhead + *est_intermediate_key_overhead_ptr +
106
- partition_byte_len + est_data_byte_len + *safety_padding_bytes_ptr);
73
+ size_t asherah_output_size_bytes =
74
+ size_t(est_envelope_overhead + est_intermediate_key_overhead +
75
+ partition_byte_len + est_data_byte_len);
107
76
  if (unlikely(verbose_flag)) {
108
77
  std::string log_msg =
109
78
  "estimate_asherah_output_size(" + std::to_string(data_byte_len) + ", " +
@@ -116,118 +85,6 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
116
85
  return asherah_output_size_bytes;
117
86
  }
118
87
 
119
- __attribute__((always_inline)) inline char* cbuffer_data_ptr(char *cobhan_buffer) {
120
- return cobhan_buffer + cobhan_header_size_bytes;
121
- }
122
-
123
- __attribute__((always_inline)) inline void configure_cbuffer(char *buffer,
124
- size_t length) {
125
- if (verbose_flag) {
126
- debug_log("configure_cbuffer", "configure_cbuffer(" +
127
- std::to_string((intptr_t)buffer) + ", " +
128
- std::to_string(length) + ")");
129
- }
130
-
131
- *((int32_t *)buffer) = length;
132
- // Reserved for future use
133
- *((int32_t *)(buffer + sizeof(int32_t))) = 0;
134
-
135
- // Write canary values
136
- char *data_ptr = cbuffer_data_ptr(buffer);
137
- if (verbose_flag) {
138
- debug_log("configure_cbuffer",
139
- "Writing first canary at " +
140
- std::to_string((intptr_t)(data_ptr + length + 1)));
141
- }
142
-
143
- // First canary value is a int32_t 0 which gives us four NULLs
144
- *((int32_t *)(data_ptr + length + 1)) = 0;
145
-
146
- if (verbose_flag) {
147
- debug_log(
148
- "configure_cbuffer",
149
- "Writing second canary at " +
150
- std::to_string((intptr_t)(data_ptr + length + 1 + sizeof(int32_t))));
151
- }
152
-
153
- // Second canary value is a int32_t 0xdeadbeef
154
- *((int32_t *)(data_ptr + length + 1 + sizeof(int32_t))) = canary_constant;
155
- }
156
-
157
- __attribute__((always_inline)) inline char *
158
- get_canary_ptr(char *cobhan_buffer) {
159
- int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
160
- return cbuffer_data_ptr(cobhan_buffer) + cobhan_buffer_size_bytes + 1;
161
- }
162
-
163
- __attribute__((always_inline)) inline bool
164
- check_canary_ptr(char *canary_ptr) {
165
- int32_t zero_value = *((int32_t *)(canary_ptr));
166
- if (zero_value != 0) {
167
- std::string error_msg =
168
- "Canary check failed: " + std::to_string(zero_value) + " != 0";
169
- error_log("canary_check_cbuffer", error_msg);
170
- return false;
171
- }
172
- int32_t canary_value = *((int32_t *)(canary_ptr + sizeof(int32_t)));
173
- if (canary_value != canary_constant) {
174
- std::string error_msg =
175
- "Canary check failed: " + std::to_string(canary_value) +
176
- " != " + std::to_string(canary_constant);
177
- error_log("canary_check_cbuffer", error_msg);
178
- return false;
179
- }
180
- return true;
181
- }
182
-
183
- __attribute__((always_inline)) inline std::unique_ptr<char[]>
184
- heap_allocate_cbuffer(const char *variable_name, size_t size_bytes) {
185
- size_t cobhan_buffer_size_bytes =
186
- calculate_cobhan_buffer_size_bytes(size_bytes);
187
- if (unlikely(verbose_flag)) {
188
- std::string log_msg =
189
- "heap_allocate_cbuffer(" + std::to_string(size_bytes) +
190
- ") (heap) cobhan_buffer_size_bytes: " +
191
- std::to_string(cobhan_buffer_size_bytes) + " for " + variable_name;
192
- debug_log("allocate_cbuffer", log_msg);
193
- }
194
-
195
- char *cobhan_buffer = new (std::nothrow) char[cobhan_buffer_size_bytes];
196
- if (unlikely(cobhan_buffer == nullptr)) {
197
- std::string error_msg =
198
- "new[" + std::to_string(cobhan_buffer_size_bytes) + " returned null";
199
- error_log("allocate_cbuffer", error_msg);
200
- return nullptr;
201
- }
202
- std::unique_ptr<char[]> cobhan_buffer_unique_ptr(cobhan_buffer);
203
- configure_cbuffer(cobhan_buffer, size_bytes + *safety_padding_bytes_ptr);
204
- return cobhan_buffer_unique_ptr;
205
- }
206
-
207
- __attribute__((always_inline)) inline Napi::Value
208
- cbuffer_to_nstring(Napi::Env &env, char *cobhan_buffer) {
209
- napi_value output;
210
-
211
- int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
212
- if (cobhan_buffer_size_bytes <= 0) {
213
- return log_error_and_throw(env, "cbuffer_to_nstring",
214
- "Invalid cobhan buffer byte length");
215
- }
216
-
217
- // Using C function because it allows length delimited input
218
- napi_status status = napi_create_string_utf8(
219
- env, ((const char *)cobhan_buffer) + cobhan_header_size_bytes,
220
- cobhan_buffer_size_bytes, &output);
221
-
222
- if (unlikely(status != napi_ok)) {
223
- return log_error_and_throw(env, "cbuffer_to_nstring",
224
- "napi_create_string_utf8 failed: " +
225
- napi_status_to_string(status));
226
- }
227
-
228
- return Napi::String(env, output);
229
- }
230
-
231
88
  __attribute__((always_inline)) inline size_t
232
89
  nstring_utf8_byte_length(Napi::Env &env, Napi::String &str) {
233
90
  napi_status status;
@@ -235,9 +92,9 @@ nstring_utf8_byte_length(Napi::Env &env, Napi::String &str) {
235
92
 
236
93
  status = napi_get_value_string_utf8(env, str, nullptr, 0, &utf8_length);
237
94
  if (unlikely(status != napi_ok)) {
238
- log_error_and_throw(env, "nstring_utf8_length",
239
- "napi_get_value_string_utf8 length check failed: " +
240
- napi_status_to_string(status));
95
+ error_log("nstring_utf8_length",
96
+ "napi_get_value_string_utf8 length check failed: " +
97
+ napi_status_to_string(status));
241
98
  return (size_t)(-1);
242
99
  }
243
100
 
@@ -251,26 +108,21 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
251
108
 
252
109
  size_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
253
110
  if (unlikely(cobhan_buffer_size_bytes <= 0)) {
254
- log_error_and_throw(env, "copy_nstring_to_cbuffer",
255
- "Invalid cobhan buffer byte length");
111
+ error_log("copy_nstring_to_cbuffer", "Invalid cobhan buffer byte length");
256
112
  return nullptr;
257
113
  }
258
114
 
259
115
  if (cobhan_buffer_size_bytes < str_utf8_byte_length) {
260
- log_error_and_throw(env, "copy_nstring_to_cbuffer",
261
- "String too large for cobhan buffer");
116
+ error_log("copy_nstring_to_cbuffer", "String too large for cobhan buffer");
262
117
  return nullptr;
263
118
  }
264
119
 
265
120
  if (unlikely(verbose_flag)) {
266
121
  debug_log("copy_nstring_to_cbuffer",
267
122
  "Copying " + std::to_string(str_utf8_byte_length) + " bytes to " +
268
- std::to_string(
269
- (intptr_t)(cobhan_buffer + cobhan_header_size_bytes)) +
270
- "-" +
271
- std::to_string((intptr_t)(cobhan_buffer +
272
- cobhan_header_size_bytes +
273
- str_utf8_byte_length)));
123
+ format_ptr(cbuffer_data_ptr(cobhan_buffer)) + " - " +
124
+ format_ptr((cbuffer_data_ptr(cobhan_buffer) +
125
+ str_utf8_byte_length)));
274
126
  }
275
127
 
276
128
  napi_status status;
@@ -278,21 +130,20 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
278
130
  // NOTE: This implementation relies on the additional byte that is reserved
279
131
  // upon allocation for a NULL delimiter as methods like
280
132
  // napi_get_value_string_utf8 append a NULL delimiter
281
- status = napi_get_value_string_utf8(env, str,
282
- cobhan_buffer + cobhan_header_size_bytes,
133
+ status = napi_get_value_string_utf8(env, str, cbuffer_data_ptr(cobhan_buffer),
283
134
  str_utf8_byte_length + 1, &copied_bytes);
284
135
  if (unlikely(status != napi_ok)) {
285
- log_error_and_throw(env, "copy_nstring_to_cbuffer",
286
- "Napi utf8 string conversion failure: " +
287
- napi_status_to_string(status));
136
+ error_log("copy_nstring_to_cbuffer",
137
+ "Napi utf8 string conversion failure: " +
138
+ napi_status_to_string(status));
288
139
  return nullptr;
289
140
  }
290
141
 
291
142
  if (unlikely(copied_bytes != str_utf8_byte_length)) {
292
- log_error_and_throw(env, "copy_nstring_to_cbuffer",
293
- "Did not copy expected number of bytes " +
294
- std::to_string(str_utf8_byte_length) + " copied " +
295
- std::to_string(copied_bytes));
143
+ error_log("copy_nstring_to_cbuffer",
144
+ "Did not copy expected number of bytes " +
145
+ std::to_string(str_utf8_byte_length) + " copied " +
146
+ std::to_string(copied_bytes));
296
147
  return nullptr;
297
148
  }
298
149
 
@@ -303,36 +154,35 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
303
154
  return cobhan_buffer;
304
155
  }
305
156
 
306
- __attribute__((always_inline)) inline char *
307
- copy_nbuffer_to_cbuffer(Napi::Env &env, Napi::Buffer<unsigned char> &nbuffer,
308
- char *cobhan_buffer) {
157
+ __attribute__((always_inline)) inline Napi::String
158
+ cbuffer_to_nstring(Napi::Env &env, char *cobhan_buffer) {
159
+ napi_value output;
309
160
 
310
161
  int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
311
- if (unlikely(cobhan_buffer_size_bytes <= 0)) {
312
- log_error_and_throw(env, "copy_nbuffer_to_cbuffer",
162
+ if (cobhan_buffer_size_bytes <= 0) {
163
+ log_error_and_throw("cbuffer_to_nstring",
313
164
  "Invalid cobhan buffer byte length");
314
- return nullptr;
315
165
  }
316
166
 
317
- size_t nbuffer_byte_length = nbuffer.ByteLength();
318
- if (nbuffer_byte_length > INT32_MAX ||
319
- cobhan_buffer_size_bytes < (int32_t)nbuffer_byte_length) {
320
- log_error_and_throw(env, "copy_nbuffer_to_cbuffer",
321
- "Buffer too large for cobhan buffer");
322
- return nullptr;
167
+ // Using C function because it allows length delimited input
168
+ napi_status status = napi_create_string_utf8(
169
+ env, cbuffer_data_ptr(cobhan_buffer), cobhan_buffer_size_bytes, &output);
170
+
171
+ if (unlikely(status != napi_ok)) {
172
+ log_error_and_throw("cbuffer_to_nstring",
173
+ "napi_create_string_utf8 failed: " +
174
+ napi_status_to_string(status));
323
175
  }
324
- memcpy(cobhan_buffer + cobhan_header_size_bytes, nbuffer.Data(),
325
- nbuffer_byte_length);
326
- configure_cbuffer(cobhan_buffer, nbuffer_byte_length);
327
- return cobhan_buffer;
176
+
177
+ return Napi::String(env, output);
328
178
  }
329
179
 
330
- __attribute__((always_inline)) inline Napi::Value
180
+ __attribute__((always_inline)) inline Napi::Buffer<unsigned char>
331
181
  cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
332
182
  int32_t cobhan_buffer_byte_length = cbuffer_byte_length(cobhan_buffer);
333
183
  if (unlikely(cobhan_buffer_byte_length <= 0)) {
334
- return log_error_and_throw(env, "cbuffer_to_nbuffer",
335
- "Invalid cobhan buffer byte length");
184
+ log_error_and_throw("cbuffer_to_nbuffer",
185
+ "Invalid cobhan buffer byte length");
336
186
  }
337
187
 
338
188
  if (unlikely(verbose_flag)) {
@@ -342,12 +192,12 @@ cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
342
192
  }
343
193
 
344
194
  if (unlikely(cobhan_buffer_byte_length <= 0)) {
345
- log_error_and_throw(env, "cbuffer_to_nbuffer",
195
+ log_error_and_throw("cbuffer_to_nbuffer",
346
196
  "Invalid cobhan buffer byte length");
347
197
  }
348
198
 
349
- Napi::Buffer nbuffer = Napi::Buffer<unsigned char>::Copy(
350
- env, ((unsigned char *)cobhan_buffer) + cobhan_header_size_bytes,
199
+ Napi::Buffer<unsigned char> nbuffer = Napi::Buffer<unsigned char>::Copy(
200
+ env, (const unsigned char *)cbuffer_data_ptr(cobhan_buffer),
351
201
  cobhan_buffer_byte_length);
352
202
 
353
203
  if (unlikely(verbose_flag)) {
@@ -358,4 +208,75 @@ cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
358
208
  return nbuffer;
359
209
  }
360
210
 
211
+ __attribute__((always_inline)) inline char *
212
+ copy_nbuffer_to_cbuffer(Napi::Env &env, Napi::Buffer<unsigned char> &nbuffer,
213
+ char *cobhan_buffer) {
214
+
215
+ int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
216
+ if (unlikely(cobhan_buffer_size_bytes <= 0)) {
217
+ error_log("copy_nbuffer_to_cbuffer", "Invalid cobhan buffer byte length");
218
+ return nullptr;
219
+ }
220
+
221
+ size_t nbuffer_byte_length = nbuffer.ByteLength();
222
+ if (nbuffer_byte_length > INT32_MAX ||
223
+ cobhan_buffer_size_bytes < (int32_t)nbuffer_byte_length) {
224
+ error_log("copy_nbuffer_to_cbuffer", "Buffer too large for cobhan buffer");
225
+ return nullptr;
226
+ }
227
+ memcpy(cbuffer_data_ptr(cobhan_buffer), nbuffer.Data(), nbuffer_byte_length);
228
+ configure_cbuffer(cobhan_buffer, nbuffer_byte_length);
229
+ return cobhan_buffer;
230
+ }
231
+
232
+ // These are macros due to the use of alloca()
233
+
234
+ #define NAPI_STRING_TO_CBUFFER(env, napi_string, cobhan_buffer, bytes_copied, \
235
+ function_name) \
236
+ std::unique_ptr<char[]> napi_string##_unique_ptr; \
237
+ do { \
238
+ /* Determine size */ \
239
+ size_t napi_string##_utf8_byte_length = \
240
+ nstring_utf8_byte_length(env, napi_string); \
241
+ if (unlikely(napi_string##_utf8_byte_length == (size_t)(-1))) { \
242
+ log_error_and_throw(function_name, \
243
+ "Failed to get " #napi_string " utf8 length"); \
244
+ } \
245
+ if (unlikely(napi_string##_utf8_byte_length == 0)) { \
246
+ log_error_and_throw(function_name, #napi_string " is empty"); \
247
+ } \
248
+ /* Allocate */ \
249
+ ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, napi_string##_utf8_byte_length, \
250
+ napi_string##_unique_ptr, function_name); \
251
+ /* Copy */ \
252
+ cobhan_buffer = copy_nstring_to_cbuffer(env, napi_string, \
253
+ napi_string##_utf8_byte_length, \
254
+ cobhan_buffer, &bytes_copied); \
255
+ if (unlikely(cobhan_buffer == nullptr)) { \
256
+ log_error_and_throw(function_name, \
257
+ "Failed to copy " #napi_string " to cobhan buffer"); \
258
+ } \
259
+ } while (0);
260
+
261
+ #define NAPI_BUFFER_TO_CBUFFER(env, napi_buffer, cobhan_buffer, bytes_copied, \
262
+ function_name) \
263
+ std::unique_ptr<char[]> napi_buffer##_unique_ptr; \
264
+ do { \
265
+ /* Determine size */ \
266
+ size_t napi_buffer##_byte_length = napi_buffer.ByteLength(); \
267
+ if (unlikely(napi_buffer##_byte_length == 0)) { \
268
+ log_error_and_throw(function_name, #napi_buffer " is empty"); \
269
+ } \
270
+ /* Allocate */ \
271
+ ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, napi_buffer##_byte_length, \
272
+ napi_buffer##_unique_ptr, function_name); \
273
+ /* Copy */ \
274
+ cobhan_buffer = copy_nbuffer_to_cbuffer(env, napi_buffer, cobhan_buffer); \
275
+ if (unlikely(cobhan_buffer == nullptr)) { \
276
+ log_error_and_throw(function_name, \
277
+ "Failed to copy " #napi_buffer " to cobhan buffer"); \
278
+ } \
279
+ bytes_copied = napi_buffer##_byte_length; \
280
+ } while (0);
281
+
361
282
  #endif
package/src/logging.cc CHANGED
@@ -1,2 +1,2 @@
1
1
  #include <cstdint>
2
- int32_t verbose_flag = 0;
2
+ __attribute__((used)) int32_t verbose_flag = 0;
package/src/logging.h CHANGED
@@ -2,11 +2,22 @@
2
2
  #define LOGGING_H
3
3
  #include "hints.h"
4
4
  #include <cstdint>
5
- #include <string>
5
+ #include <iomanip>
6
6
  #include <iostream>
7
+ #include <sstream>
8
+ #include <string>
7
9
 
8
10
  extern int32_t verbose_flag;
9
11
 
12
+ __attribute__((always_inline)) inline void debug_log(const char *function_name,
13
+ const char *message) {
14
+ if (unlikely(verbose_flag)) {
15
+ std::cerr << "asherah-node: [DEBUG] " << function_name << ": " << message
16
+ << std::endl
17
+ << std::flush;
18
+ }
19
+ }
20
+
10
21
  __attribute__((always_inline)) inline void debug_log(const char *function_name,
11
22
  std::string message) {
12
23
  if (unlikely(verbose_flag)) {
@@ -27,6 +38,15 @@ debug_log_alloca(const char *function_name, const char *variable_name,
27
38
  }
28
39
  }
29
40
 
41
+ __attribute__((always_inline)) inline void error_log(const char *function_name,
42
+ const char *message) {
43
+ if (unlikely(verbose_flag)) {
44
+ std::cerr << "asherah-node: [ERROR] " << function_name << ": " << message
45
+ << std::endl
46
+ << std::flush;
47
+ }
48
+ }
49
+
30
50
  __attribute__((always_inline)) inline void error_log(const char *function_name,
31
51
  std::string message) {
32
52
  if (unlikely(verbose_flag)) {
@@ -36,4 +56,16 @@ __attribute__((always_inline)) inline void error_log(const char *function_name,
36
56
  }
37
57
  }
38
58
 
59
+ __attribute__((always_inline)) inline std::string format_ptr(char *ptr) {
60
+ std::ostringstream ss;
61
+ ss << "0x" << std::hex << (intptr_t)ptr;
62
+ return ss.str();
63
+ }
64
+
65
+ __attribute__((always_inline, noreturn)) inline void
66
+ log_error_and_throw(const char *function_name, std::string error_msg) {
67
+ error_log(function_name, error_msg);
68
+ throw new std::runtime_error(function_name + (": " + error_msg));
69
+ }
70
+
39
71
  #endif