-
Notifications
You must be signed in to change notification settings - Fork 13
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
Fill in some text #2
Conversation
README.md
Outdated
- [acfoltzer](https://github.com/acfoltzer) | ||
- [batmanaod (Kyle)](https://github.com/batmanaod) | ||
- with guidance/assistance from [nikmoatsakis](https://github.com/nikmoatsakis) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- with guidance/assistance from [nikmoatsakis](https://github.com/nikmoatsakis) | |
- with guidance/assistance from [Niko](https://github.com/nikmoatsakis) |
I think having our "handles" and our names is probably a good idea, though I think that matters most in my case, where there's no clear connection between my name and my handle.
faq.md
Outdated
@@ -0,0 +1,32 @@ | |||
## FAQ questions | |||
|
|||
- Why use a new ABI? Why not an attribute? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting nit: I think let's use ###
headings (this also means people can link to the questions)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setjmp/longjmp section looks good but there are some minor issues open.
Also, I'm not sure that the claim that drop is always guaranteed to run in some platforms is true. I recall that on MSVC whether objects are drop on a longjmp depends on whether a function is inlined or not. For example, if you have something like:
fn foo() {
if setjmp(jmpbuf) == 0 {
bar()
}
}
fn bar() {
let x: DropT;
baz()
}
fn baz() { longjmp(jmpbuf, 1) }
and bar
is not inlined, then the destructor of bar::x
will run because the bar function is unwound by the longjmp implementation. However, if bar
is inlined into foo
, the longjmp
does not unwind over the cleanup code of bar::x
because it will be somewhere in foo
s stack frame, and that stack frame is not unwound, so the destructor for bar::x
does not run.
### How does cross-language unwinding differ from cross-language | ||
`setjmp`/`longjmp`? | ||
- `setjmp`/`longjmp` across Rust frames is currently guaranteed not to have | ||
undefined behavior or to `abort` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a weird way to say that the behavior of setjmp
/longjmp
is defined. Maybe just explain how their behavior is defined instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Not undefined" is not equivalent to "is defined"; this is an (arguably unfortunate) legacy of the C/C++ ISO standards. Nico and I agree that Rust needs to better specify how "unspecified", "undefined", "implementation defined", etc are to be used in the Rust Reference and elsewhere in the Rust community, but at the moment, I felt that this was the safest phrasing, because "undefined behavior" is (ironically) the best-defined phrase at hand, as far as I can tell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but what I'm saying is that the behavior of setjmp
and longjmp
in Rust is actually defined.
- It should never be assumed that `drop` will be called for objects in | ||
intermediate frames traversed by a `longjmp`, but this may occur on certain | ||
platforms. Rust provides no guarantee either way. Conversely, on platforms | ||
where unwinding is supported, it will always call `drop`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this last sentence mean ? E.g. x86_64-unknown-linux-gnu
is a platform where unwinding is supported, but longjmp never drops values living in stack frames. On other platforms like MSVC, do longjmp
s always drop values on stack frames?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, "it" here should have been "unwinding". You're right, this wasn't clear.
- `setjmp`/`longjmp` across Rust frames is currently guaranteed not to have | ||
undefined behavior or to `abort` | ||
- It should never be assumed that `drop` will be called for objects in | ||
intermediate frames traversed by a `longjmp`, but this may occur on certain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If replacing a longjmp
with a panic
and a setjmp
with a catch_unwind
causes any destructors to run, the behavior is undefined. Some safe Rust abstractions like Pin
rely on such things never happening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, so much for my "safe" phrasing above! But this is sort of what I was worried about and why I don't want to just say that the behavior is defined. Wasn't it pointed out in one of the RFC threads that LLVM with the MSVC linker currently does generate code that causes longjmp
to invoke destructors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't it pointed out in one of the RFC threads that LLVM with the MSVC linker currently does generate code that causes longjmp to invoke destructors?
Since for the case being discussed the behavior is undefined, running destructors is one of the many things that could happen. Whatever LLVM does can change any time as a consequence of this, and IIRC whether destructors are run or not for particular functions depends on things like the optimization level.
where unwinding is supported, it will always call `drop`. | ||
- Rust does not have a concept of `Copy` for stack-frames, which would permit | ||
the compiler to check that `longjmp` may safely traverse those frames. Such a | ||
language feature may be added in the future, but although it would be useful |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can point to Centril/rfc-effects#11 if you want to add more context about what that would entail.
the compiler to check that `longjmp` may safely traverse those frames. Such a | ||
language feature may be added in the future, but although it would be useful | ||
for `longjmp`, it would not be useful for unwinding. | ||
- `setjmp`/`longjmp` does not involve data transfer (the exception object) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value of setjmp
is a data-transfer from a longjmp
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, that's true. I'll modify it to say that the only possible value that can be transferred is c_int
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that you can use the return value of setjmp
to transfer any kind of payload via the heap, just like we do for unwinding (the payload of panic
is behind a Box<dyn Any + ...>
), by doing a heap allocation before the longjmp
and putting the pointer to it in a thread-local, that can be accessed from the setjmp
.
for `longjmp`, it would not be useful for unwinding. | ||
- `setjmp`/`longjmp` does not involve data transfer (the exception object) | ||
- unwinding involves the use of a personality function, which raises additional | ||
cross-language compatibility concerns; `setjmp`/`longjmp` does not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last sentence is unfinished.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I actually just wasn't consistent about putting periods at the end of bullet points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So setjmp
/ longjmp
have some requirements on how the language run-time works, e.g., the setjmp and longjmp must happen on the same thread, etc.
I am guessing you are referring to the part where I used "it" ambiguously, and that my response there resolves this concern? |
Yes, that resolves it. |
The new content is mostly based on the HackMD doc.