GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
// Copyright Joyent, Inc. and other Node contributors. |
||
2 |
// |
||
3 |
// Permission is hereby granted, free of charge, to any person obtaining a |
||
4 |
// copy of this software and associated documentation files (the |
||
5 |
// "Software"), to deal in the Software without restriction, including |
||
6 |
// without limitation the rights to use, copy, modify, merge, publish, |
||
7 |
// distribute, sublicense, and/or sell copies of the Software, and to permit |
||
8 |
// persons to whom the Software is furnished to do so, subject to the |
||
9 |
// following conditions: |
||
10 |
// |
||
11 |
// The above copyright notice and this permission notice shall be included |
||
12 |
// in all copies or substantial portions of the Software. |
||
13 |
// |
||
14 |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
15 |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
16 |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
||
17 |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||
18 |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
19 |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
20 |
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
21 |
|||
22 |
#include "base_object-inl.h" |
||
23 |
#include "memory_tracker-inl.h" |
||
24 |
#include "node_crypto_bio.h" |
||
25 |
#include "openssl/bio.h" |
||
26 |
#include "util-inl.h" |
||
27 |
#include <climits> |
||
28 |
#include <cstring> |
||
29 |
|||
30 |
namespace node { |
||
31 |
namespace crypto { |
||
32 |
|||
33 |
67972 |
BIOPointer NodeBIO::New(Environment* env) { |
|
34 |
67972 |
BIOPointer bio(BIO_new(GetMethod())); |
|
35 |
✓✗✓✓ ✓✓ |
67972 |
if (bio && env != nullptr) |
36 |
24470 |
NodeBIO::FromBIO(bio.get())->env_ = env; |
|
37 |
67972 |
return bio; |
|
38 |
} |
||
39 |
|||
40 |
|||
41 |
43502 |
BIOPointer NodeBIO::NewFixed(const char* data, size_t len, Environment* env) { |
|
42 |
43502 |
BIOPointer bio = New(env); |
|
43 |
|||
44 |
✓✗✗✓ |
130506 |
if (!bio || |
45 |
✓✗ | 43502 |
len > INT_MAX || |
46 |
✓✗✗✓ |
130506 |
BIO_write(bio.get(), data, len) != static_cast<int>(len) || |
47 |
43502 |
BIO_set_mem_eof_return(bio.get(), 0) != 1) { |
|
48 |
return BIOPointer(); |
||
49 |
} |
||
50 |
|||
51 |
43502 |
return bio; |
|
52 |
} |
||
53 |
|||
54 |
|||
55 |
67972 |
int NodeBIO::New(BIO* bio) { |
|
56 |
67972 |
BIO_set_data(bio, new NodeBIO()); |
|
57 |
67972 |
BIO_set_init(bio, 1); |
|
58 |
|||
59 |
67972 |
return 1; |
|
60 |
} |
||
61 |
|||
62 |
|||
63 |
67936 |
int NodeBIO::Free(BIO* bio) { |
|
64 |
✗✓ | 67936 |
if (bio == nullptr) |
65 |
return 0; |
||
66 |
|||
67 |
✓✗ | 67936 |
if (BIO_get_shutdown(bio)) { |
68 |
✓✗✓✗ ✓✗ |
67936 |
if (BIO_get_init(bio) && BIO_get_data(bio) != nullptr) { |
69 |
✓✗ | 67936 |
delete FromBIO(bio); |
70 |
67936 |
BIO_set_data(bio, nullptr); |
|
71 |
} |
||
72 |
} |
||
73 |
|||
74 |
67936 |
return 1; |
|
75 |
} |
||
76 |
|||
77 |
|||
78 |
49976 |
int NodeBIO::Read(BIO* bio, char* out, int len) { |
|
79 |
49976 |
BIO_clear_retry_flags(bio); |
|
80 |
|||
81 |
49976 |
NodeBIO* nbio = FromBIO(bio); |
|
82 |
49976 |
int bytes = nbio->Read(out, len); |
|
83 |
|||
84 |
✓✓ | 49976 |
if (bytes == 0) { |
85 |
10055 |
bytes = nbio->eof_return(); |
|
86 |
✓✓ | 10055 |
if (bytes != 0) { |
87 |
10053 |
BIO_set_retry_read(bio); |
|
88 |
} |
||
89 |
} |
||
90 |
|||
91 |
49976 |
return bytes; |
|
92 |
} |
||
93 |
|||
94 |
|||
95 |
20 |
char* NodeBIO::Peek(size_t* size) { |
|
96 |
20 |
*size = read_head_->write_pos_ - read_head_->read_pos_; |
|
97 |
20 |
return read_head_->data_ + read_head_->read_pos_; |
|
98 |
} |
||
99 |
|||
100 |
|||
101 |
6480 |
size_t NodeBIO::PeekMultiple(char** out, size_t* size, size_t* count) { |
|
102 |
6480 |
Buffer* pos = read_head_; |
|
103 |
6480 |
size_t max = *count; |
|
104 |
6480 |
size_t total = 0; |
|
105 |
|||
106 |
size_t i; |
||
107 |
✓✓ | 13422 |
for (i = 0; i < max; i++) { |
108 |
12798 |
size[i] = pos->write_pos_ - pos->read_pos_; |
|
109 |
12798 |
total += size[i]; |
|
110 |
12798 |
out[i] = pos->data_ + pos->read_pos_; |
|
111 |
|||
112 |
/* Don't get past write head */ |
||
113 |
✓✓ | 12798 |
if (pos == write_head_) |
114 |
5856 |
break; |
|
115 |
else |
||
116 |
6942 |
pos = pos->next_; |
|
117 |
} |
||
118 |
|||
119 |
✓✓ | 6480 |
if (i == max) |
120 |
624 |
*count = i; |
|
121 |
else |
||
122 |
5856 |
*count = i + 1; |
|
123 |
|||
124 |
6480 |
return total; |
|
125 |
} |
||
126 |
|||
127 |
|||
128 |
59657 |
int NodeBIO::Write(BIO* bio, const char* data, int len) { |
|
129 |
59657 |
BIO_clear_retry_flags(bio); |
|
130 |
|||
131 |
59657 |
FromBIO(bio)->Write(data, len); |
|
132 |
|||
133 |
59657 |
return len; |
|
134 |
} |
||
135 |
|||
136 |
|||
137 |
int NodeBIO::Puts(BIO* bio, const char* str) { |
||
138 |
return Write(bio, str, strlen(str)); |
||
139 |
} |
||
140 |
|||
141 |
|||
142 |
996970 |
int NodeBIO::Gets(BIO* bio, char* out, int size) { |
|
143 |
996970 |
NodeBIO* nbio = FromBIO(bio); |
|
144 |
|||
145 |
✓✓ | 996970 |
if (nbio->Length() == 0) |
146 |
1378 |
return 0; |
|
147 |
|||
148 |
995592 |
int i = nbio->IndexOf('\n', size); |
|
149 |
|||
150 |
// Include '\n', if it's there. If not, don't read off the end. |
||
151 |
✓✗✓✗ ✓✓✓✓ |
995592 |
if (i < size && i >= 0 && static_cast<size_t>(i) < nbio->Length()) |
152 |
954304 |
i++; |
|
153 |
|||
154 |
// Shift `i` a bit to nullptr-terminate string later |
||
155 |
✗✓ | 995592 |
if (size == i) |
156 |
i--; |
||
157 |
|||
158 |
// Flush read data |
||
159 |
995592 |
nbio->Read(out, i); |
|
160 |
|||
161 |
995592 |
out[i] = 0; |
|
162 |
|||
163 |
995592 |
return i; |
|
164 |
} |
||
165 |
|||
166 |
|||
167 |
71437 |
long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) |
|
168 |
void* ptr) { |
||
169 |
NodeBIO* nbio; |
||
170 |
long ret; // NOLINT(runtime/int) |
||
171 |
|||
172 |
71437 |
nbio = FromBIO(bio); |
|
173 |
71437 |
ret = 1; |
|
174 |
|||
175 |
✗✗✓✗ ✗✗✗✗ ✗✓✓✓ |
71437 |
switch (cmd) { |
176 |
case BIO_CTRL_RESET: |
||
177 |
nbio->Reset(); |
||
178 |
break; |
||
179 |
case BIO_CTRL_EOF: |
||
180 |
ret = nbio->Length() == 0; |
||
181 |
break; |
||
182 |
case BIO_C_SET_BUF_MEM_EOF_RETURN: |
||
183 |
43502 |
nbio->set_eof_return(num); |
|
184 |
43502 |
break; |
|
185 |
case BIO_CTRL_INFO: |
||
186 |
ret = nbio->Length(); |
||
187 |
if (ptr != nullptr) |
||
188 |
*reinterpret_cast<void**>(ptr) = nullptr; |
||
189 |
break; |
||
190 |
case BIO_C_SET_BUF_MEM: |
||
191 |
CHECK(0 && "Can't use SET_BUF_MEM_PTR with NodeBIO"); |
||
192 |
break; |
||
193 |
case BIO_C_GET_BUF_MEM_PTR: |
||
194 |
CHECK(0 && "Can't use GET_BUF_MEM_PTR with NodeBIO"); |
||
195 |
ret = 0; |
||
196 |
break; |
||
197 |
case BIO_CTRL_GET_CLOSE: |
||
198 |
ret = BIO_get_shutdown(bio); |
||
199 |
break; |
||
200 |
case BIO_CTRL_SET_CLOSE: |
||
201 |
BIO_set_shutdown(bio, num); |
||
202 |
break; |
||
203 |
case BIO_CTRL_WPENDING: |
||
204 |
ret = 0; |
||
205 |
break; |
||
206 |
case BIO_CTRL_PENDING: |
||
207 |
16954 |
ret = nbio->Length(); |
|
208 |
16954 |
break; |
|
209 |
case BIO_CTRL_DUP: |
||
210 |
case BIO_CTRL_FLUSH: |
||
211 |
5238 |
ret = 1; |
|
212 |
5238 |
break; |
|
213 |
case BIO_CTRL_PUSH: |
||
214 |
case BIO_CTRL_POP: |
||
215 |
default: |
||
216 |
5743 |
ret = 0; |
|
217 |
5743 |
break; |
|
218 |
} |
||
219 |
71437 |
return ret; |
|
220 |
} |
||
221 |
|||
222 |
|||
223 |
68646 |
const BIO_METHOD* NodeBIO::GetMethod() { |
|
224 |
// This is called from InitCryptoOnce() to avoid race conditions during |
||
225 |
// initialization. |
||
226 |
static BIO_METHOD* method = nullptr; |
||
227 |
|||
228 |
✓✓ | 68646 |
if (method == nullptr) { |
229 |
675 |
method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer"); |
|
230 |
675 |
BIO_meth_set_write(method, Write); |
|
231 |
675 |
BIO_meth_set_read(method, Read); |
|
232 |
675 |
BIO_meth_set_puts(method, Puts); |
|
233 |
675 |
BIO_meth_set_gets(method, Gets); |
|
234 |
675 |
BIO_meth_set_ctrl(method, Ctrl); |
|
235 |
675 |
BIO_meth_set_create(method, New); |
|
236 |
675 |
BIO_meth_set_destroy(method, Free); |
|
237 |
} |
||
238 |
|||
239 |
68646 |
return method; |
|
240 |
} |
||
241 |
|||
242 |
|||
243 |
1060768 |
void NodeBIO::TryMoveReadHead() { |
|
244 |
// `read_pos_` and `write_pos_` means the position of the reader and writer |
||
245 |
// inside the buffer, respectively. When they're equal - its safe to reset |
||
246 |
// them, because both reader and writer will continue doing their stuff |
||
247 |
// from new (zero) positions. |
||
248 |
✓✓✓✓ |
3233189 |
while (read_head_->read_pos_ != 0 && |
249 |
1048123 |
read_head_->read_pos_ == read_head_->write_pos_) { |
|
250 |
// Reset positions |
||
251 |
63530 |
read_head_->read_pos_ = 0; |
|
252 |
63530 |
read_head_->write_pos_ = 0; |
|
253 |
|||
254 |
// Move read_head_ forward, just in case if there're still some data to |
||
255 |
// read in the next buffer. |
||
256 |
✓✓ | 63530 |
if (read_head_ != write_head_) |
257 |
9299 |
read_head_ = read_head_->next_; |
|
258 |
} |
||
259 |
1060768 |
} |
|
260 |
|||
261 |
|||
262 |
1051913 |
size_t NodeBIO::Read(char* out, size_t size) { |
|
263 |
1051913 |
size_t bytes_read = 0; |
|
264 |
✓✓ | 1051913 |
size_t expected = Length() > size ? size : Length(); |
265 |
1051913 |
size_t offset = 0; |
|
266 |
1051913 |
size_t left = size; |
|
267 |
|||
268 |
✓✓ | 3151949 |
while (bytes_read < expected) { |
269 |
✗✓ | 1048123 |
CHECK_LE(read_head_->read_pos_, read_head_->write_pos_); |
270 |
1048123 |
size_t avail = read_head_->write_pos_ - read_head_->read_pos_; |
|
271 |
✓✓ | 1048123 |
if (avail > left) |
272 |
984593 |
avail = left; |
|
273 |
|||
274 |
// Copy data |
||
275 |
✓✓ | 1048123 |
if (out != nullptr) |
276 |
1035513 |
memcpy(out + offset, read_head_->data_ + read_head_->read_pos_, avail); |
|
277 |
1048123 |
read_head_->read_pos_ += avail; |
|
278 |
|||
279 |
// Move pointers |
||
280 |
1048123 |
bytes_read += avail; |
|
281 |
1048123 |
offset += avail; |
|
282 |
1048123 |
left -= avail; |
|
283 |
|||
284 |
1048123 |
TryMoveReadHead(); |
|
285 |
} |
||
286 |
✗✓ | 1051913 |
CHECK_EQ(expected, bytes_read); |
287 |
1051913 |
length_ -= bytes_read; |
|
288 |
|||
289 |
// Free all empty buffers, but write_head's child |
||
290 |
1051913 |
FreeEmpty(); |
|
291 |
|||
292 |
1051913 |
return bytes_read; |
|
293 |
} |
||
294 |
|||
295 |
|||
296 |
1051913 |
void NodeBIO::FreeEmpty() { |
|
297 |
✓✓ | 1051913 |
if (write_head_ == nullptr) |
298 |
1052995 |
return; |
|
299 |
1050105 |
Buffer* child = write_head_->next_; |
|
300 |
✓✓✓✓ |
1050105 |
if (child == write_head_ || child == read_head_) |
301 |
1042462 |
return; |
|
302 |
7643 |
Buffer* cur = child->next_; |
|
303 |
✓✓✗✓ |
7643 |
if (cur == write_head_ || cur == read_head_) |
304 |
6917 |
return; |
|
305 |
|||
306 |
726 |
Buffer* prev = child; |
|
307 |
✓✓ | 7834 |
while (cur != read_head_) { |
308 |
✗✓ | 6382 |
CHECK_NE(cur, write_head_); |
309 |
✗✓ | 6382 |
CHECK_EQ(cur->write_pos_, cur->read_pos_); |
310 |
|||
311 |
6382 |
Buffer* next = cur->next_; |
|
312 |
✓✗ | 6382 |
delete cur; |
313 |
6382 |
cur = next; |
|
314 |
} |
||
315 |
726 |
prev->next_ = cur; |
|
316 |
} |
||
317 |
|||
318 |
|||
319 |
995592 |
size_t NodeBIO::IndexOf(char delim, size_t limit) { |
|
320 |
995592 |
size_t bytes_read = 0; |
|
321 |
✓✓ | 995592 |
size_t max = Length() > limit ? limit : Length(); |
322 |
995592 |
size_t left = limit; |
|
323 |
995592 |
Buffer* current = read_head_; |
|
324 |
|||
325 |
✓✓ | 2032472 |
while (bytes_read < max) { |
326 |
✗✓ | 995592 |
CHECK_LE(current->read_pos_, current->write_pos_); |
327 |
995592 |
size_t avail = current->write_pos_ - current->read_pos_; |
|
328 |
✓✓ | 995592 |
if (avail > left) |
329 |
816706 |
avail = left; |
|
330 |
|||
331 |
// Walk through data |
||
332 |
995592 |
char* tmp = current->data_ + current->read_pos_; |
|
333 |
995592 |
size_t off = 0; |
|
334 |
✓✓✓✓ |
67847567 |
while (off < avail && *tmp != delim) { |
335 |
65856383 |
off++; |
|
336 |
65856383 |
tmp++; |
|
337 |
} |
||
338 |
|||
339 |
// Move pointers |
||
340 |
995592 |
bytes_read += off; |
|
341 |
995592 |
left -= off; |
|
342 |
|||
343 |
// Found `delim` |
||
344 |
✓✓ | 995592 |
if (off != avail) { |
345 |
954304 |
return bytes_read; |
|
346 |
} |
||
347 |
|||
348 |
// Move to next buffer |
||
349 |
✓✓ | 41288 |
if (current->read_pos_ + avail == current->len_) { |
350 |
35642 |
current = current->next_; |
|
351 |
} |
||
352 |
} |
||
353 |
✗✓ | 41288 |
CHECK_EQ(max, bytes_read); |
354 |
|||
355 |
41288 |
return max; |
|
356 |
} |
||
357 |
|||
358 |
|||
359 |
59657 |
void NodeBIO::Write(const char* data, size_t size) { |
|
360 |
59657 |
size_t offset = 0; |
|
361 |
59657 |
size_t left = size; |
|
362 |
|||
363 |
// Allocate initial buffer if the ring is empty |
||
364 |
59657 |
TryAllocateForWrite(left); |
|
365 |
|||
366 |
✓✓ | 188691 |
while (left > 0) { |
367 |
69377 |
size_t to_write = left; |
|
368 |
✗✓ | 69377 |
CHECK_LE(write_head_->write_pos_, write_head_->len_); |
369 |
69377 |
size_t avail = write_head_->len_ - write_head_->write_pos_; |
|
370 |
|||
371 |
✓✓ | 69377 |
if (to_write > avail) |
372 |
9720 |
to_write = avail; |
|
373 |
|||
374 |
// Copy data |
||
375 |
69377 |
memcpy(write_head_->data_ + write_head_->write_pos_, |
|
376 |
69377 |
data + offset, |
|
377 |
138754 |
to_write); |
|
378 |
|||
379 |
// Move pointers |
||
380 |
69377 |
left -= to_write; |
|
381 |
69377 |
offset += to_write; |
|
382 |
69377 |
length_ += to_write; |
|
383 |
69377 |
write_head_->write_pos_ += to_write; |
|
384 |
✗✓ | 69377 |
CHECK_LE(write_head_->write_pos_, write_head_->len_); |
385 |
|||
386 |
// Go to next buffer if there still are some bytes to write |
||
387 |
✓✓ | 69377 |
if (left != 0) { |
388 |
✗✓ | 9720 |
CHECK_EQ(write_head_->write_pos_, write_head_->len_); |
389 |
9720 |
TryAllocateForWrite(left); |
|
390 |
9720 |
write_head_ = write_head_->next_; |
|
391 |
|||
392 |
// Additionally, since we're moved to the next buffer, read head |
||
393 |
// may be moved as well. |
||
394 |
9720 |
TryMoveReadHead(); |
|
395 |
} |
||
396 |
} |
||
397 |
✗✓ | 59657 |
CHECK_EQ(left, 0); |
398 |
59657 |
} |
|
399 |
|||
400 |
|||
401 |
8608 |
char* NodeBIO::PeekWritable(size_t* size) { |
|
402 |
8608 |
TryAllocateForWrite(*size); |
|
403 |
|||
404 |
8608 |
size_t available = write_head_->len_ - write_head_->write_pos_; |
|
405 |
✓✗✓✓ |
8608 |
if (*size == 0 || available <= *size) |
406 |
8542 |
*size = available; |
|
407 |
|||
408 |
8608 |
return write_head_->data_ + write_head_->write_pos_; |
|
409 |
} |
||
410 |
|||
411 |
|||
412 |
8059 |
void NodeBIO::Commit(size_t size) { |
|
413 |
8059 |
write_head_->write_pos_ += size; |
|
414 |
8059 |
length_ += size; |
|
415 |
✗✓ | 8059 |
CHECK_LE(write_head_->write_pos_, write_head_->len_); |
416 |
|||
417 |
// Allocate new buffer if write head is full, |
||
418 |
// and there're no other place to go |
||
419 |
8059 |
TryAllocateForWrite(0); |
|
420 |
✓✓ | 8059 |
if (write_head_->write_pos_ == write_head_->len_) { |
421 |
2925 |
write_head_ = write_head_->next_; |
|
422 |
|||
423 |
// Additionally, since we're moved to the next buffer, read head |
||
424 |
// may be moved as well. |
||
425 |
2925 |
TryMoveReadHead(); |
|
426 |
} |
||
427 |
8059 |
} |
|
428 |
|||
429 |
|||
430 |
86044 |
void NodeBIO::TryAllocateForWrite(size_t hint) { |
|
431 |
86044 |
Buffer* w = write_head_; |
|
432 |
86044 |
Buffer* r = read_head_; |
|
433 |
// If write head is full, next buffer is either read head or not empty. |
||
434 |
✓✓✓✓ |
124203 |
if (w == nullptr || |
435 |
✓✓ | 59402 |
(w->write_pos_ == w->len_ && |
436 |
✗✓ | 32648 |
(w->next_ == r || w->next_->write_pos_ != 0))) { |
437 |
size_t len = w == nullptr ? initial_ : |
||
438 |
✓✓ | 57723 |
kThroughputBufferLength; |
439 |
✓✓ | 57723 |
if (len < hint) |
440 |
48282 |
len = hint; |
|
441 |
57723 |
Buffer* next = new Buffer(env_, len); |
|
442 |
|||
443 |
✓✓ | 57723 |
if (w == nullptr) { |
444 |
47885 |
next->next_ = next; |
|
445 |
47885 |
write_head_ = next; |
|
446 |
47885 |
read_head_ = next; |
|
447 |
} else { |
||
448 |
9838 |
next->next_ = w->next_; |
|
449 |
9838 |
w->next_ = next; |
|
450 |
} |
||
451 |
} |
||
452 |
86044 |
} |
|
453 |
|||
454 |
|||
455 |
void NodeBIO::Reset() { |
||
456 |
if (read_head_ == nullptr) |
||
457 |
return; |
||
458 |
|||
459 |
while (read_head_->read_pos_ != read_head_->write_pos_) { |
||
460 |
CHECK(read_head_->write_pos_ > read_head_->read_pos_); |
||
461 |
|||
462 |
length_ -= read_head_->write_pos_ - read_head_->read_pos_; |
||
463 |
read_head_->write_pos_ = 0; |
||
464 |
read_head_->read_pos_ = 0; |
||
465 |
|||
466 |
read_head_ = read_head_->next_; |
||
467 |
} |
||
468 |
write_head_ = read_head_; |
||
469 |
CHECK_EQ(length_, 0); |
||
470 |
} |
||
471 |
|||
472 |
|||
473 |
✓✓ | 203808 |
NodeBIO::~NodeBIO() { |
474 |
✓✓ | 67936 |
if (read_head_ == nullptr) |
475 |
20087 |
return; |
|
476 |
|||
477 |
47849 |
Buffer* current = read_head_; |
|
478 |
✓✓ | 48550 |
do { |
479 |
48550 |
Buffer* next = current->next_; |
|
480 |
✓✗ | 48550 |
delete current; |
481 |
48550 |
current = next; |
|
482 |
48550 |
} while (current != read_head_); |
|
483 |
|||
484 |
47849 |
read_head_ = nullptr; |
|
485 |
47849 |
write_head_ = nullptr; |
|
486 |
✗✓ | 115785 |
} |
487 |
|||
488 |
|||
489 |
1311360 |
NodeBIO* NodeBIO::FromBIO(BIO* bio) { |
|
490 |
✗✓ | 1311360 |
CHECK_NOT_NULL(BIO_get_data(bio)); |
491 |
1311360 |
return static_cast<NodeBIO*>(BIO_get_data(bio)); |
|
492 |
} |
||
493 |
|||
494 |
|||
495 |
} // namespace crypto |
||
496 |
} // namespace node |
Generated by: GCOVR (Version 3.4) |