Commit cd076a93 authored by Dominik Charousset's avatar Dominik Charousset

Provide better diagnostic for missing meta objects

parent d844748d
...@@ -17,6 +17,9 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -17,6 +17,9 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- Typed actors that use a `typed_actor_pointer` can now access the - Typed actors that use a `typed_actor_pointer` can now access the
`run_{delayed,scheduled}` member functions. `run_{delayed,scheduled}` member functions.
- Scheduled and delayed sends now return a disposable (#1362). - Scheduled and delayed sends now return a disposable (#1362).
- 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,9 +64,14 @@ CAF_CORE_EXPORT global_meta_objects_guard_type global_meta_objects_guard(); ...@@ -64,9 +64,14 @@ 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
/// meta object exists for `id`.
CAF_CORE_EXPORT const meta_object* global_meta_object(type_id_t 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!
CAF_CORE_EXPORT void clear_global_meta_objects(); CAF_CORE_EXPORT void clear_global_meta_objects();
......
...@@ -194,7 +194,7 @@ error_code<sec> config_value::default_construct(type_id_t id) { ...@@ -194,7 +194,7 @@ 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)) {
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 = detail::make_scope_guard([ptr] { free(ptr); });
meta->default_construct(ptr); meta->default_construct(ptr);
...@@ -520,7 +520,6 @@ config_value::parse_msg_impl(std::string_view str, ...@@ -520,7 +520,6 @@ config_value::parse_msg_impl(std::string_view str,
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))
......
...@@ -54,7 +54,26 @@ span<const meta_object> global_meta_objects() { ...@@ -54,7 +54,26 @@ span<const meta_object> global_meta_objects() {
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));
return nullptr;
}
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;
} }
......
...@@ -71,7 +71,7 @@ bool load_data(Deserializer& source, message::data_ptr& data) { ...@@ -71,7 +71,7 @@ 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_obj = detail::global_meta_object_or_null(id))
data_size += meta_obj->padded_size; data_size += meta_obj->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;
...@@ -290,13 +290,11 @@ std::string to_string(const message& msg) { ...@@ -290,13 +290,11 @@ std::string to_string(const message& msg) {
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;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
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 ptr = detail::global_meta_object_or_null(type))
return ptr->type_name; return ptr->type_name;
return {}; return {};
} }
......
...@@ -13,8 +13,8 @@ namespace caf { ...@@ -13,8 +13,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); auto meta = detail::global_meta_object(type);
result += meta_obj->padded_size; result += meta->padded_size;
} }
return result; return 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