Unverified Commit b3164d5b authored by Noir's avatar Noir Committed by GitHub

Merge pull request #1379

Provide better diagnostic for missing meta objects
parents 26b0a900 00f7bb3a
...@@ -21,6 +21,9 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -21,6 +21,9 @@ is based on [Keep a Changelog](https://keepachangelog.com).
single objects. single objects.
- Typed actors that use the type-erased pointer-view type received access to the - Typed actors that use the type-erased pointer-view type received access to the
new flow API functions (e.g., `make_observable`). new flow API functions (e.g., `make_observable`).
- Not initializing the meta objects table now prints a diagnosis message before
aborting the program. Previously, the application would usually just crash due
to a `nullptr`-access inside some CAF function.
### Fixed ### Fixed
......
...@@ -179,7 +179,7 @@ public: ...@@ -179,7 +179,7 @@ public:
} }
error abort_reason() const { error abort_reason() const {
impl_->abort_reason(); return impl_->abort_reason();
} }
private: private:
......
...@@ -64,8 +64,13 @@ CAF_CORE_EXPORT global_meta_objects_guard_type global_meta_objects_guard(); ...@@ -64,8 +64,13 @@ CAF_CORE_EXPORT global_meta_objects_guard_type global_meta_objects_guard();
/// is the index for accessing the corresponding meta object. /// is the index for accessing the corresponding meta object.
CAF_CORE_EXPORT span<const meta_object> global_meta_objects(); CAF_CORE_EXPORT span<const meta_object> global_meta_objects();
/// Returns the global meta object for given type ID. /// Returns the global meta object for given type ID. Aborts the program if no
CAF_CORE_EXPORT const meta_object* global_meta_object(type_id_t id); /// meta object exists for `id`.
CAF_CORE_EXPORT const meta_object& global_meta_object(type_id_t id);
/// Returns the global meta object for given type ID or `nullptr` if no meta
/// object exists for `id`.
CAF_CORE_EXPORT const meta_object* global_meta_object_or_null(type_id_t id);
/// Clears the array for storing global meta objects. /// Clears the array for storing global meta objects.
/// @warning intended for unit testing only! /// @warning intended for unit testing only!
......
...@@ -35,17 +35,17 @@ bool batch::data::save(Inspector& sink) const { ...@@ -35,17 +35,17 @@ bool batch::data::save(Inspector& sink) const {
sink.emplace_error(sec::unsafe_type); sink.emplace_error(sec::unsafe_type);
return false; return false;
} }
auto meta = detail::global_meta_object(item_type_); auto& meta = detail::global_meta_object(item_type_);
auto ptr = storage_; auto ptr = storage_;
if (!sink.begin_sequence(size_)) if (!sink.begin_sequence(size_))
return false; return false;
auto len = size_; auto len = size_;
do { do {
if constexpr (std::is_same_v<Inspector, binary_serializer>) { if constexpr (std::is_same_v<Inspector, binary_serializer>) {
if (!meta->save_binary(sink, ptr)) if (!meta.save_binary(sink, ptr))
return false; return false;
} else { } else {
if (!meta->save(sink, ptr)) if (!meta.save(sink, ptr))
return false; return false;
} }
ptr += item_size_; ptr += item_size_;
......
...@@ -194,12 +194,12 @@ error_code<sec> config_value::default_construct(type_id_t id) { ...@@ -194,12 +194,12 @@ error_code<sec> config_value::default_construct(type_id_t id) {
set(uri{}); set(uri{});
return sec::none; return sec::none;
default: default:
if (auto meta = detail::global_meta_object(id)) { if (auto meta = detail::global_meta_object_or_null(id)) {
using detail::make_scope_guard;
auto ptr = malloc(meta->padded_size); auto ptr = malloc(meta->padded_size);
auto free_guard = detail::make_scope_guard([ptr] { free(ptr); }); auto free_guard = make_scope_guard([ptr] { free(ptr); });
meta->default_construct(ptr); meta->default_construct(ptr);
auto destroy_guard auto destroy_guard = make_scope_guard([=] { meta->destroy(ptr); });
= detail::make_scope_guard([=] { meta->destroy(ptr); });
config_value_writer writer{this}; config_value_writer writer{this};
if (meta->save(writer, ptr)) { if (meta->save(writer, ptr)) {
return sec::none; return sec::none;
...@@ -519,13 +519,12 @@ config_value::parse_msg_impl(std::string_view str, ...@@ -519,13 +519,12 @@ config_value::parse_msg_impl(std::string_view str,
return false; return false;
auto pos = ptr->storage(); auto pos = ptr->storage();
for (auto type : ls) { for (auto type : ls) {
auto meta = detail::global_meta_object(type); auto& meta = detail::global_meta_object(type);
CAF_ASSERT(meta != nullptr); meta.default_construct(pos);
meta->default_construct(pos);
ptr->inc_constructed_elements(); ptr->inc_constructed_elements();
if (!meta->load(reader, pos)) if (!meta.load(reader, pos))
return false; return false;
pos += meta->padded_size; pos += meta.padded_size;
} }
result.reset(ptr.release(), false); result.reset(ptr.release(), false);
return reader.end_sequence(); return reader.end_sequence();
......
...@@ -51,10 +51,28 @@ span<const meta_object> global_meta_objects() { ...@@ -51,10 +51,28 @@ span<const meta_object> global_meta_objects() {
return {meta_objects, meta_objects_size}; return {meta_objects, meta_objects_size};
} }
const meta_object* global_meta_object(type_id_t id) { const meta_object& global_meta_object(type_id_t id) {
if (id < meta_objects_size) { if (id < meta_objects_size) {
auto& meta = meta_objects[id]; auto& meta = meta_objects[id];
return !meta.type_name.empty() ? &meta : nullptr; if (!meta.type_name.empty())
return meta;
}
CAF_CRITICAL_FMT(
"found no meta object for type ID %d!\n"
" This usually means that run-time type initialization is missing.\n"
" With CAF_MAIN, make sure to pass all custom type ID blocks.\n"
" With a custom main, call (before any other CAF function):\n"
" - caf::core::init_global_meta_objects()\n"
" - <module>::init_global_meta_objects() for all loaded modules\n"
" - caf::init_global_meta_objects<T>() for all custom ID blocks",
static_cast<int>(id));
}
const meta_object* global_meta_object_or_null(type_id_t id) {
if (id < meta_objects_size) {
auto& meta = meta_objects[id];
if (!meta.type_name.empty())
return &meta;
} }
return nullptr; return nullptr;
} }
......
...@@ -64,21 +64,19 @@ int error::compare(uint8_t code, type_id_t category) const noexcept { ...@@ -64,21 +64,19 @@ int error::compare(uint8_t code, type_id_t category) const noexcept {
// -- inspection support ----------------------------------------------------- // -- inspection support -----------------------------------------------------
std::string to_string(const error& x) { std::string to_string(const error& x) {
using const_void_ptr = const void*;
using const_meta_ptr = const detail::meta_object*;
if (!x) if (!x)
return "none"; return "none";
std::string result; std::string result;
auto append = [&result](const_void_ptr ptr, auto append = [&result](const void* ptr,
const_meta_ptr meta) -> const_void_ptr { const detail::meta_object& meta) -> const void* {
meta->stringify(result, ptr); meta.stringify(result, ptr);
return static_cast<const std::byte*>(ptr) + meta->padded_size; return static_cast<const std::byte*>(ptr) + meta.padded_size;
}; };
auto code = x.code(); auto code = x.code();
append(&code, detail::global_meta_object(x.category())); append(&code, detail::global_meta_object(x.category()));
if (auto& ctx = x.context()) { if (auto& ctx = x.context()) {
result += '('; result += '(';
auto ptr = static_cast<const_void_ptr>(ctx.cdata().storage()); auto ptr = static_cast<const void*>(ctx.cdata().storage());
auto types = ctx.types(); auto types = ctx.types();
ptr = append(ptr, detail::global_meta_object(types[0])); ptr = append(ptr, detail::global_meta_object(types[0]));
for (size_t index = 1; index < types.size(); ++index) { for (size_t index = 1; index < types.size(); ++index) {
......
...@@ -71,8 +71,8 @@ bool load_data(Deserializer& source, message::data_ptr& data) { ...@@ -71,8 +71,8 @@ bool load_data(Deserializer& source, message::data_ptr& data) {
CAF_ASSERT(ids.size() == msg_size); CAF_ASSERT(ids.size() == msg_size);
size_t data_size = 0; size_t data_size = 0;
for (auto id : ids) { for (auto id : ids) {
if (auto meta_obj = detail::global_meta_object(id)) if (auto meta = detail::global_meta_object_or_null(id))
data_size += meta_obj->padded_size; data_size += meta->padded_size;
else else
STOP(sec::unknown_type); STOP(sec::unknown_type);
} }
...@@ -155,7 +155,7 @@ bool load_data(Deserializer& source, message::data_ptr& data) { ...@@ -155,7 +155,7 @@ bool load_data(Deserializer& source, message::data_ptr& data) {
for (size_t i = 0; i < msg_size; ++i) { for (size_t i = 0; i < msg_size; ++i) {
auto type = type_id_t{0}; auto type = type_id_t{0};
GUARDED(source.fetch_next_object_type(type)); GUARDED(source.fetch_next_object_type(type));
if (auto meta_obj = detail::global_meta_object(type)) { if (auto meta_obj = detail::global_meta_object_or_null(type)) {
ids.push_back(type); ids.push_back(type);
auto obj_size = meta_obj->padded_size; auto obj_size = meta_obj->padded_size;
data_size += obj_size; data_size += obj_size;
...@@ -289,14 +289,12 @@ std::string to_string(const message& msg) { ...@@ -289,14 +289,12 @@ std::string to_string(const message& msg) {
auto types = msg.types(); auto types = msg.types();
if (!types.empty()) { if (!types.empty()) {
auto ptr = msg.cdata().storage(); auto ptr = msg.cdata().storage();
auto meta = detail::global_meta_object(types[0]); auto* meta = &detail::global_meta_object(types[0]);
CAF_ASSERT(meta != nullptr);
meta->stringify(result, ptr); meta->stringify(result, ptr);
ptr += meta->padded_size; ptr += meta->padded_size;
for (size_t index = 1; index < types.size(); ++index) { for (size_t index = 1; index < types.size(); ++index) {
result += ", "; result += ", ";
meta = detail::global_meta_object(types[index]); meta = &detail::global_meta_object(types[index]);
CAF_ASSERT(meta != nullptr);
meta->stringify(result, ptr); meta->stringify(result, ptr);
ptr += meta->padded_size; ptr += meta->padded_size;
} }
......
...@@ -52,9 +52,9 @@ public: ...@@ -52,9 +52,9 @@ public:
} }
std::byte* copy_init(std::byte* storage) const override { std::byte* copy_init(std::byte* storage) const override {
auto* meta = global_meta_object(src_.type_at(index_)); auto& meta = global_meta_object(src_.type_at(index_));
meta->copy_construct(storage, src_.data().at(index_)); meta.copy_construct(storage, src_.data().at(index_));
return storage + meta->padded_size; return storage + meta.padded_size;
} }
std::byte* move_init(std::byte* storage) override { std::byte* move_init(std::byte* storage) override {
...@@ -75,8 +75,8 @@ message_builder& message_builder::append_from(const caf::message& msg, ...@@ -75,8 +75,8 @@ message_builder& message_builder::append_from(const caf::message& msg,
auto end = std::min(msg.size(), first + n); auto end = std::min(msg.size(), first + n);
for (size_t index = first; index < end; ++index) { for (size_t index = first; index < end; ++index) {
auto tid = msg.type_at(index); auto tid = msg.type_at(index);
auto* meta = detail::global_meta_object(tid); auto& meta = detail::global_meta_object(tid);
storage_size_ += meta->padded_size; storage_size_ += meta.padded_size;
types_.push_back(tid); types_.push_back(tid);
elements_.emplace_back( elements_.emplace_back(
std::make_unique<message_builder_element_adapter>(msg, index)); std::make_unique<message_builder_element_adapter>(msg, index));
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
namespace caf { namespace caf {
std::string_view query_type_name(type_id_t type) { std::string_view query_type_name(type_id_t type) {
if (auto ptr = detail::global_meta_object(type)) if (auto meta = detail::global_meta_object_or_null(type))
return ptr->type_name; return meta->type_name;
return {}; return {};
} }
......
...@@ -12,10 +12,8 @@ namespace caf { ...@@ -12,10 +12,8 @@ namespace caf {
size_t type_id_list::data_size() const noexcept { size_t type_id_list::data_size() const noexcept {
auto result = size_t{0}; auto result = size_t{0};
for (auto type : *this) { for (auto type : *this)
auto meta_obj = detail::global_meta_object(type); result += detail::global_meta_object(type).padded_size;
result += meta_obj->padded_size;
}
return result; return result;
} }
...@@ -25,12 +23,12 @@ std::string to_string(type_id_list xs) { ...@@ -25,12 +23,12 @@ std::string to_string(type_id_list xs) {
std::string result; std::string result;
result += '['; result += '[';
{ {
auto tn = detail::global_meta_object(xs[0])->type_name; auto tn = detail::global_meta_object(xs[0]).type_name;
result.insert(result.end(), tn.begin(), tn.end()); result.insert(result.end(), tn.begin(), tn.end());
} }
for (size_t index = 1; index < xs.size(); ++index) { for (size_t index = 1; index < xs.size(); ++index) {
result += ", "; result += ", ";
auto tn = detail::global_meta_object(xs[index])->type_name; auto tn = detail::global_meta_object(xs[index]).type_name;
result.insert(result.end(), tn.begin(), tn.end()); result.insert(result.end(), tn.begin(), tn.end());
} }
result += ']'; result += ']';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment