Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/queue.cpp
Line
Count
Source (jump to first uncovered line)
1
// queue.cpp - originally written and placed in the public domain by Wei Dai
2
3
#include "pch.h"
4
5
#ifndef CRYPTOPP_IMPORTS
6
7
#include "queue.h"
8
#include "filters.h"
9
#include "misc.h"
10
#include "trap.h"
11
12
NAMESPACE_BEGIN(CryptoPP)
13
14
static const unsigned int s_maxAutoNodeSize = 16*1024u;
15
16
// this class for use by ByteQueue only
17
class ByteQueueNode
18
{
19
public:
20
  ByteQueueNode(size_t maxSize)
21
    : m_buf(maxSize)
22
137k
  {
23
    // See GH #962 for the reason for this assert.
24
137k
    CRYPTOPP_ASSERT(maxSize != SIZE_MAX);
25
26
137k
    m_head = m_tail = 0;
27
137k
    m_next = NULLPTR;
28
137k
  }
29
30
4.91M
  inline size_t MaxSize() const {return m_buf.size();}
31
32
  inline size_t CurrentSize() const
33
5.73M
  {
34
5.73M
    return m_tail-m_head;
35
5.73M
  }
36
37
  inline bool UsedUp() const
38
24
  {
39
24
    return (m_head==MaxSize());
40
24
  }
41
42
  inline void Clear()
43
136k
  {
44
136k
    m_head = m_tail = 0;
45
136k
  }
46
47
  inline size_t Put(const byte *begin, size_t length)
48
5.04M
  {
49
    // Avoid passing NULL to memcpy
50
5.04M
    if (!begin || !length) return length;
51
4.91M
    size_t l = STDMIN(length, MaxSize()-m_tail);
52
4.91M
    if (m_buf+m_tail != begin)
53
4.91M
      std::memcpy(m_buf+m_tail, begin, l);
54
4.91M
    m_tail += l;
55
4.91M
    return l;
56
5.04M
  }
57
58
  inline size_t Peek(byte &outByte) const
59
0
  {
60
0
    if (m_tail==m_head)
61
0
      return 0;
62
63
0
    outByte=m_buf[m_head];
64
0
    return 1;
65
0
  }
66
67
  inline size_t Peek(byte *target, size_t copyMax) const
68
0
  {
69
0
    size_t len = STDMIN(copyMax, m_tail-m_head);
70
0
    std::memcpy(target, m_buf+m_head, len);
71
0
    return len;
72
0
  }
73
74
  inline size_t CopyTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const
75
0
  {
76
0
    size_t len = m_tail-m_head;
77
0
    target.ChannelPut(channel, m_buf+m_head, len);
78
0
    return len;
79
0
  }
80
81
  inline size_t CopyTo(BufferedTransformation &target, size_t copyMax, const std::string &channel=DEFAULT_CHANNEL) const
82
0
  {
83
0
    size_t len = STDMIN(copyMax, m_tail-m_head);
84
0
    target.ChannelPut(channel, m_buf+m_head, len);
85
0
    return len;
86
0
  }
87
88
  inline size_t Get(byte &outByte)
89
0
  {
90
0
    size_t len = Peek(outByte);
91
0
    m_head += len;
92
0
    return len;
93
0
  }
94
95
  inline size_t Get(byte *outString, size_t getMax)
96
0
  {
97
0
    size_t len = Peek(outString, getMax);
98
0
    m_head += len;
99
0
    return len;
100
0
  }
101
102
  inline size_t TransferTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL)
103
0
  {
104
0
    size_t len = m_tail-m_head;
105
0
    target.ChannelPutModifiable(channel, m_buf+m_head, len);
106
0
    m_head = m_tail;
107
0
    return len;
108
0
  }
109
110
  inline size_t TransferTo(BufferedTransformation &target, lword transferMax, const std::string &channel=DEFAULT_CHANNEL)
111
4.91M
  {
112
4.91M
    size_t len = UnsignedMin(m_tail-m_head, transferMax);
113
4.91M
    target.ChannelPutModifiable(channel, m_buf+m_head, len);
114
4.91M
    m_head += len;
115
4.91M
    return len;
116
4.91M
  }
117
118
  inline size_t Skip(size_t skipMax)
119
0
  {
120
0
    size_t len = STDMIN(skipMax, m_tail-m_head);
121
0
    m_head += len;
122
0
    return len;
123
0
  }
124
125
  inline byte operator[](size_t i) const
126
0
  {
127
0
    return m_buf[m_head+i];
128
0
  }
129
130
  ByteQueueNode* m_next;
131
132
  SecByteBlock m_buf;
133
  size_t m_head, m_tail;
134
};
135
136
// ********************************************************
137
138
ByteQueue::ByteQueue(size_t nodeSize)
139
  : Bufferless<BufferedTransformation>()
140
  , m_head(NULLPTR), m_tail(NULLPTR), m_lazyString(NULLPTR), m_lazyLength(0)
141
  , m_nodeSize(nodeSize), m_lazyStringModifiable(false), m_autoNodeSize(!nodeSize)
142
137k
{
143
  // See GH #962 for the reason for this assert.
144
137k
  CRYPTOPP_ASSERT(nodeSize != SIZE_MAX);
145
146
137k
  SetNodeSize(nodeSize);
147
137k
  m_head = m_tail = new ByteQueueNode(m_nodeSize);
148
137k
}
149
150
void ByteQueue::SetNodeSize(size_t nodeSize)
151
137k
{
152
137k
  m_autoNodeSize = !nodeSize;
153
137k
  m_nodeSize = m_autoNodeSize ? 256 : nodeSize;
154
137k
}
155
156
ByteQueue::ByteQueue(const ByteQueue &copy)
157
  : Bufferless<BufferedTransformation>(copy), m_lazyString(NULLPTR), m_lazyLength(0)
158
0
{
159
0
  CopyFrom(copy);
160
0
}
161
162
void ByteQueue::CopyFrom(const ByteQueue &copy)
163
0
{
164
0
  m_lazyLength = 0;
165
0
  m_autoNodeSize = copy.m_autoNodeSize;
166
0
  m_nodeSize = copy.m_nodeSize;
167
0
  m_head = m_tail = new ByteQueueNode(*copy.m_head);
168
169
0
  for (ByteQueueNode *current=copy.m_head->m_next; current; current=current->m_next)
170
0
  {
171
0
    m_tail->m_next = new ByteQueueNode(*current);
172
0
    m_tail = m_tail->m_next;
173
0
  }
174
175
0
  m_tail->m_next = NULLPTR;
176
177
0
  Put(copy.m_lazyString, copy.m_lazyLength);
178
0
}
179
180
ByteQueue::~ByteQueue()
181
137k
{
182
137k
  Destroy();
183
137k
}
184
185
void ByteQueue::Destroy()
186
137k
{
187
275k
  for (ByteQueueNode *next, *current=m_head; current; current=next)
188
137k
  {
189
137k
    next=current->m_next;
190
137k
    delete current;
191
137k
  }
192
137k
}
193
194
void ByteQueue::IsolatedInitialize(const NameValuePairs &parameters)
195
0
{
196
0
  m_nodeSize = parameters.GetIntValueWithDefault("NodeSize", 256);
197
0
  Clear();
198
0
}
199
200
lword ByteQueue::CurrentSize() const
201
0
{
202
0
  lword size=0;
203
204
0
  for (ByteQueueNode *current=m_head; current; current=current->m_next)
205
0
    size += current->CurrentSize();
206
207
0
  return size + m_lazyLength;
208
0
}
209
210
bool ByteQueue::IsEmpty() const
211
0
{
212
0
  return m_head==m_tail && m_head->CurrentSize()==0 && m_lazyLength==0;
213
0
}
214
215
void ByteQueue::Clear()
216
0
{
217
0
  for (ByteQueueNode *next, *current=m_head->m_next; current; current=next)
218
0
  {
219
0
    next=current->m_next;
220
0
    delete current;
221
0
  }
222
223
0
  m_tail = m_head;
224
0
  m_head->Clear();
225
0
  m_head->m_next = NULLPTR;
226
0
  m_lazyLength = 0;
227
0
}
228
229
size_t ByteQueue::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
230
5.04M
{
231
5.04M
  CRYPTOPP_UNUSED(messageEnd), CRYPTOPP_UNUSED(blocking);
232
233
5.04M
  if (m_lazyLength > 0)
234
0
    FinalizeLazyPut();
235
236
5.04M
  size_t len;
237
5.04M
  while ((len=m_tail->Put(inString, length)) < length)
238
191
  {
239
191
    inString = PtrAdd(inString, len);
240
191
    length -= len;
241
191
    if (m_autoNodeSize && m_nodeSize < s_maxAutoNodeSize)
242
0
    {
243
0
      do
244
0
      {
245
0
        m_nodeSize *= 2;
246
0
      }
247
0
      while (m_nodeSize < length && m_nodeSize < s_maxAutoNodeSize);
248
0
    }
249
191
    m_tail->m_next = new ByteQueueNode(STDMAX(m_nodeSize, length));
250
191
    m_tail = m_tail->m_next;
251
191
  }
252
253
5.04M
  return 0;
254
5.04M
}
255
256
void ByteQueue::CleanupUsedNodes()
257
4.91M
{
258
  // Test for m_head due to Enterprise Analysis finding
259
4.91M
  while (m_head && m_head != m_tail && m_head->UsedUp())
260
24
  {
261
24
    ByteQueueNode *temp=m_head;
262
24
    m_head=m_head->m_next;
263
24
    delete temp;
264
24
  }
265
266
  // Test for m_head due to Enterprise Analysis finding
267
4.91M
  if (m_head && m_head->CurrentSize() == 0)
268
136k
    m_head->Clear();
269
4.91M
}
270
271
void ByteQueue::LazyPut(const byte *inString, size_t size)
272
0
{
273
0
  if (m_lazyLength > 0)
274
0
    FinalizeLazyPut();
275
276
0
  if (inString == m_tail->m_buf+m_tail->m_tail)
277
0
    Put(inString, size);
278
0
  else
279
0
  {
280
0
    m_lazyString = const_cast<byte *>(inString);
281
0
    m_lazyLength = size;
282
0
    m_lazyStringModifiable = false;
283
0
  }
284
0
}
285
286
void ByteQueue::LazyPutModifiable(byte *inString, size_t size)
287
0
{
288
0
  if (m_lazyLength > 0)
289
0
    FinalizeLazyPut();
290
0
  m_lazyString = inString;
291
0
  m_lazyLength = size;
292
0
  m_lazyStringModifiable = true;
293
0
}
294
295
void ByteQueue::UndoLazyPut(size_t size)
296
0
{
297
0
  if (m_lazyLength < size)
298
0
    throw InvalidArgument("ByteQueue: size specified for UndoLazyPut is too large");
299
300
0
  m_lazyLength -= size;
301
0
}
302
303
void ByteQueue::FinalizeLazyPut()
304
0
{
305
0
  size_t len = m_lazyLength;
306
0
  m_lazyLength = 0;
307
0
  if (len)
308
0
    Put(m_lazyString, len);
309
0
}
310
311
size_t ByteQueue::Get(byte &outByte)
312
0
{
313
0
  if (m_head->Get(outByte))
314
0
  {
315
0
    if (m_head->UsedUp())
316
0
      CleanupUsedNodes();
317
0
    return 1;
318
0
  }
319
0
  else if (m_lazyLength > 0)
320
0
  {
321
0
    outByte = *m_lazyString++;
322
0
    m_lazyLength--;
323
0
    return 1;
324
0
  }
325
0
  else
326
0
    return 0;
327
0
}
328
329
size_t ByteQueue::Get(byte *outString, size_t getMax)
330
0
{
331
0
  ArraySink sink(outString, getMax);
332
0
  return (size_t)TransferTo(sink, getMax);
333
0
}
334
335
size_t ByteQueue::Peek(byte &outByte) const
336
0
{
337
0
  if (m_head->Peek(outByte))
338
0
    return 1;
339
0
  else if (m_lazyLength > 0)
340
0
  {
341
0
    outByte = *m_lazyString;
342
0
    return 1;
343
0
  }
344
0
  else
345
0
    return 0;
346
0
}
347
348
size_t ByteQueue::Peek(byte *outString, size_t peekMax) const
349
0
{
350
0
  ArraySink sink(outString, peekMax);
351
0
  return (size_t)CopyTo(sink, peekMax);
352
0
}
353
354
size_t ByteQueue::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
355
4.91M
{
356
  // No need for CRYPTOPP_ASSERT on transferBytes here.
357
  // TransferTo2 handles LWORD_MAX as expected.
358
359
4.91M
  if (blocking)
360
4.91M
  {
361
4.91M
    lword bytesLeft = transferBytes;
362
9.82M
    for (ByteQueueNode *current=m_head; bytesLeft && current; current=current->m_next)
363
4.91M
      bytesLeft -= current->TransferTo(target, bytesLeft, channel);
364
4.91M
    CleanupUsedNodes();
365
366
4.91M
    size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength);
367
4.91M
    if (len)
368
0
    {
369
0
      if (m_lazyStringModifiable)
370
0
        target.ChannelPutModifiable(channel, m_lazyString, len);
371
0
      else
372
0
        target.ChannelPut(channel, m_lazyString, len);
373
0
      m_lazyString = PtrAdd(m_lazyString, len);
374
0
      m_lazyLength -= len;
375
0
      bytesLeft -= len;
376
0
    }
377
4.91M
    transferBytes -= bytesLeft;
378
4.91M
    return 0;
379
4.91M
  }
380
0
  else
381
0
  {
382
0
    Walker walker(*this);
383
0
    size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
384
0
    Skip(transferBytes);
385
0
    return blockedBytes;
386
0
  }
387
4.91M
}
388
389
size_t ByteQueue::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
390
412k
{
391
412k
  Walker walker(*this);
392
412k
  walker.Skip(begin);
393
412k
  lword transferBytes = end-begin;
394
395
412k
  size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
396
412k
  begin += transferBytes;
397
412k
  return blockedBytes;
398
412k
}
399
400
void ByteQueue::Unget(byte inByte)
401
0
{
402
0
  Unget(&inByte, 1);
403
0
}
404
405
void ByteQueue::Unget(const byte *inString, size_t length)
406
0
{
407
  // See GH #962 for the reason for this assert.
408
0
  CRYPTOPP_ASSERT(length != SIZE_MAX);
409
410
0
  size_t len = STDMIN(length, m_head->m_head);
411
0
  length -= len;
412
0
  m_head->m_head = m_head->m_head - len;
413
0
  std::memcpy(m_head->m_buf + m_head->m_head, inString + length, len);
414
415
0
  if (length > 0)
416
0
  {
417
0
    ByteQueueNode *newHead = new ByteQueueNode(length);
418
0
    newHead->m_next = m_head;
419
0
    m_head = newHead;
420
0
    m_head->Put(inString, length);
421
0
  }
422
0
}
423
424
const byte * ByteQueue::Spy(size_t &contiguousSize) const
425
0
{
426
0
  contiguousSize = m_head->m_tail - m_head->m_head;
427
0
  if (contiguousSize == 0 && m_lazyLength > 0)
428
0
  {
429
0
    contiguousSize = m_lazyLength;
430
0
    return m_lazyString;
431
0
  }
432
0
  else
433
0
    return m_head->m_buf + m_head->m_head;
434
0
}
435
436
byte * ByteQueue::CreatePutSpace(size_t &size)
437
0
{
438
  // See GH #962 for the reason for this assert.
439
0
  CRYPTOPP_ASSERT(size != SIZE_MAX);
440
  // Sanity check for a reasonable size
441
0
  CRYPTOPP_ASSERT(size <= 16U*1024*1024);
442
443
0
  if (m_lazyLength > 0)
444
0
    FinalizeLazyPut();
445
446
0
  if (m_tail->m_tail == m_tail->MaxSize())
447
0
  {
448
0
    m_tail->m_next = new ByteQueueNode(STDMAX(m_nodeSize, size));
449
0
    m_tail = m_tail->m_next;
450
0
  }
451
452
0
  size = m_tail->MaxSize() - m_tail->m_tail;
453
0
  return PtrAdd(m_tail->m_buf.begin(), m_tail->m_tail);
454
0
}
455
456
ByteQueue & ByteQueue::operator=(const ByteQueue &rhs)
457
0
{
458
0
  Destroy();
459
0
  CopyFrom(rhs);
460
0
  return *this;
461
0
}
462
463
bool ByteQueue::operator==(const ByteQueue &rhs) const
464
0
{
465
0
  const lword currentSize = CurrentSize();
466
467
0
  if (currentSize != rhs.CurrentSize())
468
0
    return false;
469
470
0
  Walker walker1(*this), walker2(rhs);
471
0
  byte b1, b2;
472
473
0
  while (walker1.Get(b1) && walker2.Get(b2))
474
0
    if (b1 != b2)
475
0
      return false;
476
477
0
  return true;
478
0
}
479
480
byte ByteQueue::operator[](lword index) const
481
0
{
482
0
  for (ByteQueueNode *current=m_head; current; current=current->m_next)
483
0
  {
484
0
    if (index < current->CurrentSize())
485
0
      return (*current)[(size_t)index];
486
487
0
    index -= current->CurrentSize();
488
0
  }
489
490
0
  CRYPTOPP_ASSERT(index < m_lazyLength);
491
0
  return m_lazyString[index];
492
0
}
493
494
void ByteQueue::swap(ByteQueue &rhs)
495
0
{
496
0
  std::swap(m_autoNodeSize, rhs.m_autoNodeSize);
497
0
  std::swap(m_nodeSize, rhs.m_nodeSize);
498
0
  std::swap(m_head, rhs.m_head);
499
0
  std::swap(m_tail, rhs.m_tail);
500
0
  std::swap(m_lazyString, rhs.m_lazyString);
501
0
  std::swap(m_lazyLength, rhs.m_lazyLength);
502
0
  std::swap(m_lazyStringModifiable, rhs.m_lazyStringModifiable);
503
0
}
504
505
// ********************************************************
506
507
void ByteQueue::Walker::IsolatedInitialize(const NameValuePairs &parameters)
508
412k
{
509
412k
  CRYPTOPP_UNUSED(parameters);
510
511
412k
  m_node = m_queue.m_head;
512
412k
  m_position = 0;
513
412k
  m_offset = 0;
514
412k
  m_lazyString = m_queue.m_lazyString;
515
412k
  m_lazyLength = m_queue.m_lazyLength;
516
412k
}
517
518
size_t ByteQueue::Walker::Get(byte &outByte)
519
0
{
520
0
  ArraySink sink(&outByte, 1);
521
0
  return (size_t)TransferTo(sink, 1);
522
0
}
523
524
size_t ByteQueue::Walker::Get(byte *outString, size_t getMax)
525
0
{
526
0
  ArraySink sink(outString, getMax);
527
0
  return (size_t)TransferTo(sink, getMax);
528
0
}
529
530
size_t ByteQueue::Walker::Peek(byte &outByte) const
531
0
{
532
0
  ArraySink sink(&outByte, 1);
533
0
  return (size_t)CopyTo(sink, 1);
534
0
}
535
536
size_t ByteQueue::Walker::Peek(byte *outString, size_t peekMax) const
537
0
{
538
0
  ArraySink sink(outString, peekMax);
539
0
  return (size_t)CopyTo(sink, peekMax);
540
0
}
541
542
size_t ByteQueue::Walker::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
543
825k
{
544
  // No need for CRYPTOPP_ASSERT on transferBytes here.
545
  // TransferTo2 handles LWORD_MAX as expected.
546
547
825k
  lword bytesLeft = transferBytes;
548
825k
  size_t blockedBytes = 0;
549
550
825k
  while (m_node)
551
825k
  {
552
825k
    size_t len = (size_t)STDMIN(bytesLeft, (lword)m_node->CurrentSize()-m_offset);
553
825k
    blockedBytes = target.ChannelPut2(channel, m_node->m_buf+m_node->m_head+m_offset, len, 0, blocking);
554
555
825k
    if (blockedBytes)
556
0
      goto done;
557
558
825k
    m_position += len;
559
825k
    bytesLeft -= len;
560
561
825k
    if (!bytesLeft)
562
825k
    {
563
825k
      m_offset += len;
564
825k
      goto done;
565
825k
    }
566
567
0
    m_node = m_node->m_next;
568
0
    m_offset = 0;
569
0
  }
570
571
0
  if (bytesLeft && m_lazyLength)
572
0
  {
573
0
    size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength);
574
0
    blockedBytes = target.ChannelPut2(channel, m_lazyString, len, 0, blocking);
575
0
    if (blockedBytes)
576
0
      goto done;
577
578
0
    m_lazyString = PtrAdd(m_lazyString, len);
579
0
    m_lazyLength -= len;
580
0
    bytesLeft -= len;
581
0
  }
582
583
825k
done:
584
825k
  transferBytes -= bytesLeft;
585
825k
  return blockedBytes;
586
0
}
587
588
size_t ByteQueue::Walker::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
589
0
{
590
0
  Walker walker(*this);
591
0
  walker.Skip(begin);
592
0
  lword transferBytes = end-begin;
593
594
0
  size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
595
0
  begin += transferBytes;
596
0
  return blockedBytes;
597
0
}
598
599
NAMESPACE_END
600
601
#endif