Use SipHasher rather than SHA-512 for ISLE manifest.

Fixes #3609. It turns out that `sha2` is a nontrivial dependency for
Cranelift in many contexts, partly because it pulls in a number of other
crates as well.

One option is to remove the hash check under certain circumstances, as
implemented in #3616. However, this is undesirable for other reasons:
having different dependency options in Wasmtime in particular for
crates.io vs. local builds is not really possible, and so either we
still have the higher build cost in Wasmtime, or we turn off the checks
by default, which goes against the original intent of ensuring developer
safety (no mysterious stale-source bugs).

This PR uses `SipHash` instead, which is built into the standard
library. `SipHash` is deprecated, but it's fixed and deterministic
(across runs and across Rust versions), which is what we need, unlike
the suggested replacement `std::collections::hash_map::DefaultHasher`.
The result is only 64 bits, and is not cryptographically secure, but we
never needed that; we just need a simple check to indicate when we
forget a `rebuild-isle`.
This commit is contained in:
Chris Fallin
2021-12-17 11:58:06 -08:00
parent e94ebc2263
commit 5233175b06
5 changed files with 33 additions and 15 deletions

View File

@@ -16,7 +16,6 @@
use cranelift_codegen_meta as meta;
use sha2::{Digest, Sha512};
use std::env;
use std::io::Read;
use std::process;
@@ -163,7 +162,28 @@ impl IsleCompilation {
/// `<generated_filename>.manifest` and use it to verify that a
/// rebuild was done if necessary.
fn compute_manifest(&self) -> Result<String, Box<dyn std::error::Error + 'static>> {
// We use the deprecated SipHasher from std::hash in order to verify
// that ISLE sources haven't changed since the generated source was
// last regenerated.
//
// We use this instead of a stronger and more usual content hash, like
// SHA-{160,256,512}, because it's built into the standard library and
// we don't want to pull in a separate crate. We try to keep Cranelift
// crate dependencies as intentionally small as possible. In fact, we
// used to use the `sha2` crate for SHA-512 and this turns out to be
// undesirable for downstream consumers (see #3609).
//
// Why not the recommended replacement
// `std::collections::hash_map::DefaultHasher`? Because we need the
// hash to be deterministic, both between runs (i.e., not seeded with
// random state) and across Rust versions.
//
// If `SipHasher` is ever actually removed from `std`, we'll need to
// find a new option, either a very small crate or something else
// that's built-in.
#![allow(deprecated)]
use std::fmt::Write;
use std::hash::{Hasher, SipHasher};
let mut manifest = String::new();
@@ -176,11 +196,11 @@ impl IsleCompilation {
// to `\r\n`; canonicalize the source that we hash to
// Unix-style (`\n`) so hashes will match.
let content = content.replace("\r\n", "\n");
// One line in the manifest: <filename> <sha-512 hash>.
let mut hasher = Sha512::default();
hasher.update(content.as_bytes());
// One line in the manifest: <filename> <siphash>.
let mut hasher = SipHasher::new_with_keys(0, 0); // fixed keys for determinism
hasher.write(content.as_bytes());
let filename = format!("{}", filename.display()).replace("\\", "/");
writeln!(&mut manifest, "{} {:x}", filename, hasher.finalize())?;
writeln!(&mut manifest, "{} {:x}", filename, hasher.finish())?;
}
Ok(manifest)