Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up server data structures #94

Merged
merged 12 commits into from
Apr 10, 2024
Merged

Clean up server data structures #94

merged 12 commits into from
Apr 10, 2024

Conversation

sgoll
Copy link
Contributor

@sgoll sgoll commented Apr 10, 2024

Description

This cleans up some of the data structures introduced in #89, fixing issues where ownership passed into the C library where it was not expected, potentially leaking memory. See the individual commits in the PR for details.

@sgoll sgoll requested a review from uklotzde April 10, 2024 14:40
@sgoll
Copy link
Contributor Author

sgoll commented Apr 10, 2024

Cc @guenhter

src/server.rs Show resolved Hide resolved
historizing: attrs.historizing,
}
impl Default for VariableAttributes {
fn default() -> Self {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract the code into fn new()? std often implements a no-arg constructor that impl Default then delegates to. That would at least be consistent with Server, also part of this PR. I didn't check other occurrences.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For ua::data_types I tend to avoid new() because it is not entirely clear what it does. Basically, there are two ways to create new instances of these data types:

  • init() which only creates an internally consistent but basically uninitialized state (safe to be dropped and passed around, but mostly meaningless because required attributes may be missing)
  • default() which provides sensible defaults that can be used as-is (ClientConfig, BrowseDescription)

In this case we are dealing with the latter: while still mostly unset, it has all the required attributes pre-initialized that should be set: see ua_server_utils.c (mostly blanks, but there are some bit masks and types set).

);
/// This fails when the node cannot be added.
pub fn add_object_node(&mut self, node: ObjectNode) -> Result<()> {
let status_code = ua::StatusCode::new(unsafe {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be desirable to restrict the unsafe parts to ua::Server? Unfortunately, I don't know how to achieve this 😅 So let's keep it here for now.

Maybe add a TODO comment to explain this decision?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle, yes, unsafe code should (could) reside inside the ua module and we could deal only with safe abstractions when writing the higher-level code in Client/Server (outside of ua).

In this case, however, the abstraction is extremely thin and basically only forwards the call with an unsafe {} block around it. I'm not sure that we gain much by adding this indirection. I fear that it only makes it less obvious what is happening here.

But I'm not absolutely happy with the current state of affairs myself. Until we find a better way, let's at least keep it consistent between Client and Server to avoid surprises.

@sgoll sgoll merged commit 18878d4 into main Apr 10, 2024
13 checks passed
@sgoll sgoll deleted the clean-up-server branch April 10, 2024 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants