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/binding.gyp +6 -3
- package/package.json +3 -1
- package/scripts/download-libraries.sh +4 -4
- package/src/asherah.cc +162 -529
- package/src/cobhan.cc +2 -0
- package/src/cobhan.h +150 -0
- package/src/cobhan_napi_interop.cc +1 -10
- package/src/cobhan_napi_interop.h +113 -192
- package/src/logging.cc +1 -1
- package/src/logging.h +33 -1
package/src/cobhan.cc
ADDED
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
|
-
|
|
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
|
-
|
|
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 =
|
|
105
|
-
est_envelope_overhead +
|
|
106
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
269
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
|
307
|
-
|
|
308
|
-
|
|
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 (
|
|
312
|
-
log_error_and_throw(
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
325
|
-
|
|
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::
|
|
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
|
-
|
|
335
|
-
|
|
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(
|
|
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, (
|
|
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 <
|
|
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
|