-
Notifications
You must be signed in to change notification settings - Fork 705
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
Version all C/asm symbols to enable cross-version linking. #619
Conversation
|
||
fn main() { | ||
write_versioned_headers(); |
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.
How does this work w.r.t. incremental compilation?
- How do we ensure all the C/asm code is recompiled when the versioned headers are changed?
- How do we ensure that the C/asm code isn't recompiled more than necessary?
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.
Currently, the generated generated_versioned.h
and yasm_versioned.h
headers are written out each time. Since these aren't tracked in RING_INCLUDES
, they shouldn't cause a recompilation. The only header that should cause a recompilation is the manually written versioned.h
header. This header is included in RING_INCLUDES
, so it should trigger recompilation correctly. Thus, I don't think we need to do anything special here to get the right thing to happen. But if I've misunderstood something, do let me know.
The only other optimization I see is to only regenerate the generated header files if versioned.h
is updated.
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.
generated_version.h will change whenever the ring version number is bumped, right? In that case, everything that includes it, directly or indirectly, needs to be recompiled, so that all the symbols get reversioned right? If so then generated_versioned.h. and yasm_versioned would need to be in RING_INCLUDES
or we'd need equivalent logic.
Also, I think we need to have logic that builds these generated header files, then compares the contents wit the contents of any existing header files, and only overwrites the file if there is a difference. That way the time stamp of the files won't change spuriously and we wouldn't trigger recompilation of all the C code each time.
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 I'm not 100% certain how native_versioning
works but shouldn't it be able to just compile the C files normally and then change the symbols before it links them with the Rust code? This wouldn't be as simple as running CC again on the same set of files with some changed, but in theory it should be fine.
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.
@clarcharr Yes, that's also a possible solution. That still requires you to know each symbol you want to change, however, which means you still have to keep a list somewhere. And, what's more, it also requires an objcopy
-like utility to be present. Finding/invoking the utility in a cross-platform and cross-target way can be a challenge.
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.
@SergioBenitez you wouldn't need to keep a list; any symbol that's not linked to a dynamic library should be renamed, right?
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.
Yeah, that's true; all public symbols. Still, I think the other concern, requiring an objcopy
-like utility, is the real issue, and the main reason why I didn't go this route. Note that such a utility would need to exist on the host for the target. I'm not sure how reasonable a requirement that is. We don't have any library like cc
for objcopy
, however, so we'd effectively need to write one.
It's a much more complex solution than what we have now. The current solution never recompiles or reads over binaries; it just compiles once with the symbols redefined.
build.rs
Outdated
@@ -159,7 +162,8 @@ const RING_INCLUDES: &'static [&'static str] = | |||
"include/GFp/bn.h", | |||
"include/GFp/cpu.h", | |||
"include/GFp/mem.h", | |||
"include/GFp/type_check.h"]; | |||
"include/GFp/type_check.h", | |||
"include/versioned.h"]; |
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 file should be under a GFp
directory so that all the include statements are of the form GFp/versioned.h
to prevent conflicts. If that's problematic then we could also just rename the file to have a "gfp_" prefix to its base name.
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.
Should yasm_versioned.h
be here too? The same name collision concerns apply to it.
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.
Hmm. Well, we don't know the path to yasm_versioned.h
since it's generated at build-time, so we wouldn't be able to add it to this array. Because it's generated, however, I don't think it needs to be included in this array. Please do correct me if I'm wrong, however.
@@ -279,6 +276,7 @@ name = "ring" | |||
[dependencies] | |||
libc = "0.2.34" | |||
untrusted = "0.6.1" | |||
native_versioning = { git = "https://github.com/SergioBenitez/native_versioning" } |
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.
In order for us to be able to use this it would need a MIT/ISC/Apache2 license and it would need to be released on crates.io.
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.
Of course. I've added the license to the repository, and as I said in the PR, I'll release it on crates.io once this PR is ready to be merged.
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.
I don't want to use the crate w/o it also being ISC licensed. I don't have any intention of forking it or folding it into ring, but I also want the reassurance that we could fold a variant of it into ring if the dependency were to ever become problematic for any reason, and that would only be realistic if it were ISC licensed since the rest of the ring build is ISC licensed.
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.
I really don't want to get into a license discussion here, but why isn't the MIT license sufficient? It would clearly allow you to do what you're proposing.
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.
I really don't want to get into a license discussion here, but why isn't the MIT license sufficient? It would clearly allow you to do what you're proposing.
I also want to avoid a licensing discussion. ring's build.rs is ISC-licensed and we need to be able to deal with unwanted changes to the native_versioning crate by being able to copy the code into ring using the same license we use for all the Rust code in ring. I don't want to be in the situation where our only reasonable alternative would be to do a new clean-room implementation of the logic.
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.
I think it's rather reasonable to accept the MIT license. But, I really don't care to argue this further, so I've added the ISC license to native_versioning
.
let mut c = Command::new("yasm.exe"); | ||
let _ = c.arg("-X").arg("vc") | ||
.arg("--dformat=cv8") | ||
.arg(oformat) | ||
.arg(machine) | ||
.arg("-P").arg(&yasm_versioned_symbols_header()) |
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.
Instead of doing this, I think we can just change the PerlAsm translator so that it adds an #include
to the generated asm.
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.
There are a couple of assembly files (x25519-asm-$arch.S
) that aren't generated by PerlAsm, so we'd still need to do something about those, too.
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.
OK, thanks for reminding me of that.
use std::fmt::Write; | ||
let line = line?; | ||
if line.starts_with("#define") { | ||
write!(new_data, "%{}\n", &line[1..]).expect("write to str"); |
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.
Why is this needed? Notice that none of the *.pl files do this. I think it may be because PerlAsm does this translation itself. See the suggestion below about having PerlAsm write an #include
into the generated asm files.
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 for yasm
on Windows.
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.
Probably makes sense to add a comment note about that.
let expanded = cc::Build::new() | ||
.file(&intermediate) | ||
.include(&generated_include_dir()) | ||
.expand(); |
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.
I didn't look at the native_versioning crate's source code yet (since I don't know the license). What is the reason that this has to be run through the preprocessor here?
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.
Yes, this whole dance is so that symbols are versioned by yasm
on Windows as well. We can't use the versioned.h
header file for yasm
because its pre-processor uses different syntax. So, instead of having to maintain two versioned.h
files, one for C compilers and another for yasm
, I opted to generated a yasm
-compatible header file in this function from the existing versioned.h
file.
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 this is only needed for yasm then we should only run it when we'd run yasm (windows targets).
However, like I mentioned in the other issue, I think that we should get rid of all the #define
s in versioned.h and instead distribute those #defines
where the declarations/definitions are. This might result in a small number of cases where we need to duplicate the use of VERSIONED()
between C and the assembler code, but that would be less problematic than continuously maintaining the versioned.h file as we rename and add symbols.
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.
That was my initial approach but quickly proved to be much easier said than done. It's very easy to miss a symbol this way and doing this for the perl generated assembly files is even more difficult. We'd need to modify each generator individually or keep a table of which symbols each generator generates. Then we also have to handle the yasm
case specially.
I don't think maintaining the versioned.h
file is any more or less difficult than maintaining #define
's in individual files, but I do think that one versioned.h
file is an overall cleaner and simpler solution.
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.
That was my initial approach but quickly proved to be much easier said than done. It's very easy to miss a symbol this way and doing this for the perl generated assembly files is even more difficult.
There are two cases to consider: How difficult it is for you to write this PR, and how difficult it is for us to change ring in the future after this PR. I understand that getting everything right in this PR doing it the way I propose is tricky; however, the upside of doing it the way I propose is that we're less likely to accidentally forget to add/change the #define
when we add or rename symbols incrementally going forward. In other words, it's going to be somewhat error-prone either way, and we should optimize for minimizing errors in future PRs by people who aren't familiar with this PR.
I think we should go further and just use GFp_VERSIONED()
in the C declaration and C definition of all of the functions that are only called from Rust code, instead of relying on these #defines
. We really only would need these #defines
for functions that are called from the C code, which is smaller and shrinking number of call sites.
For example, instead of:
#define GFp_aes_gcm_open GFp_VERSIONED(GFp_aes_gcm_open)
...
int GFp_aes_gcm_open(const void *ctx_buf, uint8_t *out, size_t in_out_len,
uint8_t tag_out[EVP_AEAD_AES_GCM_TAG_LEN],
const uint8_t nonce[EVP_AEAD_AES_GCM_NONCE_LEN],
const uint8_t *in, const uint8_t *ad, size_t ad_len);
We can just have:
int GFp_VERSIONED(GFp_aes_gcm_open)(
const void *ctx_buf, uint8_t *out, size_t in_out_len,
uint8_t tag_out[EVP_AEAD_AES_GCM_TAG_LEN],
const uint8_t nonce[EVP_AEAD_AES_GCM_NONCE_LEN],
const uint8_t *in, const uint8_t *ad, size_t ad_len));
Because this function is never called from C code.
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.
It's not just that what you're proposing is harder to implement, it's that it's a really complex solution that is difficult to get right. I feel confident that what I've implemented here is correct. It's a simple solution that's simple to audit. Were I to manually edit each and every C, assembly, and perl file, I would not be confident that I've covered all bases. I think what you're proposing is a time consuming endeavor with little to no benefit.
In coming up with a solution, maintainability was a big concern of mine. With the present solution, upstream changes from BoringSSL can be merged as easily as before since there are zero changes being made to any of the legacy code. With what you're proposing, each change has to be manually adjusted to properly version symbols.
I imagine most pull requests being made to ring are changes to Rust code; this PR doesn't introduce any overhead there except for using versioned_extern!
instead of extern
. But, if a PR is made that changes C/assembly code, I think it's easy for the reviewer to keep in mind that symbols are versioned. Or, at least, no more or less hard than the solution you're advocating for would make it.
I feel like your primary concern is getting this right. That's mine as well. If that's the case, then I propose the following compromise: it's very simple to write a script that checks that all public symbols in object files produced from C/assembly are properly versioned. I'll write such a script, and we'll run it on Travis. This way, it's not possible for PRs to miss versioning symbols. What do you say?
Thanks for this. Please add the licensing info to the native_versioning crate so I can read its source code to do this review. |
I have a question regarding what happens when we build from crates.io vs when we build from git. What version suffix is appended to symbols when building from a Git checkout? I would expect that either there wouldn't be a version suffix or the version suffix would be the current git commit sha1 or similar. In particular, consider the case where ring 0.13.0 is released and ring's version number in Git is also still 0.13.0. We need these two copies of ring to have differing version numbers, right? |
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.
OK, this is looking pretty good overall. Thanks for doing it. However, some things need to be changed.
build.rs
Outdated
@@ -271,8 +275,79 @@ const MSVC: &'static str = "msvc"; | |||
const MSVC_OBJ_OPT: &'static str = "/Fo"; | |||
const MSVC_OBJ_EXT: &'static str = "obj"; | |||
|
|||
const GENERATED_VERSIONED_HEADER: &str = "generated_versioned.h"; | |||
const GENERATED_YASM_VERSIONED_HEADER: &str = "generated_yasm_versioned.h"; | |||
const GENERATED_VERSIONED_MACRO: &str = "VERSIONED"; |
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 name, and all other names defined in ring's source code, needs to start with "GFp_" to avoid any potential for collisions.
include/GFp/versioned.h
Outdated
@@ -0,0 +1,400 @@ | |||
#include <generated_versioned.h> |
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 file name needs to be qualified with "GFp/" or "gfp_".
include/GFp/versioned.h
Outdated
#define gfp_little_endian_bytes_from_scalar VERSIONED(gfp_little_endian_bytes_from_scalar) | ||
|
||
// For MacOS symbols generated from perl scripts. | ||
#define _GFp_AES_encrypt VERSIONED(_GFp_AES_encrypt) |
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.
Instead of doing this, can't the header file that defiles VERSIONED
handle this? Basically, when we detect that the macOS assembler is being used, add the '_' prefix. Then we avoid all this duplication.
Also, technically this is not correct for C because we cannot legally #define
names that start with underscores in C; all such names are reserved.
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.
When we're on macOS, we need both versions. The first will be used by C regardless while the second will be used by the generated assembly code.
We could, however, generate the second set on macOS only. IE, we'd kill all of the _
ones from versioned.h
. At build time, check if we're on macOS and emit a new versioned.h
with the _
symbols. If we're not on macOS, we'd simply copy the file over.
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 first will be used by C regardless while the second will be used by the generated assembly code.
Sure. But we can make it so that GFp_VERSIONED()
expands to a name with a leading underscore only when it is included from an assembly file, and expands without the leading underscore all the rest of the time. Then we can completely eliminate the duplication.
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.
No, that's not correct. The #define
has to redefine the underscored symbol (_sym
) to a versioned underscored symbol (_sym_vxxx
) since _sym
is what's in the assembly file. We absolutely need something that's effectively:
#define _sym VERSIONED(_sym)
include/GFp/versioned.h
Outdated
// For MacOS symbols generated from perl scripts. | ||
#define _GFp_AES_encrypt VERSIONED(_GFp_AES_encrypt) | ||
#define _GFp_AES_set_encrypt_key VERSIONED(_GFp_AES_set_encrypt_key) | ||
#define _GFp_BN_copy VERSIONED(_GFp_BN_copy) |
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.
Most of these underscore-prefixed names are actually not necessary, right? GFp_BN_copy()
, for example, the weird thing the assembler does isn't relevant since the function is written in C, right?
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.
That's right. I'm being conservative here. If you know of a simple way to determine all symbols that are only used in assembly, I'm happy to pare down the list to those.
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 you know of a simple way to determine all symbols that are only used in assembly, I'm happy to pare down the list to those.
That's the advantage of my alternative proposal where we use GFp_VERSIONED()
directly within the assembly language files; all of this extra effort for macOS would be automated away.
In a future iteration we could even change the PerlAsm translator so that it knows to do these translations automatically, .e.g. by changing the translation for .extern
. Then we'd have even less manual stuff to maintain going forward.
include/GFp/versioned.h
Outdated
#define GFp_sha512_block_data_order VERSIONED(GFp_sha512_block_data_order) | ||
#define GFp_sha512_block_data_order_avx VERSIONED(GFp_sha512_block_data_order_avx) | ||
#define GFp_sha512_block_data_order_avx2 VERSIONED(GFp_sha512_block_data_order_avx2) | ||
#define GFp_size_t_align VERSIONED(GFp_size_t_align) |
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.
In the case of GFp_size_t_align
, et al., they are already defined using a macro, so that macro can just be modified to use VERSIONED()
itself, something like this:
#define DEFINE_METRICS(ty) \
OPENSSL_EXPORT uint16_t GFp_VERSIONED(GFp_##ty##_align) = alignof(ty); \
OPENSSL_EXPORT uint16_t GFp_VERSIONED(GFp_##ty##_size) = sizeof(ty);
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 I wanted to modify as little C/assembly code as possible. The current solution requires zero modifications. I think it's a nice goal.
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 I wanted to modify as little C/assembly code as possible. The current solution requires zero modifications. I think it's a nice goal.
Again, I think you're thinking about this in terms of minimizing the complexity of this PR. I am much more interested in minimizing the odds that we'll get a future PR wrong, but minimizing the amount of manual effort required for future PRs.
@@ -279,6 +276,7 @@ name = "ring" | |||
[dependencies] | |||
libc = "0.2.34" | |||
untrusted = "0.6.1" | |||
native_versioning = { git = "https://github.com/SergioBenitez/native_versioning" } |
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.
I don't want to use the crate w/o it also being ISC licensed. I don't have any intention of forking it or folding it into ring, but I also want the reassurance that we could fold a variant of it into ring if the dependency were to ever become problematic for any reason, and that would only be realistic if it were ISC licensed since the rest of the ring build is ISC licensed.
let expanded = cc::Build::new() | ||
.file(&intermediate) | ||
.include(&generated_include_dir()) | ||
.expand(); |
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 this is only needed for yasm then we should only run it when we'd run yasm (windows targets).
However, like I mentioned in the other issue, I think that we should get rid of all the #define
s in versioned.h and instead distribute those #defines
where the declarations/definitions are. This might result in a small number of cases where we need to duplicate the use of VERSIONED()
between C and the assembler code, but that would be less problematic than continuously maintaining the versioned.h file as we rename and add symbols.
let mut c = Command::new("yasm.exe"); | ||
let _ = c.arg("-X").arg("vc") | ||
.arg("--dformat=cv8") | ||
.arg(oformat) | ||
.arg(machine) | ||
.arg("-P").arg(&yasm_versioned_symbols_header()) |
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.
OK, thanks for reminding me of that.
@@ -0,0 +1,400 @@ | |||
#include <generated_versioned.h> | |||
|
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.
I think it's going to be unreasonable to maintain this file. Let's move each #define
to be right above the declaration (when in a header file) or definition (when there is no declaration in a header file.) That would make it easier for us to keep everything in sync and it will work better with incremental compilation. In particular when we add/rename a GFp_BN
symbol, we shouldn't need to recompile any C code other than the bignum code.
In the case of the asm/perlasm-defined code, we may need to duplicate the use of VERSIONED()
between the C and asm code, but I am fine with that. Overall it would still be easy to maintain. Especially over time there will be less and less C code calling assembly code (I hope) so less and less duplication needed.
|
||
fn main() { | ||
write_versioned_headers(); |
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.
generated_version.h will change whenever the ring version number is bumped, right? In that case, everything that includes it, directly or indirectly, needs to be recompiled, so that all the symbols get reversioned right? If so then generated_versioned.h. and yasm_versioned would need to be in RING_INCLUDES
or we'd need equivalent logic.
Also, I think we need to have logic that builds these generated header files, then compares the contents wit the contents of any existing header files, and only overwrites the file if there is a difference. That way the time stamp of the files won't change spuriously and we wouldn't trigger recompilation of all the C code each time.
The version appended is always the crate's version and nothing else, regardless of where the crate is being built from. The version in Nevertheless, I think it's a good idea to append something like Edit: Made the necessary changes to |
Looking forward to this update. I have a couple crates that I depend on that (directly and indirectly) depend on different versions of ring. Super frustrating because it means that for right now, I have to manually do a lot of work to just get my project (a production application) to compile. |
One of the requirements for this feature (from the issue) is: "Further, we must not need to keep track of whether we made an "ABI-breaking" change in the C/asm code." In build.rs we already have logic to detect whether we're building from git for other reasons. Let's extend that logic to replace the version suffix with something like "_dev" instead of the version number. |
Sorry, I didn't see this edit. I'll look at the updates you made to that crate. |
@briansmith How are we doing here? Really want to get this in to get Rocket working again. |
My plan is to merge all the BoringSSL changes from 2017 into ring first. Then we'll update this PR taking into consideration the BoringSSL changes. That way we can more effectively evaluate how maintainable the change would be, based on how much effort it is to update the PR. |
There are people regularly coming on Even if this patch is a bit cumbersome to maintain, I don't think the ecosystem can afford not merging it. |
The current highest priority tasks are, in priority order:
All three of these are blocking the ring 0.13 release. |
In the meantime, see https://twitter.com/BRIAN_____/status/955339612381093888. |
(Or something like it). Rocket and jsonwebtoken depend on different versions of `cookie`, and those two versions depend on different versions of `ring`, and `ring` has a policy of not being linked more than once into a binary. You'll get an error like this: ``` error: multiple packages link to native library `ring-asm`, but a native library can be linked only once package `ring v0.11.0` ... which is depended on by `cookie v0.9.2` ... which is depended on by `rocket v0.3.9` ... which is depended on by `changes v0.1.0 (file:///home/coleman/Code/Rust/changes)` links to native library `ring-asm` package `ring v0.12.1` ... which is depended on by `jsonwebtoken v4.0.1` ... which is depended on by `changes v0.1.0 (file:///home/coleman/Code/Rust/changes)` also links to native library `ring-asm` ``` My workaround: fork `jsonwebtoken` and depend on an older `ring` that Rocket transitively depends on, v0.11.0 Refs: briansmith/ring#619 briansmith/ring#535
Any news on this @briansmith @SergioBenitez? In addition I think the native_versioning crate could be useful for other libraries that link to C also. |
I decided to skip unbreaking Android CI for now.
The BoringSSL merge was just completed 5 minutes ago.
There are a lot of merge conflicts after the BoringSSL merge that need to be resolved before this can be merged.
I will release ring 0.13 more-or-less as soon as this PR is merged. |
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 first real CI run can be found here.
This is awesome!
In the aarch64-linux-gnu-gcc output:
GFp_aes_c_encrypt
GFp_aes_hw_decrypt
GFp_aes_c_set_encrypt_key
I believe the above functions just need to be added to the header. They are AArch64-/ARM- specific.
getauxval
This function is provided by libc.
In the i686-unknown-linux-gnu output:
ChaCha20_ssse3
This is 32-bit x86 (i686) specific. It seems I forgot to add the GFp_
prefix to it! Probably because I didn't realize that it is (accidentally) public.I will rename it to _ChaCha20_ssse3
so that it becomes private.
@@ -291,6 +289,10 @@ lazy_static = "1.0" | |||
cc = "1.0.3" | |||
rayon = "0.9.0" | |||
|
|||
[build-dependencies.native_versioning] | |||
git = "https://github.com/SergioBenitez/native_versioning" | |||
features = ["build"] |
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.
When native_versioning is available on crates.io, let's format this like the others:
[build-dependencies]
native_versioning = { version = "whatever", features = ["build"] }
Here is my current plan for this.
|
Rebased again and now all remaining CI errors seems to be unrelated to this PR (most recent CI run) 🎉 |
Any other blockers on that now that 0.13 has been released? |
I spent some time looking at this this weekend. I noticed that the version header is always generated during every execution of build.rs, and also not everything is recompiled if the version header changes. Instead, the version header needs to be generated only if its contents would change, and whenever it does change then everything needs to be rebuilt. |
Paging @SergioBenitez :) |
…nux only for now)
5b35161
to
785f7ad
Compare
I'm working on getting this back into shape and incorporating @1wilkens' work. Should be back in tip-top shape later this weekend. |
3f7e34d
to
ece541c
Compare
OK, the last time I looked at this a while back, there were some parts that I thought were good and there were some parts that I thought were unreasonable. In particular, the hit to incremental compilation in build.rs isn't really acceptable to me because I am constantly rebuilding ring myself all day long and it really slowed down my work by a notable amount. Over the last few months, off and on, I spent quite a lot of time replacing C code with Rust code. Partially, I did so to make this issue easier to fix in a way that doesn't impact incremental builds. In parallel to that, BoringSSL implemented some infrastructure to facilitate something similar to this. I haven't merged that into ring yet, but I think it will help. Here is what I propose:
This way, we don't need to do any extra work in build.rs and we can be reasonably confident that we'll solve the problems we're trying to solve. WDYT? |
@briansmith I'm all for it. We should definitely use the new built-in prefixing in BoringSSL. |
@briansmith Seems good! |
Closing in favor of the approach in #849 which incorporates the upstream support in BoringSSL for symbol prefixing. |
Resolves #535.
Due to a bug in the current stable Rust compiler (rust-lang/rust#44851), this fix won't work on a stable release until the next stable version. Thankfully this is only a few days away as version 1.23 is scheduled to be released on January 4, 2018.
I've tested this on OS X, Linux (Debian), and Windows (Server 2016) with
cargo test
andcargo test --features=rsa_signing
. I've confirmed that all public symbols exported from compiled binaries are versioned on each of these platforms. The only caveat is that I'm getting a warning somewhere along the chain on Windows that I've yet to track down.This makes use of a new crate I've written for this purpose; I've named that crate
native_versioning
for now. For an explanation of how this works, please see that crate's docs. In short:Once the PR is ready to be accepted, I'll publish the
native_versioning
crate and update the PR with the crate's final name.