From acb7e0558d2337ad42261ed81e67d37385679285 Mon Sep 17 00:00:00 2001
From: Niels Lohmann <niels.lohmann@gmail.com>
Date: Wed, 28 Dec 2016 12:09:15 +0100
Subject: [PATCH] :ambulance: fixed bugs detected by AFL-Fuzz

---
 src/json.hpp                                  |  57 +++++++++++++
 src/json.hpp.re2c                             |  57 +++++++++++++
 ...0,sig:06,src:000223+000677,op:splice,rep:2 |   1 +
 ...id:000000,sig:06,src:000787,op:havoc,rep:8 | Bin 0 -> 19 bytes
 ...d:000000,sig:06,src:000833,op:havoc,rep:32 | Bin 0 -> 38 bytes
 ...d:000000,sig:06,src:000838,op:havoc,rep:64 | Bin 0 -> 842 bytes
 ...,sig:06,src:000846+001064,op:splice,rep:16 | Bin 0 -> 201 bytes
 ...id:000000,sig:06,src:000848,op:flip1,pos:0 | Bin 0 -> 263 bytes
 ...d:000000,sig:06,src:001435,op:havoc,rep:32 | Bin 0 -> 2488 bytes
 ...id:000000,sig:06,src:001436,op:havoc,rep:4 | Bin 0 -> 2579 bytes
 ...1,sig:06,src:000864+000903,op:splice,rep:2 | Bin 0 -> 33 bytes
 ...,sig:06,src:001310+001138,op:splice,rep:32 |   1 +
 ...,sig:06,src:001330+000569,op:splice,rep:64 | Bin 0 -> 1932 bytes
 ...d:000001,sig:06,src:001413,op:havoc,rep:32 | Bin 0 -> 1396 bytes
 ...id:000001,sig:06,src:001447,op:havoc,rep:4 | Bin 0 -> 1839 bytes
 ...1,sig:06,src:001465+000325,op:splice,rep:4 | Bin 0 -> 475 bytes
 ...id:000002,sig:06,src:000539,op:havoc,rep:8 | Bin 0 -> 140 bytes
 ...d:000002,sig:06,src:001301,op:havoc,rep:16 | Bin 0 -> 16 bytes
 ...2,sig:06,src:001317+000850,op:splice,rep:8 | Bin 0 -> 349 bytes
 ...:000002,sig:06,src:001382,op:havoc,rep:128 | Bin 0 -> 3116 bytes
 ...2,sig:06,src:001413+001036,op:splice,rep:4 | Bin 0 -> 395 bytes
 ...,sig:06,src:000846+000155,op:splice,rep:16 | Bin 0 -> 222 bytes
 ...:000004,sig:06,src:001445,op:havoc,rep:128 | Bin 0 -> 4382 bytes
 test/src/unit-cbor.cpp                        |  78 ++++++++++++++++++
 24 files changed, 194 insertions(+)
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:000223+000677,op:splice,rep:2
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:000787,op:havoc,rep:8
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:000833,op:havoc,rep:32
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:000838,op:havoc,rep:64
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:000846+001064,op:splice,rep:16
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:000848,op:flip1,pos:0
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:001435,op:havoc,rep:32
 create mode 100644 test/data/cbor_regression/id:000000,sig:06,src:001436,op:havoc,rep:4
 create mode 100644 test/data/cbor_regression/id:000001,sig:06,src:000864+000903,op:splice,rep:2
 create mode 100644 test/data/cbor_regression/id:000001,sig:06,src:001310+001138,op:splice,rep:32
 create mode 100644 test/data/cbor_regression/id:000001,sig:06,src:001330+000569,op:splice,rep:64
 create mode 100644 test/data/cbor_regression/id:000001,sig:06,src:001413,op:havoc,rep:32
 create mode 100644 test/data/cbor_regression/id:000001,sig:06,src:001447,op:havoc,rep:4
 create mode 100644 test/data/cbor_regression/id:000001,sig:06,src:001465+000325,op:splice,rep:4
 create mode 100644 test/data/cbor_regression/id:000002,sig:06,src:000539,op:havoc,rep:8
 create mode 100644 test/data/cbor_regression/id:000002,sig:06,src:001301,op:havoc,rep:16
 create mode 100644 test/data/cbor_regression/id:000002,sig:06,src:001317+000850,op:splice,rep:8
 create mode 100644 test/data/cbor_regression/id:000002,sig:06,src:001382,op:havoc,rep:128
 create mode 100644 test/data/cbor_regression/id:000002,sig:06,src:001413+001036,op:splice,rep:4
 create mode 100644 test/data/cbor_regression/id:000003,sig:06,src:000846+000155,op:splice,rep:16
 create mode 100644 test/data/cbor_regression/id:000004,sig:06,src:001445,op:havoc,rep:128

diff --git a/src/json.hpp b/src/json.hpp
index cb301643..913f1966 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -6835,6 +6835,44 @@ class basic_json
         }
     }
 
+
+    /*
+    @brief checks if given lengths do not exceed the size of a given vector
+
+    To secure the access to the byte vector during CBOR/MessagePack
+    deserialization, bytes are copied from the vector into buffers. This
+    function checks if the number of bytes to copy (@a len) does not exceed the
+    size @s size of the vector. Additionally, an @a offset is given from where
+    to start reading the bytes.
+
+    This function checks whether reading the bytes is safe; that is, offset is a
+    valid index in the vector, offset+len
+
+    @param[in] size    size of the byte vector
+    @param[in] len     number of bytes to read
+    @param[in] offset  offset where to start reading
+
+    vec:  x x x x x X X X X X
+          ^         ^         ^
+          0         offset    len
+
+    @throws out_of_range if `len > v.size()`
+    */
+    static void check_length(const size_t size, const size_t len, const size_t offset)
+    {
+        // simple case: requested length is greater than the vector's length
+        if (len > size or offset > size)
+        {
+            throw std::out_of_range("len out of range");
+        }
+
+        // second case: adding offset would result in overflow
+        if ((size > (std::numeric_limits<size_t>::max() - offset)))
+        {
+            throw std::out_of_range("len+offset out of range");
+        }
+    }
+
     /*!
     @brief create a JSON value from a given MessagePack vector
 
@@ -6886,6 +6924,7 @@ class basic_json
                 const size_t len = v[current_idx] & 0x1f;
                 const size_t offset = current_idx + 1;
                 idx += len; // skip content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
         }
@@ -6989,6 +7028,7 @@ class basic_json
                     const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
                     const size_t offset = current_idx + 2;
                     idx += len + 1; // skip size byte + content bytes
+                    check_length(v.size(), len, offset);
                     return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
                 }
 
@@ -6997,6 +7037,7 @@ class basic_json
                     const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
                     const size_t offset = current_idx + 3;
                     idx += len + 2; // skip 2 size bytes + content bytes
+                    check_length(v.size(), len, offset);
                     return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
                 }
 
@@ -7005,6 +7046,7 @@ class basic_json
                     const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
                     const size_t offset = current_idx + 5;
                     idx += len + 4; // skip 4 size bytes + content bytes
+                    check_length(v.size(), len, offset);
                     return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
                 }
 
@@ -7223,6 +7265,7 @@ class basic_json
                 const auto len = static_cast<size_t>(v[current_idx] - 0x60);
                 const size_t offset = current_idx + 1;
                 idx += len; // skip content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7231,6 +7274,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
                 const size_t offset = current_idx + 2;
                 idx += len + 1; // skip size byte + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7239,6 +7283,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
                 const size_t offset = current_idx + 3;
                 idx += len + 2; // skip 2 size bytes + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7247,6 +7292,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
                 const size_t offset = current_idx + 5;
                 idx += len + 4; // skip 4 size bytes + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7255,6 +7301,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
                 const size_t offset = current_idx + 9;
                 idx += len + 8; // skip 8 size bytes + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7595,6 +7642,11 @@ class basic_json
     */
     static basic_json from_msgpack(const std::vector<uint8_t>& v)
     {
+        if (v.empty())
+        {
+            throw std::invalid_argument("empty vector");
+        }
+
         size_t i = 0;
         return from_msgpack_internal(v, i);
     }
@@ -7652,6 +7704,11 @@ class basic_json
     */
     static basic_json from_cbor(const std::vector<uint8_t>& v)
     {
+        if (v.empty())
+        {
+            throw std::invalid_argument("empty vector");
+        }
+
         size_t i = 0;
         return from_cbor_internal(v, i);
     }
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 6723e75a..3b598542 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -6835,6 +6835,44 @@ class basic_json
         }
     }
 
+
+    /*
+    @brief checks if given lengths do not exceed the size of a given vector
+
+    To secure the access to the byte vector during CBOR/MessagePack
+    deserialization, bytes are copied from the vector into buffers. This
+    function checks if the number of bytes to copy (@a len) does not exceed the
+    size @s size of the vector. Additionally, an @a offset is given from where
+    to start reading the bytes.
+
+    This function checks whether reading the bytes is safe; that is, offset is a
+    valid index in the vector, offset+len
+
+    @param[in] size    size of the byte vector
+    @param[in] len     number of bytes to read
+    @param[in] offset  offset where to start reading
+
+    vec:  x x x x x X X X X X
+          ^         ^         ^
+          0         offset    len
+
+    @throws out_of_range if `len > v.size()`
+    */
+    static void check_length(const size_t size, const size_t len, const size_t offset)
+    {
+        // simple case: requested length is greater than the vector's length
+        if (len > size or offset > size)
+        {
+            throw std::out_of_range("len out of range");
+        }
+
+        // second case: adding offset would result in overflow
+        if ((size > (std::numeric_limits<size_t>::max() - offset)))
+        {
+            throw std::out_of_range("len+offset out of range");
+        }
+    }
+
     /*!
     @brief create a JSON value from a given MessagePack vector
 
@@ -6886,6 +6924,7 @@ class basic_json
                 const size_t len = v[current_idx] & 0x1f;
                 const size_t offset = current_idx + 1;
                 idx += len; // skip content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
         }
@@ -6989,6 +7028,7 @@ class basic_json
                     const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
                     const size_t offset = current_idx + 2;
                     idx += len + 1; // skip size byte + content bytes
+                    check_length(v.size(), len, offset);
                     return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
                 }
 
@@ -6997,6 +7037,7 @@ class basic_json
                     const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
                     const size_t offset = current_idx + 3;
                     idx += len + 2; // skip 2 size bytes + content bytes
+                    check_length(v.size(), len, offset);
                     return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
                 }
 
@@ -7005,6 +7046,7 @@ class basic_json
                     const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
                     const size_t offset = current_idx + 5;
                     idx += len + 4; // skip 4 size bytes + content bytes
+                    check_length(v.size(), len, offset);
                     return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
                 }
 
@@ -7223,6 +7265,7 @@ class basic_json
                 const auto len = static_cast<size_t>(v[current_idx] - 0x60);
                 const size_t offset = current_idx + 1;
                 idx += len; // skip content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7231,6 +7274,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
                 const size_t offset = current_idx + 2;
                 idx += len + 1; // skip size byte + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7239,6 +7283,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
                 const size_t offset = current_idx + 3;
                 idx += len + 2; // skip 2 size bytes + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7247,6 +7292,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
                 const size_t offset = current_idx + 5;
                 idx += len + 4; // skip 4 size bytes + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7255,6 +7301,7 @@ class basic_json
                 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
                 const size_t offset = current_idx + 9;
                 idx += len + 8; // skip 8 size bytes + content bytes
+                check_length(v.size(), len, offset);
                 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
             }
 
@@ -7595,6 +7642,11 @@ class basic_json
     */
     static basic_json from_msgpack(const std::vector<uint8_t>& v)
     {
+        if (v.empty())
+        {
+            throw std::invalid_argument("empty vector");
+        }
+
         size_t i = 0;
         return from_msgpack_internal(v, i);
     }
@@ -7652,6 +7704,11 @@ class basic_json
     */
     static basic_json from_cbor(const std::vector<uint8_t>& v)
     {
+        if (v.empty())
+        {
+            throw std::invalid_argument("empty vector");
+        }
+
         size_t i = 0;
         return from_cbor_internal(v, i);
     }
diff --git a/test/data/cbor_regression/id:000000,sig:06,src:000223+000677,op:splice,rep:2 b/test/data/cbor_regression/id:000000,sig:06,src:000223+000677,op:splice,rep:2
new file mode 100644
index 00000000..e30ed176
--- /dev/null
+++ b/test/data/cbor_regression/id:000000,sig:06,src:000223+000677,op:splice,rep:2
@@ -0,0 +1 @@
+�{��������������
\ No newline at end of file
diff --git a/test/data/cbor_regression/id:000000,sig:06,src:000787,op:havoc,rep:8 b/test/data/cbor_regression/id:000000,sig:06,src:000787,op:havoc,rep:8
new file mode 100644
index 0000000000000000000000000000000000000000..8de7c9e50d18d64f7807ba158718d1f71895dcbb
GIT binary patch
literal 19
Ucmb>a4*~zI8JHLtY#4w50DwOT>;M1&

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000000,sig:06,src:000833,op:havoc,rep:32 b/test/data/cbor_regression/id:000000,sig:06,src:000833,op:havoc,rep:32
new file mode 100644
index 0000000000000000000000000000000000000000..d2ae80c771595f1dd59d700664577524eb5b6c78
GIT binary patch
literal 38
ncmb>a4+Yz{ZCko+8v~FsY*hH0R#}`{B9NAmvAB3qiNr4e3C$Nr

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000000,sig:06,src:000838,op:havoc,rep:64 b/test/data/cbor_regression/id:000000,sig:06,src:000838,op:havoc,rep:64
new file mode 100644
index 0000000000000000000000000000000000000000..d1ef19b507738ecf9c8e939347afc9087aad6876
GIT binary patch
literal 842
zcmb>a4+Yz{$)Db~EwwbYcH+c|^OvrjxCRUqz~oj20SI@^|MwFoPMEl8B2ZVup>5l?
zIcx@MO4*SF)C2^Ltq}Tri3G#{2FAoJ=bXmcYz2?hq6UUU28Hyzs?@xav}6VbCWay_
zl7JCb)j?QAQ3Z>D76NTeElSBt%uP)xF3p3=V>c32GkLs{%#ywm?bHf|U`fU=_3}V#
zvvU(O^Ww`h8Gs<Qq!_3GC@mG7Se%!eIsgtN;H||&7i_1B)3Ha3VOR!cLT6xPU?@&4
Hk@y7w=dWiJ

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000000,sig:06,src:000846+001064,op:splice,rep:16 b/test/data/cbor_regression/id:000000,sig:06,src:000846+001064,op:splice,rep:16
new file mode 100644
index 0000000000000000000000000000000000000000..42b437e065a2056b4964bea5475518ae21df225e
GIT binary patch
literal 201
zcmb>a4+Y!6fB{6-9|Do5w{1(!O|6{>0&6F(K>}OX#DIW3n4CBfs(v$2eM)K)SpCFC
u5Oo#;o<M2b)D4i-QQY!KGAS|T^$ZLQiMgqn#U*)$=^6fMX~n4}62Aa=JcT#_

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000000,sig:06,src:000848,op:flip1,pos:0 b/test/data/cbor_regression/id:000000,sig:06,src:000848,op:flip1,pos:0
new file mode 100644
index 0000000000000000000000000000000000000000..82f3520df29576b59353474e57367534541ac727
GIT binary patch
literal 263
zcmb>a4+Y!6fB{6-9|Do5w{1%;O|6{>0&6F(K>}OhY_KGVfN9zc)RdB%1QBn9N}n&0
z_?41al9=V3lbM{Y;E`I?z>vtGke-*DnpcvR3?x#EQi?OHQYBOpbMsS*OY;mHGyKz9
zi&IM^(lRniBpJWd%O~chX6Ghm=Eaw1=B31xr<P;_p>}G8RB&QwU2&>{H!go<Cgw1r
ST9pSh3v5dm(3TF6Ex!Pf-H5&b

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000000,sig:06,src:001435,op:havoc,rep:32 b/test/data/cbor_regression/id:000000,sig:06,src:001435,op:havoc,rep:32
new file mode 100644
index 0000000000000000000000000000000000000000..679a1663ad992f2b5702463eddfb0279f06d3c8e
GIT binary patch
literal 2488
zcmeHJ&rcIU6khZsCy(`D+>0b6(hUX^LPGdafk>dNZ4(a0gz3!N-GSMi?aY+!s*&o|
zo6*D@#Df?A0sjR42Tz_fF~JLHjL|x~Eu}PqH3ISAoaTG;_RV|W+q`d{)#i&!d9y^2
zLJQpOGYzRs8z}`MFheBe@Rs7`x`CDX!mLr{nZqV9@L@-7)kg>Sc0a!{SH3OX*tsx9
zc`&I$+oKE-VBuqmu9^0fl7IyEW&)Q6P~c^*<iJE_d1iX(R({qJsbPeaLxvRCf@6@9
ziyYfHydE8fDZ1bI?fTl`@rwutrg$Sf07vgW9DQ{B$<yPHpLZQU?81K!pR_}~dOcpO
zumTV&04v=z-Rsei-Bqx(4nj}@y8YgY#0Yy(0zd7HEGjM_bDe$ZSZ_P_|F<X1z{@{f
zCw%{zgqt*ay5>_)UZ?J4^p@?Z=W(VN{3G1=R`d7c+(bM^11&Rp<V|(xly|gFmAiB*
zOUmo2H4$yYxM(C=^^s|nj4pBEW-)(XZ)BHaNo%p2jLrwBvC(KGgVaWN4Y^Q4t}K8f
zK)Q2`ONm6R(}}KHRVggSF=CeDK1NCdS6Vslps2(-lUa?0Lm89=3Zw&KmNNn(8rlDH
zv;Aca$`0{qFc%G4SdVw8D+?tCOMuVUVIrOE<GPT#p+#2?P%^%%!!M$!NbkW)(0U8(
z<JB@0L1=B*W9{O#LTsueuYHTOe5suns3DvZa-~U#6M)Qm%Gaf(EVv+b1(;^Gt1U~L
zm!`yQ`vm<!={}E>@+(O?DYiAyH7<x~TS_3+?J9`asY;kH+Pji~gQ`p|(2Hum)v1tC
zqLOYTPmCm&D5Gg{XuAVr0?2d>DcOGCx$~*tstnsV-&uSY<#-Ut3~9=uty?K?Qla7k
zAktqsD6ZLDufIz^lbY8uq(*4nFbplFI$VZCm(xV@bF5EW5B;C5zoavemSvDA%3@z;
Gb3Xwc-m0Vk

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000000,sig:06,src:001436,op:havoc,rep:4 b/test/data/cbor_regression/id:000000,sig:06,src:001436,op:havoc,rep:4
new file mode 100644
index 0000000000000000000000000000000000000000..bb32f698895c0584b1476a95e8db9b6272bef2f5
GIT binary patch
literal 2579
zcmdT`&u<e)6t?N9oH)7%)D;3Gq{gf8LqbLo3WlVOOl)FT2yw~m&fDE_W_Q-}#__r!
z63)H$4yRr!E}Z%&@SpSm;slkdBFvlhdPzti3Lt3b;(5<{&)>ZFeee0V(Mq?y>hw4>
ztfj)L0yIvC83Q_TQieGH&?v7DzHvs*NSMf(cR)f6&&|W_i)UWG`1?<1{onS5=ifGj
zN=}-z6A8&U$TSk{2dA@W5SaF(Ye^^)SW})dc-kA>ymn>or`07_=Z-q}QppT-wDJK_
z>89M;eeUlzr`Du6cV?G8pa1Oe?3ZDOFWqtf>eqXp9l@_<#^3)~=nmu>aG|NI)HLe#
z#k~COP0(6!p!P@W=rccp9>n=q*fmN+?X0vsxn=J^Ynff@bI)(Y!q*B_U>Z1(2%54q
zT({M3F1CJbcYBTb^XJZ8x=L{#TN1KNX#%CYJGg=M$iyoD)eZ|`*wf74s681L9)E+J
zJr)*7p2QYOj%w9c0m}wc8}Pt5p2uy$t~h#8huA(+n(H!ikHm0e2zne05mvgL7sw%C
zLupzOnptU5Dc&0P4Oz`sNg%>ysSueSH#G1oV`y5GQ`C<SefZHqSs7e|Km$fc-)YhG
z;e7P!5QmGRh)tE$cy>HTzPc={l}d$>i-crJ6j}UeU2mF#L8Z2zN~&}Aozh|5SAT6!
z>Nm$IM&r=d^DdigO(vFj9cq5j@ac2kmJ<zO@-0b~8)QADB=$uj%v{Peiyv)B6}E^+
z7I${a9inz6nbI{XCNCKwx_LA5&^p;Vu)NeP!2tA<k{on)eir$lj2wX%q$#>oBm;?Y
z_eS}YtQuPWwCpUMUMkh9Me{7lPRw%7&{V29nj*kLq1hRWWH~!i{z~p}HN<KYF6Sgz
zpqg%1XkOxJ!58`zb)98h@e8acMW&hE_n?~#@}(^MVC!aV(PkcWW2;&TX3o!h^Zm3p
zK?3h+azAYyMCJb{bB|TL{|<A%3_nRNd-z$X<xBJP!Kd(3d~j#H-e+eVa`ua3W~CTv
zH2ZnE2o9Y6)g#~7e>wF&rp2~W`Zh_GW^aNuJ{{+F_u*Bc&3FyiVZ_75HVtih%R!_3
NefxuDbw9>>^9`wVbX@=d

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000001,sig:06,src:000864+000903,op:splice,rep:2 b/test/data/cbor_regression/id:000001,sig:06,src:000864+000903,op:splice,rep:2
new file mode 100644
index 0000000000000000000000000000000000000000..e94858106169ac59d0330ea1f59fcc42f09d2f2e
GIT binary patch
literal 33
ecmZ3OQa^bX!-NUe4Q2jmtlVHwUteGS9|i#A<`C`x

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000001,sig:06,src:001310+001138,op:splice,rep:32 b/test/data/cbor_regression/id:000001,sig:06,src:001310+001138,op:splice,rep:32
new file mode 100644
index 00000000..92079a80
--- /dev/null
+++ b/test/data/cbor_regression/id:000001,sig:06,src:001310+001138,op:splice,rep:32
@@ -0,0 +1 @@
+�{������������������������������et�
\ No newline at end of file
diff --git a/test/data/cbor_regression/id:000001,sig:06,src:001330+000569,op:splice,rep:64 b/test/data/cbor_regression/id:000001,sig:06,src:001330+000569,op:splice,rep:64
new file mode 100644
index 0000000000000000000000000000000000000000..0e3f141f863bb079b063807cf5accd2f27fadc2f
GIT binary patch
literal 1932
zcmeHIy-ve05VlYsfHz=bth4X}s8Xg@0yR4v$tAe8<H|lDf}t$DL7xC-UWcb(Lr93l
zByCWBV5t;ZRpO?*^Xa?KXWi$;;?8w%pX)*HvGwYk)s`PeN~B{n*AnSb+LhB!LE$tO
z63<o%^?eXZur_nfBs|nHWIT*4_r(ZHh^Gd`WLXpFxwI3J3hK|mfO?)v?GJSbbEnhn
z(7Uq6lX)mT(kcYXgTxM+M0YIu*fG8x(0yoI2blj5F5ggg-`>!z&SihA-D}NXYksfh
zZ^r%gVUQ~6EERDR(#aTem2`T8LYV`trRBMlnnK3|1F4PC_*zD2vZJ4(dxIA*e_#<1
z40SSsY%Ff^ob`~Pm<*bCNvLM>l<)-TQd7?NEh#cUXua0h4s`Y7D9fuGmQ(%$hfzmd

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000001,sig:06,src:001413,op:havoc,rep:32 b/test/data/cbor_regression/id:000001,sig:06,src:001413,op:havoc,rep:32
new file mode 100644
index 0000000000000000000000000000000000000000..0ce68701c4269554399e96dd393c063e3493f186
GIT binary patch
literal 1396
zcmc(fy>1gh5XaBBA{C_@q^ppSz$i!{WQ0UwLcj|4VH=@9LDsi(zBPBZ=bf?dtRQSU
zBpM1T8dA~l0z3;(Kt&ah5QW)W8!P^Z3kuk3=Qp!Eqn-cGyQI>nRqZBc#P(!6CjrTJ
z7!fGzcFYhrk4UyU;F6u#i6GzJv>|{HzR}U>#>MZ)KR(+BziQXMoGl3%ZBgv_B48YX
z*ca@Q?Q9VOQ?9==Xp0EyvLy*Gw7QRXwlCkW-o2s>DDqYuFak$O7Z9Z?2gCXGYTh)~
z;dpKt_IgF!49$g4jh`prEKqOWo;0R=SY&6cMRL0RY&h(%Tb<L7E_+^PXuQPpOJp@j
zmhqbz`uOQqqZ`$M3#GfRn@VKmOnYj5P)cyn^6(GPWv&n7VQ5^~AgQ2mHOO?dpY0#1
zAide)Ew>bkdnSfFsTvb8M41?{=&yT_zxKUYdGh*7`tRU}EY<$Hd{5Rn`?h6SYXkm^
zlbOC(UFos3oAut<j-DHdR9wwSQ;(I0Jx~L$hfrxa$H+ndyb<k*b5sFt1QG{=QxhhN
zD*6<r1y@Gn@zNjlM0+=oh)fMi3i$Q_%2@$n&dO(Fq}ah&7n7P|o<3k{Sw;~S_(ZY}
zYXjbSuV_#Q#y7e~#|GBHQ-J=)B<@ck*i_7YUf>BABi#cnZGByVr{{HTo~Z5yIZbsT
XBGS3D8Q8;xiw>uMgr!9{#QfLaIWB|R

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000001,sig:06,src:001447,op:havoc,rep:4 b/test/data/cbor_regression/id:000001,sig:06,src:001447,op:havoc,rep:4
new file mode 100644
index 0000000000000000000000000000000000000000..35f3cb597438e5ac05686abe6588f769b8e233a4
GIT binary patch
literal 1839
zcmcJQ&ubGw6vq>LvLJZOMO*|61)HU|LP;r7(;pgQ5|fCCm(K3I%}zSIlgvz-je?DM
z^y0yj7kly|UOf3H^l$Jl@F1RAK`hp{n@vp8h+1?mnfJ}in>X)$-p-45u2L)*RZ29;
zi&|2E(ng7B4bnFnM5*~bEv!1&+GrbXrd?y+01h5})_dKh*~5b`?~Sc*#cLnVW|;6-
zb))1mPAKq(%g7a@w5k;lX}jy48uOtnETPqm)x5WUWA0XA!<3PbrdER!4J9dTP)f)w
z-yI!KM$O22bUZR9tQeC<mdD1|A#r&5^I;>N!vyVrNslKxo|-J5P}?Vz-Dd;o^_!JS
zlb3-qiFL)YVYQc{0u*;ZN=5+zaJQ6AY!|BFMSrP^77|idc}U9raDG?vV7X2$JL551
z3MCw!QBAHu?pQKon)zaOHGi{Msb=OE7Z#S+aGyms7$3OQj*yie9ezlMO1s(<(Wxa;
zgH}}%dpot?iWPes#VV<Vk@RWpVVg)MZKByHKe%MJlr%Xy;ieXzO%h2iYRZi9PNRWz
zdd%MpW=$J!4!$-c!Ia>M9k?DHwxYr7CXh&Vj?tAm?z&Ba3VR4!e(b4l*Da{vg+U&2
z+|#2NlP9zgT=f-YdSO;L=sBBXPX!l+tfg(?{Je9{#iZvzO}O*Bcy#-dv0pmf9OO)u
z!I7Zc>9OMV+|u^Z??&JEKXrO^gc%=BFw&D1eu@Th#-#9wB;MO?%yb@$7eX0a9<Qaw
z!eTA6!XZI5%x_pu>4Zc{;wuN_hTs%ru-M=EDyBf2ZLpk1Lk((va+i(HlC`+JNijke
zMstF!IGR(FHFFBGo@zI7{D)-G(Qb;!Vw1ZG`+DD_<U5IayntYmpc!5)vP(#8TSzJg
zN);c8J1vkMr==iQDIF*Z4ry_nXXkYeXw(J`&ZzExJ;GRm6gHg0YMWdrMPw%<f!^pK
z2zZ*8JTn!(0O`7F3{HN4O@^5GDn)xZhhGJ?_EPFj8OYxdN?A9NNDQdE5Cu}$<VjR9
U5a#3A(ew4I{vkoy_SDqJA7y<u2LJ#7

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000001,sig:06,src:001465+000325,op:splice,rep:4 b/test/data/cbor_regression/id:000001,sig:06,src:001465+000325,op:splice,rep:4
new file mode 100644
index 0000000000000000000000000000000000000000..64812d4f4540f9794ab32226c6a42988c207836a
GIT binary patch
literal 475
zcmZ3OGHdcIh6xj_8_N9CSa<znHC~ijY$%W~X_Ny5)(X}F)?U`W?$-YyAT=*H4X*-L
z2~25{4XZ}7Ek8cB#42S+NJe^cer|4RUP-RLzJk7kf{miCi2?%;0|UeFl#-&-)UTPT
znkaxFF{eU4!Em~wgR+WhoSK%Qk+F%XnYo2!BG??)-|oz;P5&KoQ;Y8oGQb$jz#zao
zU8FR%ur$9UHAg8eKPf9Uxul`OQa?uNO+j9IW@1iedIu;p(vpEhYEepFVs2_macQ1m
OdWL^mT5)QL#4i8}qWaVT

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000002,sig:06,src:000539,op:havoc,rep:8 b/test/data/cbor_regression/id:000002,sig:06,src:000539,op:havoc,rep:8
new file mode 100644
index 0000000000000000000000000000000000000000..5c537f8d79df076878d1fc1f8a37152d2e810812
GIT binary patch
literal 140
zcmZ3OR-T!Xo?5abHHCqZfgveBulhfB@Kb<+f#K)RlAS53#c`EsetD@4#=kQ265l4L
zmZVmc2ry*$rzIw5mKYdlDjZWtNi0ds$xJWFO=S>ZNL9}$kyOZ=n9C0|A}^(6ngipP
Xw8GTP^qdk&qc16WiMcu1h7!L3r4T|{

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000002,sig:06,src:001301,op:havoc,rep:16 b/test/data/cbor_regression/id:000002,sig:06,src:001301,op:havoc,rep:16
new file mode 100644
index 0000000000000000000000000000000000000000..0bde9e5dafffd9b12824980438be7148cc5b4cbd
GIT binary patch
literal 16
OcmeC4QvDwR7=!?C;0&Sw

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000002,sig:06,src:001317+000850,op:splice,rep:8 b/test/data/cbor_regression/id:000002,sig:06,src:001317+000850,op:splice,rep:8
new file mode 100644
index 0000000000000000000000000000000000000000..0a004d9e5d88a9143366bb06355f4802b8978194
GIT binary patch
literal 349
zcmbPI{hvs1k4SY?SM~;I;<nV3)TD`E&<LR>o-dL3m6BMJnB|<4nVhZQky_NikjS8r
zo|l`NSCW<tBvOk~iZiQHB~%h~^HYjT^9&m^{L@;CQ%fY$GBQde8NbxaC+4PR=O*Um
z#g}L1rNoq{mSh5<c4~!GaAIg(ajJqh)HmC}Km<hA9|Dn?i8+j@R^<WB0^1S>w50=N
G%P#;ZUH69o

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000002,sig:06,src:001382,op:havoc,rep:128 b/test/data/cbor_regression/id:000002,sig:06,src:001382,op:havoc,rep:128
new file mode 100644
index 0000000000000000000000000000000000000000..6ff4823ae78f780f81f09637fa08249459c2338e
GIT binary patch
literal 3116
zcmZ3OGHdcIh6xj_8_N9CSa<znl~|NoY$%W~X_S+b(-fg#EnsYG?dxv+9|BVIa+`q)
zJfRA5tbq!wy{vP=3V#3ppITU&Uy+)q#M<=VBR92}F_?itfML2wsRB^E1Sp;c)ff-a
zSWw7NTvFOzo?ewwQdFAyH8E8a9h5UNFfjP)<<}SIr|V~A73b%bR9BSr8&*SI1f*CP
zAnf$yn%vUVypkw=eFc371sg?O69onyp!VMk42%q^Uo%0bW3dNAc}j^G&@s4_LtRLO
z!(dKKPtMQHO=S?kbQsJgb`)<jB<B1FI(wy}gR+WhoSK%Qk+F%XfVqWbBG4TFJlEgu
z%;*8UYTv7MTX~pxITH-)bj4L1{M58GAd&W_d*AC-0ti{4nMktr|AA4OwkQ=Pih+E1
z8pw$TMzJ<5ia|bV06MK06r!Lc0!snD?%*Wj3FAXj1V}kJMPVvON>OQxfC&fTihD=^
zmJ%^tfy3DRUvO8cB0Cy~a;PgFg01&Mcv=CJu6<DxesX@ie~A@5wUg>MMh2i|+M{4J
z1V%$(Gz11o2!IMPXxWP>{NN>izN8&e5ucl8EdW*zD$+f`HGmqDG@=Gk0GH(m^Pr6c
zgaS}$>mQ$5VwJKZBm+`8LTYUXNUaU4$cV10vcb(2j7s7$j#3}ex<RX|2Cj7iYXnf-
zI$;oiHzSZ*C$Tu1O^~?!{~tL5P@7Fqhhan$14`p69MM{WSPyJ)VTgfc1VHT?9){_P
zkg7Bb6#IRkrV+L_8y+JVfJT6uMzH22G%5=awt$q-$d<`eX|%#Z|9=r0NGO6eqSK0!
zvQm>v8Y(RH1(cqw1~%i68hNn1;TEs0`+oC0P`eK(1T%FDknsW7PGcy~EXhzXRLD)u
zO-e0NvWiwpEH7fH)Bp=xDtP6j=B8$pD8<(1DikXeD6p`yvAa3?xVd|HdU^Z!`uPV4
Q1_g(N&g}dzz`*bU07#X%a{vGU

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000002,sig:06,src:001413+001036,op:splice,rep:4 b/test/data/cbor_regression/id:000002,sig:06,src:001413+001036,op:splice,rep:4
new file mode 100644
index 0000000000000000000000000000000000000000..d32904abc2805ce51238f7023c52ab0f6152b0f2
GIT binary patch
literal 395
zcmbPI?iK9srx22oSd!?IpU#+{T3n(KkXTZZT9l_ykXT%7xS%9IDJwO(M4?=vJhLQ2
z!B8PJCp9<qUCDw53(c=zzU@#*`0a0ci_<DIKhLqGARr?%Cov^8rywIUQAZ)bv7|UP
zu_!siwK6?3FEuDXDZivxEvYcv)k)XW&rQDwETET?RFIQck{VEypPX7;oL}UeQ;!N7
zQMnM_|N8$(0GkRFv1%m6aOO`q>;Hdb)f138V78{F0|P^1PKA7eVe0gX!Xt~-fC3^Y
z0%|$G4;=P#ZGV0s&o?DAJ+masz|hDzH!nRiF()%UFE=HxB(3IYDllwQN)vNaQ;JI&
Q8PYTS)6$AlOC){)06NLQRsaA1

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000003,sig:06,src:000846+000155,op:splice,rep:16 b/test/data/cbor_regression/id:000003,sig:06,src:000846+000155,op:splice,rep:16
new file mode 100644
index 0000000000000000000000000000000000000000..156afe0f177baf655b54b410a2128abd6b8002f9
GIT binary patch
literal 222
zcmb>a4+XUofnf65i7(bnYy`5-mq`3dNi0dsa?Z(2&Q|b9Eoxv$WKc-Y%T3KINh{Ax
zDap`f{F0WDnwjpDotsf2$@nEDFEJO$PRz`UFVD<N$uCbW$t=l9t&j>%%q_?{qTrpM
zmzJ1Rnv+<PU!)M8nUbDblA4*Dn4Y>cz05x?4To@XD$phMKu6|zg48zX2k*_(E67XF
hOw7rIx+WOtq|_pi^{FYvrFn)r89?KTQ+p(S0RTe0Vu%0$

literal 0
HcmV?d00001

diff --git a/test/data/cbor_regression/id:000004,sig:06,src:001445,op:havoc,rep:128 b/test/data/cbor_regression/id:000004,sig:06,src:001445,op:havoc,rep:128
new file mode 100644
index 0000000000000000000000000000000000000000..e342979eb1b875aadac159e722c4259527aec25c
GIT binary patch
literal 4382
zcmeHKPmkL~6rTvhp{E|h0V$VqKs3?P3Zbl!*zTXgDrCbZ)p9}Ei9NPwGw~!dlg6Q?
zUdoOCLWm>ni3<Xu{S^HGd<T%Y(!)xK@WzfECwAO4pzVcs@q2GP_M4gae(yKmj`o`e
z^-{~k3fD@gz=>3)23Cp)x75c{Zah@Hb3zPN8kI&=IVC@qk7I47+?hN{{GDee5ZbDL
zuV)2`R-K(Sc_Ygi`q1g}vHwTH9l+i`=S-Fvw}nL+X$kB~i-<jrZ6d)kXz|g|z=lH_
z*yw_@g>BhXT#(|Uo{9g)b%R^jGjyg0?gnJ{hznCho>~i%|2>n4u{D&t`_0Cm(j*oh
zGBx>PX;z;nMrLK;-%aR|`i<|Oot>GN2Gb}%Ao7q{;(h5{l7Xv5dVPjfxSVd$9Q~D)
zuaZVuH|ca;+uSXh-b)5|En2_H3J4)Fu2L7iOu4(I`VEINY!cRYD1Non*fJ%-!f<w7
zo4VwXces)-cLqnhH?F=@->ZngQ8s(G6}k7R4zD4&L8Rp34+dN4y~u@KHu!I+lk(A6
z($Uz~>$r<2{$#Rn9D2D#+BX@O5<^f@K}-g~jl(OJ*U|@kLS3q^_OZadpSp0^HEslP
zdsiw$DJl$1R#ChMUNCG~+196;&W#dE<wkT4emmAyR_vAE%z2SUWA`E@cz!)+t!I1|
zPy6A=H=6@?NK7gSB!5OW#II&4PxGPtv{Fw_t906Yj@@ZgA7w=s_>k{Ej0S&yF4BT0
zME`y0NN$6nXv2k;_J*#m!oh7K1T_IBlyjUYyicI;LcDm5X-L@A*l|lRZ}Y_L7}Xv%
z1ee@WRXJdi2>431Qm7qlZ`IyDXtt^w*RNgM+<|!=yr=PLTFc7fqM4{KS$0$pk~qLA
zn+!E_b&EgeAlJ04L--o#$e1E`T0&QISQWn}ssd+JMLQ2M<Na&L+R6%4#dqP$-FQv}
zIk96wd11j$oAcF?9?$e>n65ceMf=`oG%}8e-gB=QAYu$Yw*)b7jG;a(45*xvUs9eV
zbVJLTLH7)c*T>++Vo9`#xqs=riIy02y^CuTL5Q!XWT8!TpiP8bY<Zj5joO5DVQm5-
zXhs=rBBBtzl_*324`CtZ@CZ1d8IK@q@(7j8@^;ej7kNY?LGJ%YJVI|*M(0=&@UP_Y
z2uP3#LYL=xME7ZU#J{7&wI$PSc_`OpC;3byO0fh>jgNDBu%p=VI7{MDt;{nKi-4=G
z{p-qFXq)@9ObW5{EV&3m1(Zc`5jsT?#m(X(c@!3*=QXcRQP@}3q_6?|&A8q$xR7|)
zBl7zoAirOdV^<S_8n@rYUXy-Ej!!zI8IY34zz(JW3<T!^k(HiiD{SHF1LS-%z4}C4
z<U$~@MlY-VX@Jn9&A4I5*P<z$k>%GSlb)jUJei!IBea-sCLCCN6?zNQEfqBJg&*w!
N4a8pAxG&4w{{SA`b1?t_

literal 0
HcmV?d00001

diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp
index 14944cff..5769ac98 100644
--- a/test/src/unit-cbor.cpp
+++ b/test/src/unit-cbor.cpp
@@ -1186,6 +1186,84 @@ TEST_CASE("single CBOR roundtrip")
     }
 }
 
+TEST_CASE("CBOR regressions")
+{
+    SECTION("fuzz test results")
+    {
+        /*
+        The following test cases were found during a two-day session with
+        AFL-Fuzz. As a result, empty byte vectors and excessive lengths are
+        detected.
+        */
+        for (std::string filename :
+                {
+                    "test/data/cbor_regression/id:000000,sig:06,src:000223+000677,op:splice,rep:2",
+                    "test/data/cbor_regression/id:000000,sig:06,src:000787,op:havoc,rep:8",
+                    "test/data/cbor_regression/id:000000,sig:06,src:000833,op:havoc,rep:32",
+                    "test/data/cbor_regression/id:000000,sig:06,src:000838,op:havoc,rep:64",
+                    "test/data/cbor_regression/id:000000,sig:06,src:000846+001064,op:splice,rep:16",
+                    "test/data/cbor_regression/id:000000,sig:06,src:000848,op:flip1,pos:0",
+                    "test/data/cbor_regression/id:000000,sig:06,src:001435,op:havoc,rep:32",
+                    "test/data/cbor_regression/id:000000,sig:06,src:001436,op:havoc,rep:4v",
+                    "test/data/cbor_regression/id:000001,sig:06,src:000864+000903,op:splice,rep:2",
+                    "test/data/cbor_regression/id:000001,sig:06,src:001310+001138,op:splice,rep:32",
+                    "test/data/cbor_regression/id:000001,sig:06,src:001330+000569,op:splice,rep:64",
+                    "test/data/cbor_regression/id:000001,sig:06,src:001413,op:havoc,rep:32",
+                    "test/data/cbor_regression/id:000001,sig:06,src:001447,op:havoc,rep:4",
+                    "test/data/cbor_regression/id:000001,sig:06,src:001465+000325,op:splice,rep:4",
+                    "test/data/cbor_regression/id:000002,sig:06,src:000539,op:havoc,rep:8",
+                    "test/data/cbor_regression/id:000002,sig:06,src:001301,op:havoc,rep:16",
+                    "test/data/cbor_regression/id:000002,sig:06,src:001317+000850,op:splice,rep:8",
+                    "test/data/cbor_regression/id:000002,sig:06,src:001382,op:havoc,rep:128",
+                    "test/data/cbor_regression/id:000002,sig:06,src:001413+001036,op:splice,rep:4",
+                    "test/data/cbor_regression/id:000003,sig:06,src:000846+000155,op:splice,rep:16",
+                    "test/data/cbor_regression/id:000004,sig:06,src:001445,op:havoc,rep:128"
+                })
+        {
+            CAPTURE(filename);
+
+            try
+            {
+                // parse CBOR file
+                std::ifstream f_cbor(filename, std::ios::binary);
+                std::vector<uint8_t> vec1(
+                    (std::istreambuf_iterator<char>(f_cbor)),
+                    std::istreambuf_iterator<char>());
+                json j1 = json::from_cbor(vec1);
+
+                try
+                {
+                    // step 2: round trip
+                    std::vector<uint8_t> vec2 = json::to_cbor(j1);
+
+                    // parse serialization
+                    json j2 = json::from_cbor(vec2);
+
+                    // deserializations must match
+                    CHECK(j1 == j2);
+                }
+                catch (const std::invalid_argument&)
+                {
+                    // parsing a CBOR serialization must not fail
+                    CHECK(false);
+                }
+            }
+            catch (const std::invalid_argument&)
+            {
+                // parse errors are ok, because input may be random bytes
+            }
+            catch (const std::out_of_range&)
+            {
+                // parse errors are ok, because input may be random bytes
+            }
+            catch (const std::domain_error&)
+            {
+                // parse errors are ok, because input may be random bytes
+            }
+        }
+    }
+}
+
 TEST_CASE("CBOR roundtrips", "[hide]")
 {
     SECTION("input from flynn")