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

Unregister processes when they die #635

Merged
merged 2 commits into from
Jun 24, 2023

Conversation

UncleGrumpy
Copy link
Collaborator

Adds the function globalcontext_maybe_unregister_process_id to globalcontext.c to allow removing the appropriate entry from the registered atoms table when the associated context is destroyed.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later

const struct RegisteredProcess *registered_process = GET_LIST_ENTRY(item, struct RegisteredProcess, registered_processes_list_head);
if (registered_process->local_process_id == target_process_id) {
list_remove(item);
free(item);
Copy link
Collaborator

Choose a reason for hiding this comment

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

this may cause a memory corruption, we have to free(registered_process). Right now this code works just by chance.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That was my first inclination too, but globalcontext_unregister_process we free'd item not registered_process. I believe we had a similar discussion then.

Copy link
Collaborator Author

@UncleGrumpy UncleGrumpy Jun 14, 2023

Choose a reason for hiding this comment

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

Indeed, we had a lengthy discussion... #364.
I can change it here, if you feel it reads better that way. If so, we should also change it in globalcontext_unregister_process for consistency.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In fact it must be free(item), when I changed it to free(registered_process) th CI for MacOS builds fails with the following error:

/Users/runner/work/AtomVM/AtomVM/src/libAtomVM/globalcontext.c:327:18: error: passing 'const struct RegisteredProcess *' to parameter of type 'void *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
            free(registered_process);
                 ^~~~~~~~~~~~~~~~~~
/Applications/Xcode_14.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk/usr/include/malloc/_malloc.h:42:18: note: passing argument to parameter here
void     free(void *);
                    ^

Copy link
Collaborator

Choose a reason for hiding this comment

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

So I think we should remove that const from const struct RegisteredProcess *registered_process.

Copy link
Collaborator

Choose a reason for hiding this comment

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

In order to check which is the right thing to do I suggest doing this change:

 struct RegisteredProcess
 {
+    uint64_t dummy1;
+    uint32_t dummy2;
+
     struct ListHead registered_processes_list_head;
 
     int atom_index;

or even this change:

 struct RegisteredProcess
 {
-    struct ListHead registered_processes_list_head;
-
     int atom_index;
     int local_process_id;
+
+    struct ListHead registered_processes_list_head;
 };

I think you will end with both to a crash, that means that the code is now depending on the struct memory layout.
If you do free(registered_process); you make sure you are going to free at offset 0, which is the same pointer that is returned from malloc.

Does it make sense to you?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. I was not thinking about how future API changes could break this in bad ways. Assuming that removing the const from const struct RegisteredProcess *registered_process will pass the MacOS CI workflows, would you like me to fix the free(item) in globalcontext_unregister_process as well? I can add it in a separate bug fix commit, without flattening.

src/libAtomVM/context.c Show resolved Hide resolved
@UncleGrumpy UncleGrumpy force-pushed the bring_out_your_dead branch 2 times, most recently from 2269009 to 49eb33e Compare June 16, 2023 00:48
const struct RegisteredProcess *registered_process = GET_LIST_ENTRY(item, struct RegisteredProcess, registered_processes_list_head);
if (registered_process->local_process_id == target_process_id) {
list_remove(item);
free(item);
Copy link
Collaborator

Choose a reason for hiding this comment

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

In order to check which is the right thing to do I suggest doing this change:

 struct RegisteredProcess
 {
+    uint64_t dummy1;
+    uint32_t dummy2;
+
     struct ListHead registered_processes_list_head;
 
     int atom_index;

or even this change:

 struct RegisteredProcess
 {
-    struct ListHead registered_processes_list_head;
-
     int atom_index;
     int local_process_id;
+
+    struct ListHead registered_processes_list_head;
 };

I think you will end with both to a crash, that means that the code is now depending on the struct memory layout.
If you do free(registered_process); you make sure you are going to free at offset 0, which is the same pointer that is returned from malloc.

Does it make sense to you?

@UncleGrumpy
Copy link
Collaborator Author

UncleGrumpy commented Jun 22, 2023

Yes. I was not thinking about how future API changes could break this in bad ways. I went ahead and fixed the free(item) in globalcontext_unregister_process in a separate bug fix commit, without flattening.

The way the registered processes were freed when being unregisterd was unsafe if
future API changes requre adjusting the layout of the RegisteredProcess struct.

Signed-off-by: Winford <winford@object.stream>
Adds the function `globalcontext_maybe_unregister_process_id` to globalcontext.c
to allow removing the appropriate entry from the registered atoms table when the
associated context is destroyed.

Signed-off-by: Winford <winford@object.stream>
@bettio bettio added this to the v0.6 milestone Jun 22, 2023
@bettio bettio merged commit 547447c into atomvm:master Jun 24, 2023
74 of 78 checks passed
@UncleGrumpy UncleGrumpy deleted the bring_out_your_dead branch June 28, 2023 03:03
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