Skip to content

Commit bbe337c

Browse files
barcodebarcode
and
barcode
authored
Prevent memory leak when exception is thrown in adl_serializer::to_json (nlohmann#3901)
Co-authored-by: barcode <[email protected]>
1 parent fe4b663 commit bbe337c

15 files changed

+1321
-1167
lines changed

.cirrus.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ check_task:
77
- tar xfz cmake-3.20.2.tar.gz
88
- cd cmake-3.20.2
99
- ./configure
10-
- make cmake ctest -j10
10+
- make cmake ctest -j4
1111
- cd ..
1212
- mkdir build
1313
- cd build
1414
- ../cmake-3.20.2/bin/cmake .. -DJSON_FastTests=ON
15-
- make -j10
15+
- make -j4
1616
- cd tests
17-
- ../../cmake-3.20.2/bin/ctest -j10
17+
- ../../cmake-3.20.2/bin/ctest -j4

include/nlohmann/detail/conversions/to_json.hpp

+57-57
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace detail
3434

3535
/*
3636
* Note all external_constructor<>::construct functions need to call
37-
* j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
37+
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
3838
* allocated value (e.g., a string). See bug issue
3939
* https://github.com/nlohmann/json/issues/2865 for more information.
4040
*/
@@ -47,9 +47,9 @@ struct external_constructor<value_t::boolean>
4747
template<typename BasicJsonType>
4848
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
4949
{
50-
j.m_value.destroy(j.m_type);
51-
j.m_type = value_t::boolean;
52-
j.m_value = b;
50+
j.m_data.m_value.destroy(j.m_data.m_type);
51+
j.m_data.m_type = value_t::boolean;
52+
j.m_data.m_value = b;
5353
j.assert_invariant();
5454
}
5555
};
@@ -60,18 +60,18 @@ struct external_constructor<value_t::string>
6060
template<typename BasicJsonType>
6161
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
6262
{
63-
j.m_value.destroy(j.m_type);
64-
j.m_type = value_t::string;
65-
j.m_value = s;
63+
j.m_data.m_value.destroy(j.m_data.m_type);
64+
j.m_data.m_type = value_t::string;
65+
j.m_data.m_value = s;
6666
j.assert_invariant();
6767
}
6868

6969
template<typename BasicJsonType>
7070
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
7171
{
72-
j.m_value.destroy(j.m_type);
73-
j.m_type = value_t::string;
74-
j.m_value = std::move(s);
72+
j.m_data.m_value.destroy(j.m_data.m_type);
73+
j.m_data.m_type = value_t::string;
74+
j.m_data.m_value = std::move(s);
7575
j.assert_invariant();
7676
}
7777

@@ -80,9 +80,9 @@ struct external_constructor<value_t::string>
8080
int > = 0 >
8181
static void construct(BasicJsonType& j, const CompatibleStringType& str)
8282
{
83-
j.m_value.destroy(j.m_type);
84-
j.m_type = value_t::string;
85-
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
83+
j.m_data.m_value.destroy(j.m_data.m_type);
84+
j.m_data.m_type = value_t::string;
85+
j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
8686
j.assert_invariant();
8787
}
8888
};
@@ -93,18 +93,18 @@ struct external_constructor<value_t::binary>
9393
template<typename BasicJsonType>
9494
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
9595
{
96-
j.m_value.destroy(j.m_type);
97-
j.m_type = value_t::binary;
98-
j.m_value = typename BasicJsonType::binary_t(b);
96+
j.m_data.m_value.destroy(j.m_data.m_type);
97+
j.m_data.m_type = value_t::binary;
98+
j.m_data.m_value = typename BasicJsonType::binary_t(b);
9999
j.assert_invariant();
100100
}
101101

102102
template<typename BasicJsonType>
103103
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
104104
{
105-
j.m_value.destroy(j.m_type);
106-
j.m_type = value_t::binary;
107-
j.m_value = typename BasicJsonType::binary_t(std::move(b));
105+
j.m_data.m_value.destroy(j.m_data.m_type);
106+
j.m_data.m_type = value_t::binary;
107+
j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
108108
j.assert_invariant();
109109
}
110110
};
@@ -115,9 +115,9 @@ struct external_constructor<value_t::number_float>
115115
template<typename BasicJsonType>
116116
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
117117
{
118-
j.m_value.destroy(j.m_type);
119-
j.m_type = value_t::number_float;
120-
j.m_value = val;
118+
j.m_data.m_value.destroy(j.m_data.m_type);
119+
j.m_data.m_type = value_t::number_float;
120+
j.m_data.m_value = val;
121121
j.assert_invariant();
122122
}
123123
};
@@ -128,9 +128,9 @@ struct external_constructor<value_t::number_unsigned>
128128
template<typename BasicJsonType>
129129
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
130130
{
131-
j.m_value.destroy(j.m_type);
132-
j.m_type = value_t::number_unsigned;
133-
j.m_value = val;
131+
j.m_data.m_value.destroy(j.m_data.m_type);
132+
j.m_data.m_type = value_t::number_unsigned;
133+
j.m_data.m_value = val;
134134
j.assert_invariant();
135135
}
136136
};
@@ -141,9 +141,9 @@ struct external_constructor<value_t::number_integer>
141141
template<typename BasicJsonType>
142142
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
143143
{
144-
j.m_value.destroy(j.m_type);
145-
j.m_type = value_t::number_integer;
146-
j.m_value = val;
144+
j.m_data.m_value.destroy(j.m_data.m_type);
145+
j.m_data.m_type = value_t::number_integer;
146+
j.m_data.m_value = val;
147147
j.assert_invariant();
148148
}
149149
};
@@ -154,19 +154,19 @@ struct external_constructor<value_t::array>
154154
template<typename BasicJsonType>
155155
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
156156
{
157-
j.m_value.destroy(j.m_type);
158-
j.m_type = value_t::array;
159-
j.m_value = arr;
157+
j.m_data.m_value.destroy(j.m_data.m_type);
158+
j.m_data.m_type = value_t::array;
159+
j.m_data.m_value = arr;
160160
j.set_parents();
161161
j.assert_invariant();
162162
}
163163

164164
template<typename BasicJsonType>
165165
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
166166
{
167-
j.m_value.destroy(j.m_type);
168-
j.m_type = value_t::array;
169-
j.m_value = std::move(arr);
167+
j.m_data.m_value.destroy(j.m_data.m_type);
168+
j.m_data.m_type = value_t::array;
169+
j.m_data.m_value = std::move(arr);
170170
j.set_parents();
171171
j.assert_invariant();
172172
}
@@ -179,24 +179,24 @@ struct external_constructor<value_t::array>
179179
using std::begin;
180180
using std::end;
181181

182-
j.m_value.destroy(j.m_type);
183-
j.m_type = value_t::array;
184-
j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
182+
j.m_data.m_value.destroy(j.m_data.m_type);
183+
j.m_data.m_type = value_t::array;
184+
j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
185185
j.set_parents();
186186
j.assert_invariant();
187187
}
188188

189189
template<typename BasicJsonType>
190190
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
191191
{
192-
j.m_value.destroy(j.m_type);
193-
j.m_type = value_t::array;
194-
j.m_value = value_t::array;
195-
j.m_value.array->reserve(arr.size());
192+
j.m_data.m_value.destroy(j.m_data.m_type);
193+
j.m_data.m_type = value_t::array;
194+
j.m_data.m_value = value_t::array;
195+
j.m_data.m_value.array->reserve(arr.size());
196196
for (const bool x : arr)
197197
{
198-
j.m_value.array->push_back(x);
199-
j.set_parent(j.m_value.array->back());
198+
j.m_data.m_value.array->push_back(x);
199+
j.set_parent(j.m_data.m_value.array->back());
200200
}
201201
j.assert_invariant();
202202
}
@@ -205,13 +205,13 @@ struct external_constructor<value_t::array>
205205
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
206206
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
207207
{
208-
j.m_value.destroy(j.m_type);
209-
j.m_type = value_t::array;
210-
j.m_value = value_t::array;
211-
j.m_value.array->resize(arr.size());
208+
j.m_data.m_value.destroy(j.m_data.m_type);
209+
j.m_data.m_type = value_t::array;
210+
j.m_data.m_value = value_t::array;
211+
j.m_data.m_value.array->resize(arr.size());
212212
if (arr.size() > 0)
213213
{
214-
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
214+
std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
215215
}
216216
j.set_parents();
217217
j.assert_invariant();
@@ -224,19 +224,19 @@ struct external_constructor<value_t::object>
224224
template<typename BasicJsonType>
225225
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
226226
{
227-
j.m_value.destroy(j.m_type);
228-
j.m_type = value_t::object;
229-
j.m_value = obj;
227+
j.m_data.m_value.destroy(j.m_data.m_type);
228+
j.m_data.m_type = value_t::object;
229+
j.m_data.m_value = obj;
230230
j.set_parents();
231231
j.assert_invariant();
232232
}
233233

234234
template<typename BasicJsonType>
235235
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
236236
{
237-
j.m_value.destroy(j.m_type);
238-
j.m_type = value_t::object;
239-
j.m_value = std::move(obj);
237+
j.m_data.m_value.destroy(j.m_data.m_type);
238+
j.m_data.m_type = value_t::object;
239+
j.m_data.m_value = std::move(obj);
240240
j.set_parents();
241241
j.assert_invariant();
242242
}
@@ -248,9 +248,9 @@ struct external_constructor<value_t::object>
248248
using std::begin;
249249
using std::end;
250250

251-
j.m_value.destroy(j.m_type);
252-
j.m_type = value_t::object;
253-
j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
251+
j.m_data.m_value.destroy(j.m_data.m_type);
252+
j.m_data.m_type = value_t::object;
253+
j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
254254
j.set_parents();
255255
j.assert_invariant();
256256
}

include/nlohmann/detail/exceptions.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ class exception : public std::exception
7373
{
7474
case value_t::array:
7575
{
76-
for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
76+
for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)
7777
{
78-
if (&current->m_parent->m_value.array->operator[](i) == current)
78+
if (&current->m_parent->m_data.m_value.array->operator[](i) == current)
7979
{
8080
tokens.emplace_back(std::to_string(i));
8181
break;
@@ -86,7 +86,7 @@ class exception : public std::exception
8686

8787
case value_t::object:
8888
{
89-
for (const auto& element : *current->m_parent->m_value.object)
89+
for (const auto& element : *current->m_parent->m_data.m_value.object)
9090
{
9191
if (&element.second == current)
9292
{

include/nlohmann/detail/input/json_sax.hpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class json_sax_dom_parser
244244
JSON_ASSERT(ref_stack.back()->is_object());
245245

246246
// add null at given key and store the reference for later
247-
object_element = &(ref_stack.back()->m_value.object->operator[](val));
247+
object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));
248248
return true;
249249
}
250250

@@ -319,8 +319,8 @@ class json_sax_dom_parser
319319

320320
if (ref_stack.back()->is_array())
321321
{
322-
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
323-
return &(ref_stack.back()->m_value.array->back());
322+
ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
323+
return &(ref_stack.back()->m_data.m_value.array->back());
324324
}
325325

326326
JSON_ASSERT(ref_stack.back()->is_object());
@@ -439,7 +439,7 @@ class json_sax_dom_callback_parser
439439
// add discarded value at given key and store the reference for later
440440
if (keep && ref_stack.back())
441441
{
442-
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
442+
object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
443443
}
444444

445445
return true;
@@ -524,7 +524,7 @@ class json_sax_dom_callback_parser
524524
// remove discarded value
525525
if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
526526
{
527-
ref_stack.back()->m_value.array->pop_back();
527+
ref_stack.back()->m_data.m_value.array->pop_back();
528528
}
529529

530530
return true;
@@ -607,8 +607,8 @@ class json_sax_dom_callback_parser
607607
// array
608608
if (ref_stack.back()->is_array())
609609
{
610-
ref_stack.back()->m_value.array->emplace_back(std::move(value));
611-
return {true, &(ref_stack.back()->m_value.array->back())};
610+
ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
611+
return {true, &(ref_stack.back()->m_data.m_value.array->back())};
612612
}
613613

614614
// object

0 commit comments

Comments
 (0)