Skip to content

Commit 12696d6

Browse files
committed
Work around GCC UBSAN+inline constexpr bug
See bug here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 We cannot at compile-time compare a pointer to nullptr if we are using UBSAN, in GCC, if that pointer exists as inline constexpr data object.
1 parent e51a513 commit 12696d6

File tree

1 file changed

+53
-20
lines changed

1 file changed

+53
-20
lines changed

include/json2cpp/json2cpp.hpp

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ template<typename CharType> struct data_variant
126126
// cppcheck-suppress noExplicitConstructor
127127
constexpr data_variant(std::basic_string_view<CharType> s) : value{ s }, selected{ selected_type::string } {}
128128

129+
[[nodiscard]] constexpr bool is_boolean() const noexcept {
130+
return selected == selected_type::boolean;
131+
}
132+
129133
[[nodiscard]] constexpr const bool *get_if_boolean() const noexcept
130134
{
131135
if (selected == selected_type::boolean) {
@@ -135,51 +139,80 @@ template<typename CharType> struct data_variant
135139
}
136140
}
137141

142+
[[nodiscard]] constexpr bool is_array() const noexcept {
143+
return selected == selected_type::array;
144+
}
145+
138146
[[nodiscard]] constexpr const basic_array_t<CharType> *get_if_array() const noexcept
139147
{
140-
if (selected == selected_type::array) {
148+
if (is_array()) {
141149
return &value.array_;
142150
} else {
143151
return nullptr;
144152
}
145153
}
154+
155+
[[nodiscard]] constexpr bool is_object() const noexcept {
156+
return selected == selected_type::object;
157+
}
158+
146159
[[nodiscard]] constexpr const basic_object_t<CharType> *get_if_object() const noexcept
147160
{
148-
if (selected == selected_type::object) {
161+
if (is_object()) {
149162
return &value.object_;
150163
} else {
151164
return nullptr;
152165
}
153166
}
167+
168+
[[nodiscard]] constexpr bool is_integer() const noexcept {
169+
return selected == selected_type::integer;
170+
}
171+
154172
[[nodiscard]] constexpr const std::int64_t *get_if_integer() const noexcept
155173
{
156-
if (selected == selected_type::integer) {
174+
if (is_integer()) {
157175
return &value.int64_t_;
158176
} else {
159177
return nullptr;
160178
}
161179
}
180+
181+
[[nodiscard]] constexpr bool is_uinteger() const noexcept {
182+
return selected == selected_type::uinteger;
183+
}
184+
162185
[[nodiscard]] constexpr const std::uint64_t *get_if_uinteger() const noexcept
163186
{
164-
if (selected == selected_type::uinteger) {
187+
if (is_uinteger()) {
165188
return &value.uint64_t_;
166189
} else {
167190
return nullptr;
168191
}
169192
}
170193

194+
195+
[[nodiscard]] constexpr bool is_floating_point() const noexcept {
196+
return selected == selected_type::floating_point;
197+
}
198+
199+
171200
[[nodiscard]] constexpr const double *get_if_floating_point() const noexcept
172201
{
173-
if (selected == selected_type::floating_point) {
202+
if (is_floating_point()) {
174203
return &value.double_;
175204
} else {
176205
return nullptr;
177206
}
178207
}
179208

209+
[[nodiscard]] constexpr bool is_string() const noexcept {
210+
return selected == selected_type::string;
211+
}
212+
180213
[[nodiscard]] constexpr const std::basic_string_view<CharType> *get_if_string() const noexcept
181214
{
182-
if (selected == selected_type::string) {
215+
if (is_string()) {
183216
return &value.string_view_;
184217
} else {
185218
return nullptr;
@@ -369,17 +402,17 @@ template<typename CharType> struct basic_json
369402

370403
constexpr const auto &array_data() const
371404
{
372-
if (const auto *result = data.get_if_array(); result != nullptr) {
373-
return *result;
405+
if (data.is_array()) {
406+
return *data.get_if_array();
374407
} else {
375408
throw std::runtime_error("value is not an array type");
376409
}
377410
}
378411

379412
constexpr const auto &object_data() const
380413
{
381-
if (const auto *result = data.get_if_object(); result != nullptr) {
382-
return *result;
414+
if (data.is_object()) {
415+
return *data.get_if_object();
383416
} else {
384417
throw std::runtime_error("value is not an object type");
385418
}
@@ -394,25 +427,25 @@ template<typename CharType> struct basic_json
394427
// but it's necessary for API compatibility with nlohmann::json
395428
if constexpr (std::is_same_v<Type,
396429
std::uint64_t> || std::is_same_v<Type, std::int64_t> || std::is_same_v<Type, double>) {
397-
if (const auto *uint_value = data.get_if_uinteger(); uint_value != nullptr) {
398-
return Type(*uint_value);
399-
} else if (const auto *value = data.get_if_integer(); value != nullptr) {
400-
return Type(*value);
401-
} else if (const auto *fpvalue = data.get_if_floating_point(); fpvalue != nullptr) {
402-
return Type(*fpvalue);
430+
if (data.is_uinteger()) {
431+
return Type(*data.get_if_uinteger());
432+
} else if (data.is_integer()) {
433+
return Type(*data.get_if_integer());
434+
} else if (data.is_floating_point()) {
435+
return Type(*data.get_if_floating_point());
403436
} else {
404437
throw std::runtime_error("Unexpected type: number requested");// + ss.str() );
405438
}
406439
} else if constexpr (std::is_same_v<Type,
407440
std::basic_string_view<CharType>> || std::is_same_v<Type, std::basic_string<CharType>>) {
408-
if (const auto *value = data.get_if_string(); value != nullptr) {
409-
return *value;
441+
if (data.is_string()) {
442+
return *data.get_if_string();
410443
} else {
411444
throw std::runtime_error("Unexpected type: string-like requested");
412445
}
413446
} else if constexpr (std::is_same_v<Type, bool>) {
414-
if (const auto *value = data.get_if_boolean(); value != nullptr) {
415-
return *value;
447+
if (data.is_boolean()) {
448+
return *data.get_if_boolean();
416449
} else {
417450
throw std::runtime_error("Unexpected type: bool requested");
418451
}

0 commit comments

Comments
 (0)