Description
Background
We were attempting to fix a name resolution bug in rustc on rust-lang/rust#112743. During our regression testing, we discovered an issue with rust-openssl. In this post, I'll describe the bug and explore potential solutions.
Error log
[INFO] [stderr] Compiling openssl-macros v0.1.1
[INFO] [stdout] error[E0425]: cannot find function, tuple struct or tuple variant `EVP_PKEY_id` in crate `ffi`
[INFO] [stdout] --> src/pkey.rs:195:36
[INFO] [stdout] |
[INFO] [stdout] 195 | unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
[INFO] [stdout] | ^^^^^^^^^^^ help: a constant with a similar name exists: `EVP_PKEY_DH`
[INFO] [stdout] |
[INFO] [stdout] ::: /opt/rustwide/cargo-home/registry/src/index.crates.io-6f17d22bba15001f/openssl-sys-0.9.88/src/./evp.rs:11:1
[INFO] [stdout] |
[INFO] [stdout] 11 | pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement;
[INFO] [stdout] | ---------------------------- similarly named constant `EVP_PKEY_DH` defined here
More details: rust-lang/rust#112743 (comment)
Reduced
macro_rules! cfg_if {
($(
if #[cfg($($meta:meta),*)] { $($it:item)* }
) else * else {
$($it2:item)*
}) => {
cfg_if! {
@__items
() ;
$( ( ($($meta),*) ($($it)*) ), )*
( () ($($it2)*) ),
}
};
(
if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
$(
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
)*
) => {
cfg_if! {
@__items
() ;
( ($($i_met),*) ($($i_it)*) ),
$( ( ($($e_met),*) ($($e_it)*) ), )*
( () () ),
}
};
(@__items ($($not:meta,)*) ; ) => {};
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
};
(@__apply $m:meta, $($it:item)*) => {
$(#[$m] $it)*
};
}
mod openssl {
pub use self::evp::*;
pub use self::handwritten::*;
mod evp {
cfg_if! {
if #[cfg(ossl300)] {
pub unsafe fn EVP_PKEY_id() {}
}
}
}
mod handwritten {
pub use self::evp::*;
mod evp {
cfg_if! {
if #[cfg(ossl300)] {
pub unsafe fn EVP_PKEY_id() {}
} else {
extern "C" {
pub fn EVP_PKEY_id();
}
}
}
}
}
}
pub use openssl::*;
fn main() {
unsafe {
EVP_PKEY_id();
}
}
Actually, when we compile using rustc code.rs --cfg ossl300
, we expect to see an ambiguous error related to EVP_PKEY_id. However, this error is not currently being thrown. Instead, the result indicates that EVP_PKEY_id
is referring to openssl::evp::EVP_PKEY_id
.
btw, if you remove the cfg_if
, you will encounter an ambiguous error:
mod openssl {
pub use self::evp::*;
pub use self::handwritten::*;
mod evp {
#[cfg(all(ossl300, not(any())))]
pub unsafe fn EVP_PKEY_id() {}
}
mod handwritten {
pub use self::evp::*;
mod evp {
#[cfg(all(ossl300, not(any())))]
pub unsafe fn EVP_PKEY_id() {}
#[cfg(all(not(any(ossl300))))]
extern "C" {
pub fn EVP_PKEY_id();
}
}
}
}
pub use openssl::*;
fn main() {
unsafe {
EVP_PKEY_id(); // `EVP_PKEY_id` is ambiguous
}
}
Expected
Since I'm not familiar with this project, I'm not entirely certain how to fix this issue correctly. One possible solution is to remove the pub
keyword from pub unsafe fn EVP_PKEY_id() {}
in handwritten::evp
, or to rename it. In any case, I believe we can resolve this problem and release a new version once it's fixed.