mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-10 11:36:22 +00:00
LibDeviceTree: Fix stale pointers in phandle and parent handling
We need to set them after we've created the full tree, as otherwise the HashMap containing the nodes may reallocate and invalidate the pointers.
This commit is contained in:
parent
b2377f1f9c
commit
ffa9875fa6
Notes:
sideshowbarker
2024-07-16 18:26:46 +09:00
Author: https://github.com/Hendiadyoin1
Commit: ffa9875fa6
Pull-request: https://github.com/SerenityOS/serenity/pull/24141
Reviewed-by: https://github.com/ADKaster ✅
2 changed files with 65 additions and 8 deletions
|
@ -39,14 +39,7 @@ ErrorOr<NonnullOwnPtr<DeviceTree>> DeviceTree::parse(ReadonlyBytes flattened_dev
|
||||||
current_node = current_node->parent();
|
current_node = current_node->parent();
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
},
|
},
|
||||||
.on_property = [&device_tree, ¤t_node](StringView name, ReadonlyBytes value) -> ErrorOr<IterationDecision> {
|
.on_property = [¤t_node](StringView name, ReadonlyBytes value) -> ErrorOr<IterationDecision> {
|
||||||
DeviceTreeProperty property { value };
|
|
||||||
|
|
||||||
if (name == "phandle"sv) {
|
|
||||||
auto phandle = property.as<u32>();
|
|
||||||
TRY(device_tree->set_phandle(phandle, current_node));
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(current_node->properties().try_set(name, DeviceTreeProperty { value }));
|
TRY(current_node->properties().try_set(name, DeviceTreeProperty { value }));
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
},
|
},
|
||||||
|
@ -58,6 +51,25 @@ ErrorOr<NonnullOwnPtr<DeviceTree>> DeviceTree::parse(ReadonlyBytes flattened_dev
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// FIXME: While growing the a nodes children map, we might have reallocated it's storage
|
||||||
|
// breaking the parent pointers of the children, so we need to fix them here
|
||||||
|
auto fix_parent = [](auto self, DeviceTreeNodeView& node) -> void {
|
||||||
|
for (auto& [name, child] : node.children()) {
|
||||||
|
child.m_parent = &node;
|
||||||
|
self(self, child);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fix_parent(fix_parent, *device_tree);
|
||||||
|
// Note: For the same reason as above, we need to postpone setting the phandles until the tree is fully built
|
||||||
|
TRY(device_tree->for_each_node([&device_tree]([[maybe_unused]] StringView name, DeviceTreeNodeView& node) -> ErrorOr<RecursionDecision> {
|
||||||
|
if (auto phandle = node.get_property("phandle"sv); phandle.has_value()) {
|
||||||
|
auto phandle_value = phandle.value().as<u32>();
|
||||||
|
TRY(device_tree->set_phandle(phandle_value, &node));
|
||||||
|
}
|
||||||
|
return RecursionDecision::Recurse;
|
||||||
|
}));
|
||||||
|
|
||||||
return device_tree;
|
return device_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <AK/IterationDecision.h>
|
#include <AK/IterationDecision.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
|
#include <AK/RecursionDecision.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
|
|
||||||
namespace DeviceTree {
|
namespace DeviceTree {
|
||||||
|
@ -168,6 +169,28 @@ public:
|
||||||
// bonus points if it could automatically recurse in the tree under some conditions,
|
// bonus points if it could automatically recurse in the tree under some conditions,
|
||||||
// like "simple-bus" or "pci-bridge" nodes
|
// like "simple-bus" or "pci-bridge" nodes
|
||||||
|
|
||||||
|
auto for_each_node(CallableAs<ErrorOr<RecursionDecision>, StringView, DeviceTreeNodeView const&> auto callback) const
|
||||||
|
{
|
||||||
|
auto iterate = [&](auto self, StringView name, DeviceTreeNodeView const& node) -> ErrorOr<RecursionDecision> {
|
||||||
|
auto result = TRY(callback(name, node));
|
||||||
|
|
||||||
|
if (result == RecursionDecision::Recurse) {
|
||||||
|
for (auto const& [name, child] : node.children()) {
|
||||||
|
auto child_result = TRY(self(self, name, child));
|
||||||
|
|
||||||
|
if (child_result == RecursionDecision::Break)
|
||||||
|
return RecursionDecision::Break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RecursionDecision::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return iterate(iterate, "/"sv, *this);
|
||||||
|
}
|
||||||
|
|
||||||
DeviceTreeNodeView const* phandle(u32 phandle) const
|
DeviceTreeNodeView const* phandle(u32 phandle) const
|
||||||
{
|
{
|
||||||
if (phandle >= m_phandles.size())
|
if (phandle >= m_phandles.size())
|
||||||
|
@ -184,6 +207,28 @@ private:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto for_each_node(CallableAs<ErrorOr<RecursionDecision>, StringView, DeviceTreeNodeView&> auto callback)
|
||||||
|
{
|
||||||
|
auto iterate = [&](auto self, StringView name, DeviceTreeNodeView& node) -> ErrorOr<RecursionDecision> {
|
||||||
|
auto result = TRY(callback(name, node));
|
||||||
|
|
||||||
|
if (result == RecursionDecision::Recurse) {
|
||||||
|
for (auto& [name, child] : node.children()) {
|
||||||
|
auto child_result = TRY(self(self, name, child));
|
||||||
|
|
||||||
|
if (child_result == RecursionDecision::Break)
|
||||||
|
return RecursionDecision::Break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RecursionDecision::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return iterate(iterate, "/"sv, *this);
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> set_phandle(u32 phandle, DeviceTreeNodeView* node)
|
ErrorOr<void> set_phandle(u32 phandle, DeviceTreeNodeView* node)
|
||||||
{
|
{
|
||||||
if (m_phandles.size() > phandle && m_phandles[phandle] != nullptr)
|
if (m_phandles.size() > phandle && m_phandles[phandle] != nullptr)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue