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

Port easy exits #17

Merged
merged 3 commits into from
Feb 10, 2017
Merged

Port easy exits #17

merged 3 commits into from
Feb 10, 2017

Conversation

mrhota
Copy link
Collaborator

@mrhota mrhota commented Feb 9, 2017

some of the mess in exit.rs is meant for dynlink. Read commit
messages for exit.c and friends for full details and
justifications.

some of the mess in exit.rs is meant for dynlink. Read commit
messages for exit.c and friends for full details and
justifications.
Copy link
Owner

@anp anp left a comment

Choose a reason for hiding this comment

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

Looks great! I have a couple of questions about how you've replicated the logic from the C side. I suspect that knowing whether it's right is hard b/c the tests are unlikely to check the differences I'm seeing, but it seems like it's worth looking at.

pub unsafe extern "C" fn _Exit(ec: c_int) -> ! {
syscall!(EXIT_GROUP, ec);
syscall!(EXIT, ec);
loop {}
Copy link
Owner

Choose a reason for hiding this comment

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

Please correct me if I'm wrong, but based on http://git.musl-libc.org/cgit/musl/tree/src/exit/_Exit.c this seems like it should be

loop { syscall!(EXIT, ec); }

since the C for loop will continue attempting to call the EXIT syscall until the process has aborted.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

looks like I lost my original reply in the ether.

the loop on line 7 is unreachable, since the EXIT syscall doesn't return. The loop serves to make the function divergent: without the loop, the return type of the syscall! macro, (), conflicts with the specified return type of !, so rustc refuses to compile it. Adding the loop lets rustc compile without complaint.

The loop is similar in spirit to the loop in the original C. See reasoning here: http://git.musl-libc.org/cgit/musl/commit/src/exit/_Exit.c?id=0c05bd3a9c165cf2f0b9d6fa23a1f96532ddcdb3

Copy link
Owner

Choose a reason for hiding this comment

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

Awesome, thanks for filling me in!

src/exit/exit.rs Outdated
#[linkage = "weak"]
#[no_mangle]
pub unsafe extern "C" fn __libc_exit_fini() {
_fini()
Copy link
Owner

Choose a reason for hiding this comment

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

Based on http://git.musl-libc.org/cgit/musl/tree/src/exit/exit.c#n18 it seems like this should perform some magic-y math on those void pointers before calling _fini(). If that's not necessary for some reason, could you include a comment that explains that here for me and any future readers?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think I'd rather add a TODO: those symbols are used by dynamic linker for purposes that are still mysterious to me. You can read about Rich Felker's motivations in his very descriptive commit messages here: http://git.musl-libc.org/cgit/musl/log/src/exit/exit.c

Copy link
Owner

Choose a reason for hiding this comment

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

@mrhota
Copy link
Collaborator Author

mrhota commented Feb 10, 2017

@dikaiosune I removed the unsafe annotations. They receive simple integers as arguments and don't do anything crazy (or interesting, really).

I added comments explaining some reasoning and passing off to musl commit messages for further discussion.

@anp
Copy link
Owner

anp commented Feb 10, 2017

Cool. Looks good.

The functions don't do anything crazy, but we do mark their linkage as weak, and expect the linker to place its own definitions in for the dummies, right? I'm not sure what invariants we would expect a caller to enforce by requiring the calls be placed in an unsafe block, but it seems like it's maybe most appropriate to leave them as unsafe? I'll defer to your judgement.

@mrhota
Copy link
Collaborator Author

mrhota commented Feb 10, 2017

@dikaiosune I got inspired to do that because was re-reading https://huonw.github.io/blog/2014/07/what-does-rusts-unsafe-mean/ for some insight into marking fns unsafe vs using unsafe blocks internally.

I wouldn't say we expect the linker to provide strong symbols for things like _fini or __funcs_on_exit, but we are prepared for it by marking the symbols weak. If we expected the symbols, we'd probably just have some extern decls instead of definitions:

extern "C" {
    fn _fini();
    fn __funcs_on_exit();
}

@mrhota
Copy link
Collaborator Author

mrhota commented Feb 10, 2017

If it's up to me, I prefer fewer unsafes!

@anp anp merged commit 04614ca into anp:master Feb 10, 2017
@mrhota mrhota deleted the exit_and_friends branch February 10, 2017 04:58
@anp
Copy link
Owner

anp commented Feb 10, 2017

Cool. Thinking about it more I think we kind of just have to trust that the linker will do what it says, and that there's nothing our userspace program can do to prevent it behaving poorly.

@anp
Copy link
Owner

anp commented Feb 10, 2017

I prefer fewer unsafes!

Heh, I actually have the opposite mindset. I would rather be overcautious about what should be declared unsafe lest we accidentally create a "safe" call chain that breaks things. I think in this case it's immaterial but an interesting philosophical question nonetheless.

One example I see is from this audit report I read this morning:

https://www.x41-dsec.de/reports/Kudelski-X41-Wire-Report-phase1-20170208.pdf

(pg 12, section 3.3) I think that this init function probably should have returned a Result<(), SomeError>, but if they were trying to match a C API they alternatively could have marked it as an unsafe function, signaling to a caller that if they didn't handle its failure correctly that there could be memory unsafety as a result. Ideally they would have done both: used a Result to make use of the must_use compiler lint but also mark the init function as unsafe so that the caller has to be aware of potential memory safety consequences of not handling its failure properly.

Anyways, it's late and I'm waiting for several builds so this is just a ramble.

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