Skip to content

Commit 1b91666

Browse files
MaheshGPaiMahesh Pai
authored andcommitted
BugFix: SIGABRT in quantiles_sketch::deserialize(): dereferencing empty std::optional (libc++ verbose_abort)
1 parent 5a05552 commit 1b91666

File tree

4 files changed

+86
-50
lines changed

4 files changed

+86
-50
lines changed

kll/include/kll_sketch_impl.hpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <iomanip>
2525
#include <sstream>
2626
#include <stdexcept>
27+
#include <type_traits>
2728

2829
#include "conditional_forward.hpp"
2930
#include "count_zeros.hpp"
@@ -481,18 +482,22 @@ kll_sketch<T, C, A> kll_sketch<T, C, A>::deserialize(std::istream& is, const Ser
481482
read(is, levels.data(), sizeof(levels[0]) * num_levels);
482483
}
483484
levels[num_levels] = capacity;
484-
optional<T> tmp; // space to deserialize min and max
485485
optional<T> min_item;
486486
optional<T> max_item;
487487
if (!is_single_item) {
488-
sd.deserialize(is, &*tmp, 1);
488+
// Space to deserialize min and max.
489+
// serde::deserialize expects allocated but not initialized storage.
490+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
491+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
492+
493+
sd.deserialize(is, tmp, 1);
489494
// serde call did not throw, repackage and cleanup
490-
min_item.emplace(*tmp);
491-
(*tmp).~T();
492-
sd.deserialize(is, &*tmp, 1);
495+
min_item.emplace(std::move(*tmp));
496+
tmp->~T();
497+
sd.deserialize(is, tmp, 1);
493498
// serde call did not throw, repackage and cleanup
494-
max_item.emplace(*tmp);
495-
(*tmp).~T();
499+
max_item.emplace(std::move(*tmp));
500+
tmp->~T();
496501
}
497502
A alloc(allocator);
498503
auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };
@@ -565,18 +570,22 @@ kll_sketch<T, C, A> kll_sketch<T, C, A>::deserialize(const void* bytes, size_t s
565570
ptr += copy_from_mem(ptr, levels.data(), sizeof(levels[0]) * num_levels);
566571
}
567572
levels[num_levels] = capacity;
568-
optional<T> tmp; // space to deserialize min and max
569573
optional<T> min_item;
570574
optional<T> max_item;
571575
if (!is_single_item) {
572-
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
576+
// Space to deserialize min and max.
577+
// serde::deserialize expects allocated but not initialized storage.
578+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
579+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
580+
581+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
573582
// serde call did not throw, repackage and cleanup
574-
min_item.emplace(*tmp);
575-
(*tmp).~T();
576-
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
583+
min_item.emplace(std::move(*tmp));
584+
tmp->~T();
585+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
577586
// serde call did not throw, repackage and cleanup
578-
max_item.emplace(*tmp);
579-
(*tmp).~T();
587+
max_item.emplace(std::move(*tmp));
588+
tmp->~T();
580589
}
581590
A alloc(allocator);
582591
auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };

quantiles/include/quantiles_sketch_impl.hpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <stdexcept>
2626
#include <iomanip>
2727
#include <sstream>
28+
#include <type_traits>
2829

2930
#include "count_zeros.hpp"
3031
#include "conditional_forward.hpp"
@@ -393,18 +394,22 @@ auto quantiles_sketch<T, C, A>::deserialize(std::istream &is, const SerDe& serde
393394
const bool is_compact = (serial_version == 2) | ((flags_byte & (1 << flags::IS_COMPACT)) > 0);
394395
const bool is_sorted = (flags_byte & (1 << flags::IS_SORTED)) > 0;
395396

396-
optional<T> tmp; // space to deserialize min and max
397397
optional<T> min_item;
398398
optional<T> max_item;
399399

400-
serde.deserialize(is, &*tmp, 1);
400+
// Space to deserialize min and max.
401+
// serde::deserialize expects allocated but not initialized storage.
402+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
403+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
404+
405+
serde.deserialize(is, tmp, 1);
401406
// serde call did not throw, repackage and cleanup
402-
min_item.emplace(*tmp);
403-
(*tmp).~T();
404-
serde.deserialize(is, &*tmp, 1);
407+
min_item.emplace(std::move(*tmp));
408+
tmp->~T();
409+
serde.deserialize(is, tmp, 1);
405410
// serde call did not throw, repackage and cleanup
406-
max_item.emplace(*tmp);
407-
(*tmp).~T();
411+
max_item.emplace(std::move(*tmp));
412+
tmp->~T();
408413

409414
if (serial_version == 1) {
410415
read<uint64_t>(is); // no longer used
@@ -507,18 +512,22 @@ auto quantiles_sketch<T, C, A>::deserialize(const void* bytes, size_t size, cons
507512
const bool is_compact = (serial_version == 2) | ((flags_byte & (1 << flags::IS_COMPACT)) > 0);
508513
const bool is_sorted = (flags_byte & (1 << flags::IS_SORTED)) > 0;
509514

510-
optional<T> tmp; // space to deserialize min and max
511515
optional<T> min_item;
512516
optional<T> max_item;
513517

514-
ptr += serde.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
518+
// Space to deserialize min and max.
519+
// serde::deserialize expects allocated but not initialized storage.
520+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
521+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
522+
523+
ptr += serde.deserialize(ptr, end_ptr - ptr, tmp, 1);
515524
// serde call did not throw, repackage and cleanup
516-
min_item.emplace(*tmp);
517-
(*tmp).~T();
518-
ptr += serde.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
525+
min_item.emplace(std::move(*tmp));
526+
tmp->~T();
527+
ptr += serde.deserialize(ptr, end_ptr - ptr, tmp, 1);
519528
// serde call did not throw, repackage and cleanup
520-
max_item.emplace(*tmp);
521-
(*tmp).~T();
529+
max_item.emplace(std::move(*tmp));
530+
tmp->~T();
522531

523532
if (serial_version == 1) {
524533
uint64_t unused_long;

req/include/req_sketch_impl.hpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <sstream>
2424
#include <stdexcept>
25+
#include <type_traits>
2526

2627
namespace datasketches {
2728

@@ -461,7 +462,6 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(std::istream& is, const Ser
461462
const bool hra = flags_byte & (1 << flags::IS_HIGH_RANK);
462463
if (is_empty) return req_sketch(k, hra, comparator, allocator);
463464

464-
optional<T> tmp; // space to deserialize min and max
465465
optional<T> min_item;
466466
optional<T> max_item;
467467

@@ -472,14 +472,19 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(std::istream& is, const Ser
472472
uint64_t n = 1;
473473
if (num_levels > 1) {
474474
n = read<uint64_t>(is);
475-
sd.deserialize(is, &*tmp, 1);
475+
// Space to deserialize min and max.
476+
// serde::deserialize expects allocated but not initialized storage.
477+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
478+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
479+
480+
sd.deserialize(is, tmp, 1);
476481
// serde call did not throw, repackage and cleanup
477-
min_item.emplace(*tmp);
478-
(*tmp).~T();
479-
sd.deserialize(is, &*tmp, 1);
482+
min_item.emplace(std::move(*tmp));
483+
tmp->~T();
484+
sd.deserialize(is, tmp, 1);
480485
// serde call did not throw, repackage and cleanup
481-
max_item.emplace(*tmp);
482-
(*tmp).~T();
486+
max_item.emplace(std::move(*tmp));
487+
tmp->~T();
483488
}
484489

485490
if (raw_items) {
@@ -537,7 +542,6 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(const void* bytes, size_t s
537542
const bool hra = flags_byte & (1 << flags::IS_HIGH_RANK);
538543
if (is_empty) return req_sketch(k, hra, comparator, allocator);
539544

540-
optional<T> tmp; // space to deserialize min and max
541545
optional<T> min_item;
542546
optional<T> max_item;
543547

@@ -549,14 +553,19 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(const void* bytes, size_t s
549553
if (num_levels > 1) {
550554
ensure_minimum_memory(end_ptr - ptr, sizeof(n));
551555
ptr += copy_from_mem(ptr, n);
552-
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
556+
// Space to deserialize min and max.
557+
// serde::deserialize expects allocated but not initialized storage.
558+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
559+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
560+
561+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
553562
// serde call did not throw, repackage and cleanup
554-
min_item.emplace(*tmp);
555-
(*tmp).~T();
556-
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
563+
min_item.emplace(std::move(*tmp));
564+
tmp->~T();
565+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
557566
// serde call did not throw, repackage and cleanup
558-
max_item.emplace(*tmp);
559-
(*tmp).~T();
567+
max_item.emplace(std::move(*tmp));
568+
tmp->~T();
560569
}
561570

562571
if (raw_items) {

sampling/include/ebpps_sample_impl.hpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <cmath>
2929
#include <string>
3030
#include <sstream>
31+
#include <type_traits>
3132

3233
namespace datasketches {
3334

@@ -365,11 +366,15 @@ std::pair<ebpps_sample<T, A>, size_t> ebpps_sample<T, A>::deserialize(const uint
365366

366367
optional<T> partial_item;
367368
if (has_partial) {
368-
optional<T> tmp; // space to deserialize
369-
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
369+
// Space to deserialize.
370+
// serde::deserialize expects allocated but not initialized storage.
371+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
372+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
373+
374+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
370375
// serde did not throw so place item and clean up
371-
partial_item.emplace(*tmp);
372-
(*tmp).~T();
376+
partial_item.emplace(std::move(*tmp));
377+
tmp->~T();
373378
}
374379

375380
return std::pair<ebpps_sample<T,A>, size_t>(
@@ -400,11 +405,15 @@ ebpps_sample<T, A> ebpps_sample<T, A>::deserialize(std::istream& is, const SerDe
400405

401406
optional<T> partial_item;
402407
if (has_partial) {
403-
optional<T> tmp; // space to deserialize
404-
sd.deserialize(is, &*tmp, 1);
408+
// Space to deserialize.
409+
// serde::deserialize expects allocated but not initialized storage.
410+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
411+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
412+
413+
sd.deserialize(is, tmp, 1);
405414
// serde did not throw so place item and clean up
406-
partial_item.emplace(*tmp);
407-
(*tmp).~T();
415+
partial_item.emplace(std::move(*tmp));
416+
tmp->~T();
408417
}
409418

410419
if (!is.good()) throw std::runtime_error("error reading from std::istream");

0 commit comments

Comments
 (0)