Skip to content

Commit 2a9fafc

Browse files
authored
Merge pull request #230 from rust-lang/1.24.1-announcement
1.24.1 announcement
2 parents a2eed96 + f0f99b3 commit 2a9fafc

File tree

1 file changed

+268
-0
lines changed

1 file changed

+268
-0
lines changed

_posts/2018-03-01-Rust-1.24.1.md

+268
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
---
2+
layout: post
3+
title: "Announcing Rust 1.24.1"
4+
author: The Rust Core Team
5+
---
6+
7+
The Rust team is happy to announce a new version of Rust, 1.24.1. Rust is a
8+
systems programming language focused on safety, speed, and concurrency.
9+
10+
If you have a previous version of Rust installed via rustup, getting Rust
11+
1.24.1 is as easy as:
12+
13+
```bash
14+
$ rustup update stable
15+
```
16+
17+
If you don't have it already, you can [get `rustup`][install] from the
18+
appropriate page on our website, and check out the [detailed release notes for
19+
1.24.1][notes] on GitHub.
20+
21+
[install]: https://www.rust-lang.org/install.html
22+
[notes]: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1241-2018-03-01
23+
24+
## What's in 1.24.1 stable
25+
26+
Several minor regressions were found in 1.24.0 which collectively merited a
27+
release.
28+
29+
A quick summary of the changes:
30+
31+
* Do not abort when unwinding through FFI (this reverts behavior added in 1.24.0)
32+
* Emit UTF-16 files for linker arguments on Windows
33+
* Make the error index generator work again
34+
* Cargo will warn on Windows 7 if an update is needed.
35+
36+
If your code is continuing to build, then the only issue that may affect you is
37+
the unwinding issue. We plan on bringing this behavior back in 1.25 or 1.26,
38+
depending on how smoothly the new strategy goes.
39+
40+
With that, let's dig into the details!
41+
42+
### Do not abort when unwinding through FFI
43+
44+
TL;DR: the new behavior in 1.24.0 broke the `rlua` crate, and is being
45+
reverted. If you have since changed your code to take advantage of the behavior
46+
in 1.24.0, you'll need to revert it for now. While we still plan to introduce
47+
this behavior eventually, we will be rolling it out more slowly and with a new
48+
implementation strategy.
49+
50+
Quoting [the 1.24 annoucement](https://blog.rust-lang.org/2018/02/15/Rust-1.24.html):
51+
52+
> There’s one other change we’d like to talk about here: undefined behavior.
53+
> Rust generally strives to minimize undefined behavior, having none of it in
54+
> safe code, and as little as possible in unsafe code. One area where you could
55+
> invoke UB is when a panic! goes across an FFI boundary. In other words, this:
56+
57+
```rust
58+
extern "C" fn panic_in_ffi() {
59+
panic!("Test");
60+
}
61+
```
62+
63+
> This cannot work, as the exact mechanism of how panics work would have to
64+
> be reconciled with how the "C" ABI works, in this example, or any other ABI
65+
> in other examples.
66+
>
67+
> In Rust 1.24, this code will now abort instead of producing undefined behavior.
68+
69+
As mentioned above, this caused breakage. It started with [a bug filed against
70+
the `rlua` crate](https://github.com/chucklefish/rlua/issues/71). `rlua` is a
71+
package that provides high level bindings between Rust and the [Lua programming
72+
language](https://www.lua.org/).
73+
74+
> Side note: `rlua` is maintained by [Chucklefish](https://chucklefish.org/),
75+
> a game development studio from London that's using Rust. Lua is a very
76+
> popular language to use for extending and scripting games. We care deeply about
77+
> production Rust users, and so handling this was a very high priority for the
78+
> Rust team.
79+
80+
On Windows, and only on Windows, any attempt to handle errors from Lua would
81+
simply abort. This makes `rlua` unusable, as any error of any kind within Lua
82+
causes your program to die.
83+
84+
After digging in, the culpurit was found: `setjmp`/`longjmp`. These functions
85+
are provided by the C standard library as a means of handling errors. You
86+
first call `setjmp`, and then, at some later point in time, call `longjmp`.
87+
When you do, control flow returns to where you had previously called
88+
`setjmp`. This is often used as a way to implement exceptions, and sometimes,
89+
even coroutines. Lua's implementation uses `setjmp`/`longjmp` [to implement
90+
exceptions](https://www.lua.org/pil/24.3.html):
91+
92+
> Unlike C++ or Java, the C language does not offer an exception handling
93+
> mechanism. To ameliorate this difficulty, Lua uses the setjmp facility from
94+
> C, which results in a mechanism similar to exception handling. (If you
95+
> compile Lua with C++, it is not difficult to change the code so that it uses
96+
> real exceptions instead.)
97+
98+
The issue is this: what happens when some C code `setjmp`/`longjmp`'s through
99+
Rust stack frames? Because drop checking and borrow checking know nothing
100+
about this style of control flow, if you `longjmp` across a Rust stack
101+
frame that has any type that's not `Copy` on its stack, undefined
102+
behavior will result. However, if the jump happens entirely in C, this
103+
should work just fine. This is how `rlua` was managing it: every call
104+
into Lua is [wrapped with `lua_pcall`](https://www.lua.org/pil/24.3.2.html):
105+
106+
> When you write library functions for Lua, however, there is a standard way
107+
> to handle errors. Whenever a C function detects an error, it simply calls
108+
> `lua_error`, (or better yet `luaL_error`, which formats the error message and
109+
> then calls `lua_error`). The `lua_error` function clears whatever needs to be
110+
> cleared in Lua and jumps back to the `lua_pcall` that originated that
111+
> execution, passing along the error message.
112+
113+
So, the question becomes: Why does this break? And why does it break on
114+
Windows?
115+
116+
When we talked about `setjmp`/`longjmp` inititally, a key phrase here wasn't
117+
highlighted. Here it is:
118+
119+
> After digging in, the culpurit was found: `setjmp`/`longjmp`. These functions
120+
> are *provided by the C standard library* as a means of handling errors.
121+
122+
These functions aren't part of the C language, but part of the standard
123+
library. That means that platform authors implement these functions, and
124+
their implementations may differ.
125+
126+
Windows has a concept called SEH, short for ["Structured Exception
127+
Handling"](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx).
128+
Windows uses SEH to implement `setjmp`/`longjmp`, as the whole idea of SEH
129+
is to have uniform error handling. For similar reasons, C++ exceptions use
130+
SEH, as do Rust panics.
131+
132+
Before we can sort the exact details of what's happening, let's look at how `rlua`
133+
works. `rlua` has an internal function, `protect_lua_call`, used to call into
134+
Lua. Using it looks like this:
135+
136+
```rust
137+
protect_lua_call(self.state, 0, 1, |state| {
138+
ffi::lua_newtable(state);
139+
})?;
140+
```
141+
142+
That is, `protect_lua_call` takes some arguments, one of which is a closure. This
143+
closure is passed to `lua_pcall`, which catches any `longjmp`s that may be thrown
144+
by the code passed to it, aka, that closure.
145+
146+
Consider the code above, and imagine that `lua_newtable` here could call
147+
`longjmp`. Here's what should happen:
148+
149+
1. `protect_lua_call` takes our closure, and passes it to `lua_pcall`.
150+
2. `lua_pcall` calls `setjmp` to handle any errors, and invokes our closure.
151+
2. Inside our closure, `lua_newtable` has an error, and calls `longjmp`.
152+
3. The initial `lua_pcall` catches the `longjmp` with the `setjmp` it called earlier.
153+
4. Everyone is happy.
154+
155+
However, the implementation of `protect_lua_call` converts our closure to an
156+
`extern fn`, since that's what Lua needs. So, with the changes in 1.24.0, it
157+
sets up a panic handler that will cause an abort. In other words, the code
158+
sorta looks something like this pseudo code now:
159+
160+
```rust
161+
protect_lua_call(self.state, 0, 1, |state| {
162+
let result = panic::catch_unwind(|| {
163+
ffi::lua_newtable(state);
164+
});
165+
166+
if result.is_err() {
167+
process::abort();
168+
}
169+
})?;
170+
```
171+
172+
Earlier, when discussing `setjmp`/`longjmp`, we said that the issue with it in
173+
Rust code is that it doesn't handle Rust destructors. So, on every platform but
174+
Windows, the above `catch_unwind` shenanigans is effectively ignored, so
175+
everything works. However, on Windows, since both `setjmp`/`longjmp` and Rust
176+
panics use SEH, the `longjmp` gets "caught", and runs the new abort code!
177+
178+
The [solution here](https://github.com/rust-lang/rust/pull/48572) is to
179+
generate the abort handler, but in a way that `longjmp` won't trigger it. It's
180+
not 100% clear if this will make it into Rust 1.25; if the landing is smooth,
181+
we may backport, otherwise, this functionality will be back in 1.26.
182+
183+
### Emit UTF-16 files for linker arguments on Windows
184+
185+
TL;DR: `rustc` stopped working for some Windows users in edge-case situations.
186+
If it's been working for you, you were not affected by this bug.
187+
188+
In constrast with the previous bug, which is very complex and tough to understand,
189+
this bug's impact is simple: if you have non-ASCII paths in the directory where
190+
you invoke `rustc`, in 1.24, it would incorrectly error with a message like
191+
192+
> fatal error LNK1181: cannot open input file
193+
194+
The PR that caused it, [#47507](https://github.com/rust-lang/rust/pull/47507),
195+
has a good explanation of the behavior that ended up causing the problem:
196+
197+
> When spawning a linker rustc has historically been known to blow OS limits
198+
> for the command line being too large, notably on Windows. This is especially
199+
> true of incremental compilation where there can be dozens of object files per
200+
> compilation. The compiler currently has logic for detecting a failure to
201+
> spawn and instead passing arguments via a file instead, but this failure
202+
> detection only triggers if a process actually fails to spawn.
203+
204+
However, when generating that file, we were doing it incorrectly. As [the
205+
docs state](https://docs.microsoft.com/en-gb/cpp/build/reference/unicode-support-in-the-compiler-and-linker#linker-response-files-and-def-files):
206+
207+
> Response files and DEF files can be either UTF-16 with a BOM, or ANSI.
208+
209+
We were providing a UTF-8 encoded file, with no
210+
[BOM](https://en.wikipedia.org/wiki/Byte_order_mark). The fix is therefore
211+
straightforward: produce a UTF-16 file with a BOM.
212+
213+
### Make the error index generator work again
214+
215+
TL;DR: building Rust 1.24.0 with Rust 1.24.0 broke in some circumstances.
216+
If you weren't building Rust yourself, you were not affected by this bug.
217+
218+
When packaging Rust for various Linux distros, it was found that [building
219+
1.24 with 1.24 fails](https://github.com/rust-lang/rust/issues/48308).
220+
This was caused by an incorrect path, causing certain metadata to not
221+
be generated properly.
222+
223+
As this issue is not particularly interesting, and only affects a small
224+
number of people, all of whom should be aware of it by now, we won't go
225+
into the details further. To learn more, please check out the issue and
226+
the resulting discussion.
227+
228+
### Cargo will warn on Windows 7 if an update is needed.
229+
230+
TL;DR: Cargo couldn't fetch the index from crates.io if you were using an older
231+
Windows without having applied security fixes. If you are using a newer
232+
Windows, or a patched Windows, you are not affected by this bug.
233+
234+
In February of 2017, [GitHub announced that they were dropping support for
235+
weak cryptographic
236+
standards](https://githubengineering.com/crypto-deprecation-notice/). One
237+
year later, in February of 2018, [the deprecation period is over, and support
238+
is
239+
removed](https://blog.github.com/2018-02-23-weak-cryptographic-standards-removed/).
240+
In general, this is a great thing.
241+
242+
Cargo uses GitHub to store the index of Crates.io, our package repository.
243+
It also uses `libgit2` for `git` operations. `libgit2` uses
244+
[WinHTTP](https://msdn.microsoft.com/en-us/library/windows/desktop/aa382925(v=vs.85).aspx)
245+
for making HTTP calls. As part of the OS, its feature set depends on the OS you're using.
246+
247+
> This section uses "Windows 7" to mean "Windows 7, Windows Server 2018, and Windows Server 2012",
248+
> because it's much shorter. The following applies to all three of these editions of Windows,
249+
> however.
250+
251+
Windows 7 [received an update](https://support.microsoft.com/en-us/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in)
252+
in June of 2016 regarding TLS. Before the patch, Windows 7 would use TLS 1.0 by default. This update
253+
allows for applications to use TLS 1.1 or 1.2 natively instead.
254+
255+
If your system has not received that update, then you'd still be using TLS 1.0. This means
256+
that accessing GitHub would start to fail.
257+
258+
`libgit2` [created a fix](https://github.com/libgit2/libgit2/pull/4550), using the `WinHTTP` API
259+
to request TLS 1.2. On master, we've [updated to fix this](https://github.com/rust-lang/cargo/pull/5091),
260+
but for 1.24.1 stable, we're [issuing a warning](https://github.com/rust-lang/cargo/pull/5069),
261+
suggesting that they upgrade their Windows version. Although the `libgit2` fix
262+
could have been backported, we felt that the code change footprint was too
263+
large for the point release, especially since the issue does not affect patched
264+
systems.
265+
266+
## Contributors to 1.24.1
267+
268+
[Thanks!](https://thanks.rust-lang.org/rust/1.24.1)

0 commit comments

Comments
 (0)