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 "crypto/crypto_bio.h" |
||
23 |
#include "base_object-inl.h" |
||
24 |
#include "memory_tracker-inl.h" |
||
25 |
#include "allocated_buffer-inl.h" |
||
26 |
#include "util-inl.h" |
||
27 |
|||
28 |
#include <openssl/bio.h> |
||
29 |
|||
30 |
#include <climits> |
||
31 |
#include <cstring> |
||
32 |
|||
33 |
namespace node { |
||
34 |
namespace crypto { |
||
35 |
|||
36 |
62821 |
BIOPointer NodeBIO::New(Environment* env) { |
|
37 |
62821 |
BIOPointer bio(BIO_new(GetMethod())); |
|
38 |
✓✗✓✓ ✓✓ |
62821 |
if (bio && env != nullptr) |
39 |
24768 |
NodeBIO::FromBIO(bio.get())->env_ = env; |
|
40 |
62821 |
return bio; |
|
41 |
} |
||
42 |
|||
43 |
|||
44 |
38053 |
BIOPointer NodeBIO::NewFixed(const char* data, size_t len, Environment* env) { |
|
45 |
76106 |
BIOPointer bio = New(env); |
|
46 |
|||
47 |
✓✗ | 76106 |
if (!bio || |
48 |
38053 |
len > INT_MAX || |
|
49 |
✓✗✓✗ ✗✓✗✓ |
114159 |
BIO_write(bio.get(), data, len) != static_cast<int>(len) || |
50 |
38053 |
BIO_set_mem_eof_return(bio.get(), 0) != 1) { |
|
51 |
return BIOPointer(); |
||
52 |
} |
||
53 |
|||
54 |
38053 |
return bio; |
|
55 |
} |
||
56 |
|||
57 |
|||
58 |
62821 |
int NodeBIO::New(BIO* bio) { |
|
59 |
62821 |
BIO_set_data(bio, new NodeBIO()); |
|
60 |
62821 |
BIO_set_init(bio, 1); |
|
61 |
|||
62 |
62821 |
return 1; |
|
63 |
} |
||
64 |
|||
65 |
|||
66 |
62811 |
int NodeBIO::Free(BIO* bio) { |
|
67 |
✗✓ | 62811 |
if (bio == nullptr) |
68 |
return 0; |
||
69 |
|||
70 |
✓✗ | 62811 |
if (BIO_get_shutdown(bio)) { |
71 |
✓✗✓✗ ✓✗ |
62811 |
if (BIO_get_init(bio) && BIO_get_data(bio) != nullptr) { |
72 |
✓✗ | 62811 |
delete FromBIO(bio); |
73 |
62811 |
BIO_set_data(bio, nullptr); |
|
74 |
} |
||
75 |
} |
||
76 |
|||
77 |
62811 |
return 1; |
|
78 |
} |
||
79 |
|||
80 |
|||
81 |
36732 |
int NodeBIO::Read(BIO* bio, char* out, int len) { |
|
82 |
36732 |
BIO_clear_retry_flags(bio); |
|
83 |
|||
84 |
36732 |
NodeBIO* nbio = FromBIO(bio); |
|
85 |
36732 |
int bytes = nbio->Read(out, len); |
|
86 |
|||
87 |
✓✓ | 36732 |
if (bytes == 0) { |
88 |
7660 |
bytes = nbio->eof_return(); |
|
89 |
✓✓ | 7660 |
if (bytes != 0) { |
90 |
7658 |
BIO_set_retry_read(bio); |
|
91 |
} |
||
92 |
} |
||
93 |
|||
94 |
36732 |
return bytes; |
|
95 |
} |
||
96 |
|||
97 |
|||
98 |
20 |
char* NodeBIO::Peek(size_t* size) { |
|
99 |
20 |
*size = read_head_->write_pos_ - read_head_->read_pos_; |
|
100 |
20 |
return read_head_->data_ + read_head_->read_pos_; |
|
101 |
} |
||
102 |
|||
103 |
|||
104 |
7712 |
size_t NodeBIO::PeekMultiple(char** out, size_t* size, size_t* count) { |
|
105 |
7712 |
Buffer* pos = read_head_; |
|
106 |
7712 |
size_t max = *count; |
|
107 |
7712 |
size_t total = 0; |
|
108 |
|||
109 |
size_t i; |
||
110 |
✓✗ | 7848 |
for (i = 0; i < max; i++) { |
111 |
7848 |
size[i] = pos->write_pos_ - pos->read_pos_; |
|
112 |
7848 |
total += size[i]; |
|
113 |
7848 |
out[i] = pos->data_ + pos->read_pos_; |
|
114 |
|||
115 |
/* Don't get past write head */ |
||
116 |
✓✓ | 7848 |
if (pos == write_head_) |
117 |
7712 |
break; |
|
118 |
else |
||
119 |
136 |
pos = pos->next_; |
|
120 |
} |
||
121 |
|||
122 |
✗✓ | 7712 |
if (i == max) |
123 |
*count = i; |
||
124 |
else |
||
125 |
7712 |
*count = i + 1; |
|
126 |
|||
127 |
7712 |
return total; |
|
128 |
} |
||
129 |
|||
130 |
|||
131 |
48884 |
int NodeBIO::Write(BIO* bio, const char* data, int len) { |
|
132 |
48884 |
BIO_clear_retry_flags(bio); |
|
133 |
|||
134 |
48884 |
FromBIO(bio)->Write(data, len); |
|
135 |
|||
136 |
48884 |
return len; |
|
137 |
} |
||
138 |
|||
139 |
|||
140 |
int NodeBIO::Puts(BIO* bio, const char* str) { |
||
141 |
return Write(bio, str, strlen(str)); |
||
142 |
} |
||
143 |
|||
144 |
|||
145 |
867565 |
int NodeBIO::Gets(BIO* bio, char* out, int size) { |
|
146 |
867565 |
NodeBIO* nbio = FromBIO(bio); |
|
147 |
|||
148 |
✓✓ | 867565 |
if (nbio->Length() == 0) |
149 |
1564 |
return 0; |
|
150 |
|||
151 |
866001 |
int i = nbio->IndexOf('\n', size); |
|
152 |
|||
153 |
// Include '\n', if it's there. If not, don't read off the end. |
||
154 |
✓✗✓✗ ✓✓✓✓ |
866001 |
if (i < size && i >= 0 && static_cast<size_t>(i) < nbio->Length()) |
155 |
830493 |
i++; |
|
156 |
|||
157 |
// Shift `i` a bit to nullptr-terminate string later |
||
158 |
✗✓ | 866001 |
if (size == i) |
159 |
i--; |
||
160 |
|||
161 |
// Flush read data |
||
162 |
866001 |
nbio->Read(out, i); |
|
163 |
|||
164 |
866001 |
out[i] = 0; |
|
165 |
|||
166 |
866001 |
return i; |
|
167 |
} |
||
168 |
|||
169 |
|||
170 |
73346 |
long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) |
|
171 |
void* ptr) { |
||
172 |
NodeBIO* nbio; |
||
173 |
long ret; // NOLINT(runtime/int) |
||
174 |
|||
175 |
73346 |
nbio = FromBIO(bio); |
|
176 |
73346 |
ret = 1; |
|
177 |
|||
178 |
✗✓✓✗ ✗✗✗✗ ✗✓✓✓ |
73346 |
switch (cmd) { |
179 |
case BIO_CTRL_RESET: |
||
180 |
nbio->Reset(); |
||
181 |
break; |
||
182 |
32 |
case BIO_CTRL_EOF: |
|
183 |
32 |
ret = nbio->Length() == 0; |
|
184 |
32 |
break; |
|
185 |
38053 |
case BIO_C_SET_BUF_MEM_EOF_RETURN: |
|
186 |
38053 |
nbio->set_eof_return(num); |
|
187 |
38053 |
break; |
|
188 |
case BIO_CTRL_INFO: |
||
189 |
ret = nbio->Length(); |
||
190 |
if (ptr != nullptr) |
||
191 |
*reinterpret_cast<void**>(ptr) = nullptr; |
||
192 |
break; |
||
193 |
case BIO_C_SET_BUF_MEM: |
||
194 |
CHECK(0 && "Can't use SET_BUF_MEM_PTR with NodeBIO"); |
||
195 |
break; |
||
196 |
case BIO_C_GET_BUF_MEM_PTR: |
||
197 |
CHECK(0 && "Can't use GET_BUF_MEM_PTR with NodeBIO"); |
||
198 |
ret = 0; |
||
199 |
break; |
||
200 |
case BIO_CTRL_GET_CLOSE: |
||
201 |
ret = BIO_get_shutdown(bio); |
||
202 |
break; |
||
203 |
case BIO_CTRL_SET_CLOSE: |
||
204 |
BIO_set_shutdown(bio, num); |
||
205 |
break; |
||
206 |
case BIO_CTRL_WPENDING: |
||
207 |
ret = 0; |
||
208 |
break; |
||
209 |
17258 |
case BIO_CTRL_PENDING: |
|
210 |
17258 |
ret = nbio->Length(); |
|
211 |
17258 |
break; |
|
212 |
6116 |
case BIO_CTRL_DUP: |
|
213 |
case BIO_CTRL_FLUSH: |
||
214 |
6116 |
ret = 1; |
|
215 |
6116 |
break; |
|
216 |
11887 |
case BIO_CTRL_PUSH: |
|
217 |
case BIO_CTRL_POP: |
||
218 |
default: |
||
219 |
11887 |
ret = 0; |
|
220 |
11887 |
break; |
|
221 |
} |
||
222 |
73346 |
return ret; |
|
223 |
} |
||
224 |
|||
225 |
|||
226 |
68005 |
const BIO_METHOD* NodeBIO::GetMethod() { |
|
227 |
// This is called from InitCryptoOnce() to avoid race conditions during |
||
228 |
// initialization. |
||
229 |
static BIO_METHOD* method = nullptr; |
||
230 |
|||
231 |
✓✓ | 68005 |
if (method == nullptr) { |
232 |
5184 |
method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer"); |
|
233 |
5184 |
BIO_meth_set_write(method, Write); |
|
234 |
5184 |
BIO_meth_set_read(method, Read); |
|
235 |
5184 |
BIO_meth_set_puts(method, Puts); |
|
236 |
5184 |
BIO_meth_set_gets(method, Gets); |
|
237 |
5184 |
BIO_meth_set_ctrl(method, Ctrl); |
|
238 |
5184 |
BIO_meth_set_create(method, New); |
|
239 |
5184 |
BIO_meth_set_destroy(method, Free); |
|
240 |
} |
||
241 |
|||
242 |
68005 |
return method; |
|
243 |
} |
||
244 |
|||
245 |
|||
246 |
955005 |
void NodeBIO::TryMoveReadHead() { |
|
247 |
// `read_pos_` and `write_pos_` means the position of the reader and writer |
||
248 |
// inside the buffer, respectively. When they're equal - its safe to reset |
||
249 |
// them, because both reader and writer will continue doing their stuff |
||
250 |
// from new (zero) positions. |
||
251 |
✓✓ | 955005 |
while (read_head_->read_pos_ != 0 && |
252 |
✓✓ | 902729 |
read_head_->read_pos_ == read_head_->write_pos_) { |
253 |
// Reset positions |
||
254 |
51404 |
read_head_->read_pos_ = 0; |
|
255 |
51404 |
read_head_->write_pos_ = 0; |
|
256 |
|||
257 |
// Move read_head_ forward, just in case if there're still some data to |
||
258 |
// read in the next buffer. |
||
259 |
✓✓ | 51404 |
if (read_head_ != write_head_) |
260 |
346 |
read_head_ = read_head_->next_; |
|
261 |
} |
||
262 |
903601 |
} |
|
263 |
|||
264 |
|||
265 |
910262 |
size_t NodeBIO::Read(char* out, size_t size) { |
|
266 |
910262 |
size_t bytes_read = 0; |
|
267 |
✓✓ | 910262 |
size_t expected = Length() > size ? size : Length(); |
268 |
910262 |
size_t offset = 0; |
|
269 |
910262 |
size_t left = size; |
|
270 |
|||
271 |
✓✓ | 1812991 |
while (bytes_read < expected) { |
272 |
✗✓ | 902729 |
CHECK_LE(read_head_->read_pos_, read_head_->write_pos_); |
273 |
902729 |
size_t avail = read_head_->write_pos_ - read_head_->read_pos_; |
|
274 |
✓✓ | 902729 |
if (avail > left) |
275 |
851325 |
avail = left; |
|
276 |
|||
277 |
// Copy data |
||
278 |
✓✓ | 902729 |
if (out != nullptr) |
279 |
895073 |
memcpy(out + offset, read_head_->data_ + read_head_->read_pos_, avail); |
|
280 |
902729 |
read_head_->read_pos_ += avail; |
|
281 |
|||
282 |
// Move pointers |
||
283 |
902729 |
bytes_read += avail; |
|
284 |
902729 |
offset += avail; |
|
285 |
902729 |
left -= avail; |
|
286 |
|||
287 |
902729 |
TryMoveReadHead(); |
|
288 |
} |
||
289 |
✗✓ | 910262 |
CHECK_EQ(expected, bytes_read); |
290 |
910262 |
length_ -= bytes_read; |
|
291 |
|||
292 |
// Free all empty buffers, but write_head's child |
||
293 |
910262 |
FreeEmpty(); |
|
294 |
|||
295 |
910262 |
return bytes_read; |
|
296 |
} |
||
297 |
|||
298 |
|||
299 |
910262 |
void NodeBIO::FreeEmpty() { |
|
300 |
✓✓ | 910262 |
if (write_head_ == nullptr) |
301 |
910261 |
return; |
|
302 |
908508 |
Buffer* child = write_head_->next_; |
|
303 |
✓✓✓✓ |
908508 |
if (child == write_head_ || child == read_head_) |
304 |
903033 |
return; |
|
305 |
5475 |
Buffer* cur = child->next_; |
|
306 |
✓✓✗✓ |
5475 |
if (cur == write_head_ || cur == read_head_) |
307 |
5474 |
return; |
|
308 |
|||
309 |
1 |
Buffer* prev = child; |
|
310 |
✓✓ | 2 |
while (cur != read_head_) { |
311 |
✗✓ | 1 |
CHECK_NE(cur, write_head_); |
312 |
✗✓ | 1 |
CHECK_EQ(cur->write_pos_, cur->read_pos_); |
313 |
|||
314 |
1 |
Buffer* next = cur->next_; |
|
315 |
✓✗ | 1 |
delete cur; |
316 |
1 |
cur = next; |
|
317 |
} |
||
318 |
1 |
prev->next_ = cur; |
|
319 |
} |
||
320 |
|||
321 |
|||
322 |
866001 |
size_t NodeBIO::IndexOf(char delim, size_t limit) { |
|
323 |
866001 |
size_t bytes_read = 0; |
|
324 |
✓✓ | 866001 |
size_t max = Length() > limit ? limit : Length(); |
325 |
866001 |
size_t left = limit; |
|
326 |
866001 |
Buffer* current = read_head_; |
|
327 |
|||
328 |
✓✓ | 901509 |
while (bytes_read < max) { |
329 |
✗✓ | 866001 |
CHECK_LE(current->read_pos_, current->write_pos_); |
330 |
866001 |
size_t avail = current->write_pos_ - current->read_pos_; |
|
331 |
✓✓ | 866001 |
if (avail > left) |
332 |
709044 |
avail = left; |
|
333 |
|||
334 |
// Walk through data |
||
335 |
866001 |
char* tmp = current->data_ + current->read_pos_; |
|
336 |
866001 |
size_t off = 0; |
|
337 |
✓✓✓✓ |
57934934 |
while (off < avail && *tmp != delim) { |
338 |
57068933 |
off++; |
|
339 |
57068933 |
tmp++; |
|
340 |
} |
||
341 |
|||
342 |
// Move pointers |
||
343 |
866001 |
bytes_read += off; |
|
344 |
866001 |
left -= off; |
|
345 |
|||
346 |
// Found `delim` |
||
347 |
✓✓ | 866001 |
if (off != avail) { |
348 |
830493 |
return bytes_read; |
|
349 |
} |
||
350 |
|||
351 |
// Move to next buffer |
||
352 |
✓✓ | 35508 |
if (current->read_pos_ + avail == current->len_) { |
353 |
28728 |
current = current->next_; |
|
354 |
} |
||
355 |
} |
||
356 |
✗✓ | 35508 |
CHECK_EQ(max, bytes_read); |
357 |
|||
358 |
35508 |
return max; |
|
359 |
} |
||
360 |
|||
361 |
|||
362 |
48884 |
void NodeBIO::Write(const char* data, size_t size) { |
|
363 |
48884 |
size_t offset = 0; |
|
364 |
48884 |
size_t left = size; |
|
365 |
|||
366 |
// Allocate initial buffer if the ring is empty |
||
367 |
48884 |
TryAllocateForWrite(left); |
|
368 |
|||
369 |
✓✓ | 97906 |
while (left > 0) { |
370 |
49022 |
size_t to_write = left; |
|
371 |
✗✓ | 49022 |
CHECK_LE(write_head_->write_pos_, write_head_->len_); |
372 |
49022 |
size_t avail = write_head_->len_ - write_head_->write_pos_; |
|
373 |
|||
374 |
✓✓ | 49022 |
if (to_write > avail) |
375 |
138 |
to_write = avail; |
|
376 |
|||
377 |
// Copy data |
||
378 |
49022 |
memcpy(write_head_->data_ + write_head_->write_pos_, |
|
379 |
49022 |
data + offset, |
|
380 |
to_write); |
||
381 |
|||
382 |
// Move pointers |
||
383 |
49022 |
left -= to_write; |
|
384 |
49022 |
offset += to_write; |
|
385 |
49022 |
length_ += to_write; |
|
386 |
49022 |
write_head_->write_pos_ += to_write; |
|
387 |
✗✓ | 49022 |
CHECK_LE(write_head_->write_pos_, write_head_->len_); |
388 |
|||
389 |
// Go to next buffer if there still are some bytes to write |
||
390 |
✓✓ | 49022 |
if (left != 0) { |
391 |
✗✓ | 138 |
CHECK_EQ(write_head_->write_pos_, write_head_->len_); |
392 |
138 |
TryAllocateForWrite(left); |
|
393 |
138 |
write_head_ = write_head_->next_; |
|
394 |
|||
395 |
// Additionally, since we're moved to the next buffer, read head |
||
396 |
// may be moved as well. |
||
397 |
138 |
TryMoveReadHead(); |
|
398 |
} |
||
399 |
} |
||
400 |
✗✓ | 48884 |
CHECK_EQ(left, 0); |
401 |
48884 |
} |
|
402 |
|||
403 |
|||
404 |
7166 |
char* NodeBIO::PeekWritable(size_t* size) { |
|
405 |
7166 |
TryAllocateForWrite(*size); |
|
406 |
|||
407 |
7166 |
size_t available = write_head_->len_ - write_head_->write_pos_; |
|
408 |
✓✗✓✓ |
7166 |
if (*size == 0 || available <= *size) |
409 |
7123 |
*size = available; |
|
410 |
|||
411 |
7166 |
return write_head_->data_ + write_head_->write_pos_; |
|
412 |
} |
||
413 |
|||
414 |
|||
415 |
6342 |
void NodeBIO::Commit(size_t size) { |
|
416 |
6342 |
write_head_->write_pos_ += size; |
|
417 |
6342 |
length_ += size; |
|
418 |
✗✓ | 6342 |
CHECK_LE(write_head_->write_pos_, write_head_->len_); |
419 |
|||
420 |
// Allocate new buffer if write head is full, |
||
421 |
// and there're no other place to go |
||
422 |
6342 |
TryAllocateForWrite(0); |
|
423 |
✓✓ | 6342 |
if (write_head_->write_pos_ == write_head_->len_) { |
424 |
734 |
write_head_ = write_head_->next_; |
|
425 |
|||
426 |
// Additionally, since we're moved to the next buffer, read head |
||
427 |
// may be moved as well. |
||
428 |
734 |
TryMoveReadHead(); |
|
429 |
} |
||
430 |
6342 |
} |
|
431 |
|||
432 |
|||
433 |
62530 |
void NodeBIO::TryAllocateForWrite(size_t hint) { |
|
434 |
62530 |
Buffer* w = write_head_; |
|
435 |
62530 |
Buffer* r = read_head_; |
|
436 |
// If write head is full, next buffer is either read head or not empty. |
||
437 |
✓✓ | 62530 |
if (w == nullptr || |
438 |
✓✓ | 19830 |
(w->write_pos_ == w->len_ && |
439 |
✓✓✗✓ |
874 |
(w->next_ == r || w->next_->write_pos_ != 0))) { |
440 |
✓✓ | 43368 |
size_t len = w == nullptr ? initial_ : |
441 |
kThroughputBufferLength; |
||
442 |
✓✓ | 43368 |
if (len < hint) |
443 |
33212 |
len = hint; |
|
444 |
|||
445 |
// If there is a one time allocation size hint, use it. |
||
446 |
✓✓ | 43368 |
if (allocate_hint_ > len) { |
447 |
23 |
len = allocate_hint_; |
|
448 |
23 |
allocate_hint_ = 0; |
|
449 |
} |
||
450 |
|||
451 |
43368 |
Buffer* next = new Buffer(env_, len); |
|
452 |
|||
453 |
✓✓ | 43368 |
if (w == nullptr) { |
454 |
42700 |
next->next_ = next; |
|
455 |
42700 |
write_head_ = next; |
|
456 |
42700 |
read_head_ = next; |
|
457 |
} else { |
||
458 |
668 |
next->next_ = w->next_; |
|
459 |
668 |
w->next_ = next; |
|
460 |
} |
||
461 |
} |
||
462 |
62530 |
} |
|
463 |
|||
464 |
|||
465 |
void NodeBIO::Reset() { |
||
466 |
if (read_head_ == nullptr) |
||
467 |
return; |
||
468 |
|||
469 |
while (read_head_->read_pos_ != read_head_->write_pos_) { |
||
470 |
CHECK(read_head_->write_pos_ > read_head_->read_pos_); |
||
471 |
|||
472 |
length_ -= read_head_->write_pos_ - read_head_->read_pos_; |
||
473 |
read_head_->write_pos_ = 0; |
||
474 |
read_head_->read_pos_ = 0; |
||
475 |
|||
476 |
read_head_ = read_head_->next_; |
||
477 |
} |
||
478 |
write_head_ = read_head_; |
||
479 |
CHECK_EQ(length_, 0); |
||
480 |
} |
||
481 |
|||
482 |
|||
483 |
✓✓ | 251244 |
NodeBIO::~NodeBIO() { |
484 |
✓✓ | 125622 |
if (read_head_ == nullptr) |
485 |
40242 |
return; |
|
486 |
|||
487 |
85380 |
Buffer* current = read_head_; |
|
488 |
1328 |
do { |
|
489 |
86708 |
Buffer* next = current->next_; |
|
490 |
✓✗ | 86708 |
delete current; |
491 |
86708 |
current = next; |
|
492 |
✓✓ | 86708 |
} while (current != read_head_); |
493 |
|||
494 |
85380 |
read_head_ = nullptr; |
|
495 |
85380 |
write_head_ = nullptr; |
|
496 |
251244 |
} |
|
497 |
|||
498 |
|||
499 |
1157353 |
NodeBIO* NodeBIO::FromBIO(BIO* bio) { |
|
500 |
✗✓ | 1157353 |
CHECK_NOT_NULL(BIO_get_data(bio)); |
501 |
1157353 |
return static_cast<NodeBIO*>(BIO_get_data(bio)); |
|
502 |
} |
||
503 |
|||
504 |
|||
505 |
} // namespace crypto |
||
506 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |