Skip to content
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

Add and use const_ptr_api macro in openssl-sys #1359

Merged
merged 2 commits into from
Oct 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions openssl-sys/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,8 @@ extern "C" {
pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int;
}

cfg_if! {
if #[cfg(any(ossl110, libressl280))] {
extern "C" {
pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *const ASN1_STRING) -> c_int;
}
} else {
extern "C" {
pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ASN1_STRING) -> c_int;
}
const_ptr_api! {
extern "C" {
pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the macro be changed to only apply to the individual extern definition rather than wrapping the whole extern "C" block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Syntactically speaking I think the macro can do that, but rustc doesn't like it; playground example fails with error[E0428]: the name ASN1_STRING_to_UTF8 is defined multiple times; but when looking at the generated code through Tools -> Expand macros it seems to be doing the right thing.

I'm pretty sure that is the reason why the cfg_if! blocks have internal extern "C" {...} blocks too; probably the same limitation. And even if rustc got fixed and you raise the MSRV, ctest will still fail, as it uses an old fork if a rustc internal crates to do parsing and macro expansion.

Passing extern "C" { ... } can be removed of course, but it can't be part of another extern "C" { ... } block and needs to emit extern "C" { ... } for the fn items.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah bummer. This seems good then!

}
}
39 changes: 8 additions & 31 deletions openssl-sys/src/bio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,10 @@ pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long {
BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void)
}

cfg_if! {
if #[cfg(any(ossl110, libressl280))] {
extern "C" {
pub fn BIO_s_file() -> *const BIO_METHOD;
pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO;
}
} else {
extern "C" {
pub fn BIO_s_file() -> *mut BIO_METHOD;
pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO;
}
const_ptr_api! {
extern "C" {
pub fn BIO_s_file() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD;
pub fn BIO_new(type_: #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD) -> *mut BIO;
}
}
extern "C" {
Expand All @@ -88,26 +81,10 @@ extern "C" {
pub fn BIO_free_all(b: *mut BIO);
}

cfg_if! {
if #[cfg(any(ossl110, libressl280))] {
extern "C" {
pub fn BIO_s_mem() -> *const BIO_METHOD;
}
} else {
extern "C" {
pub fn BIO_s_mem() -> *mut BIO_METHOD;
}
}
}
cfg_if! {
if #[cfg(any(ossl102, libressl280))] {
extern "C" {
pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO;
}
} else {
extern "C" {
pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO;
}
const_ptr_api! {
extern "C" {
pub fn BIO_s_mem() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD;
pub fn BIO_new_mem_buf(buf: #[const_ptr_if(any(ossl102, libressl280))] c_void, len: c_int) -> *mut BIO;
}
}

Expand Down
60 changes: 16 additions & 44 deletions openssl-sys/src/evp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,9 @@ extern "C" {
outl: *mut c_int,
) -> c_int;
}
cfg_if! {
if #[cfg(any(ossl111b, libressl280))] {
extern "C" {
pub fn EVP_PKEY_size(pkey: *const EVP_PKEY) -> c_int;
}
} else {
extern "C" {
pub fn EVP_PKEY_size(pkey: *mut EVP_PKEY) -> c_int;
}
const_ptr_api! {
extern "C" {
pub fn EVP_PKEY_size(pkey: #[const_ptr_if(any(ossl111b, libressl280))] EVP_PKEY) -> c_int;
}
}
cfg_if! {
Expand All @@ -206,23 +200,13 @@ cfg_if! {
}
}
}
cfg_if! {
if #[cfg(any(ossl102, libressl280))] {
extern "C" {
pub fn EVP_DigestVerifyFinal(
ctx: *mut EVP_MD_CTX,
sigret: *const c_uchar,
siglen: size_t,
) -> c_int;
}
} else {
extern "C" {
pub fn EVP_DigestVerifyFinal(
ctx: *mut EVP_MD_CTX,
sigret: *mut c_uchar,
siglen: size_t,
) -> c_int;
}
const_ptr_api! {
extern "C" {
pub fn EVP_DigestVerifyFinal(
ctx: *mut EVP_MD_CTX,
sigret: #[const_ptr_if(any(ossl102, libressl280))] c_uchar,
siglen: size_t,
) -> c_int;
}
}

Expand Down Expand Up @@ -317,15 +301,9 @@ extern "C" {

pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int;
}
cfg_if! {
if #[cfg(any(ossl110, libressl280))] {
extern "C" {
pub fn EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int;
}
} else {
extern "C" {
pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int;
}
const_ptr_api! {
extern "C" {
pub fn EVP_PKEY_bits(key: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int;
}
}
extern "C" {
Expand Down Expand Up @@ -456,15 +434,9 @@ extern "C" {
) -> c_int;
}

cfg_if! {
if #[cfg(any(ossl110, libressl280))] {
extern "C" {
pub fn EVP_PKCS82PKEY(p8: *const PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY;
}
} else {
extern "C" {
pub fn EVP_PKCS82PKEY(p8: *mut PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY;
}
const_ptr_api! {
extern "C" {
pub fn EVP_PKCS82PKEY(p8: #[const_ptr_if(any(ossl110, libressl280))] PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY;
}
}

Expand Down
1 change: 1 addition & 0 deletions openssl-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
unused_imports
)]
#![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")]
#![recursion_limit = "128"] // configure fixed limit across all rust versions

extern crate libc;

Expand Down
209 changes: 209 additions & 0 deletions openssl-sys/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,212 @@ macro_rules! const_fn {
)*
}
}

// openssl changes `*mut` to `*const` in certain parameters in certain versions;
// in C this is ABI and (mostly) API compatible.
//
// We need to handle this explicitly, and this macro helps annotate which
// parameter got converted in which version.
//
// Input is:
// extern "C" {
// #[attributes...]
// pub fn name(args) -> rettype; // `-> rettype` optional
// // more functions...
// }
//
// This macro replaces `#[const_ptr_if(...)]` in types with `*const` or `*mut`
// (depending on the inner cfg flags)
//
// Walks through all argument and return types, but only finds inner types of
// `*const` and `*mut`; doesn't walk arrays or generics.
//
// NOTE: can't abstract `pub` as `$fn_vis:vis`, as ctest macro handling doesn't
// support it (old syntax crate). But we really only need `pub` anyway.
//
// NOTE: ctest seams to simply ignore macros it can't expand (whatever the
// reason)
macro_rules! const_ptr_api {
// ----------------------------------------------------------------
// (partialarg): partial argument, waiting for "final" argument type
// MAGIC PART 1: hande conditional const ptr in argument type
( (partialarg)
{ $(#[$fn_attr:meta])* pub fn $fn_name:ident }
$args_packed:tt
[ $($part_arg:tt)* ]
[ #[const_ptr_if( $($cfg:tt)* )] $($arg_rem:tt)* ]
$ret_packed:tt
) => {
const_ptr_api!( (partialarg) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed );
const_ptr_api!( (partialarg) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed );
};
// continue partial argument with `*mut` pointer (might need special const handling in inner type)
( (partialarg)
$def_packed:tt
$args_packed:tt
[ $($part_arg:tt)* ]
[ *mut $($arg_rem:tt)* ]
$ret_packed:tt
) => {
const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed );
};
// continue partial argument with `*const` pointer (might need special const handling in inner type)
( (partialarg)
$def_packed:tt
$args_packed:tt
[ $($part_arg:tt)* ]
[ *const $($arg_rem:tt)* ]
$ret_packed:tt
) => {
const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed );
};
// finish partial argument with trailing comma
( (partialarg)
$def_packed:tt
{ $($args_tt:tt)* }
[ $($part_arg:tt)* ]
[ $arg_ty:ty, $($arg_rem:tt)* ]
$ret_packed:tt
) => {
const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ $($arg_rem)* ] $ret_packed );
};
// finish final partial argument (no trailing comma)
( (partialarg)
$def_packed:tt
{ $($args_tt:tt)* }
[ $($part_arg:tt)* ]
[ $arg_ty:ty ]
$ret_packed:tt
) => {
const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ ] $ret_packed );
};

// ----------------------------------------------------------------
// (parseargs): parsing arguments
// start next argument
( (parseargs)
$def_packed:tt
$args_packed:tt
[ $arg_name:ident : $($arg_rem:tt)* ]
$ret_packed:tt
) => {
const_ptr_api!( (partialarg) $def_packed $args_packed [ $arg_name: ] [ $($arg_rem)* ] $ret_packed );
};
// end of arguments, there is a return type; start parsing it
( (parseargs)
$def_packed:tt
$args_packed:tt
[ ]
[ -> $($rem:tt)* ]
) => {
const_ptr_api!( (partialret) $def_packed $args_packed [] [ $($rem)* ] );
};
// end of arguments, no return type
( (parseargs)
$def_packed:tt
$args_packed:tt
[ ]
[ ]
) => {
const_ptr_api!( (generate) $def_packed $args_packed { () } );
};

// ----------------------------------------------------------------
// (partialret): have partial return type, waiting for final return type
// MAGIC PART 2: hande conditional const ptr in return type
( (partialret)
{ $(#[$fn_attr:meta])* pub fn $fn_name:ident }
$args_packed:tt
[ $($part_ret:tt)* ]
[ #[const_ptr_if( $($cfg:tt)* )] $($rem:tt)* ]
) => {
const_ptr_api!( (partialret) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *const ] [ $($rem)* ] );
const_ptr_api!( (partialret) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] );
};
// `* mut` part in return type; continue parsing to find inner conditional const ptr
( (partialret)
$def_packed:tt
$args_packed:tt
[ $($part_ret:tt)* ]
[ *mut $($rem:tt)* ]
) => {
const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] );
};
// `* const` part in return type; continue parsing to find inner conditional const ptr
( (partialret)
$def_packed:tt
$args_packed:tt
[ $($part_ret:tt)* ]
[ *const $($rem:tt)* ]
) => {
const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *const ] [ $($rem)* ] );
};
// final part of return type
( (partialret)
$def_packed:tt
$args_packed:tt
[ $($part_ret:tt)* ]
[ $ret_ty:ty ]
) => {
const_ptr_api!( (generate) $def_packed $args_packed { $($part_ret)* $ret_ty } );
};

// ----------------------------------------------------------------
// generate
( (generate)
{ $(#[$fn_attr:meta])* pub fn $fn_name:ident }
{ $({ $arg_name:ident: $($arg_ty:tt)* })* }
{ $ret_ty:ty }
) => {
extern "C" {
$(#[$fn_attr])*
pub fn $fn_name( $(
$arg_name: $($arg_ty)*
),* ) -> $ret_ty;
}
};

// ----------------------------------------------------------------
// (fn): gather tokens for return type until ";"
// found end; start parsing current function, and parse remaining functions
( (fn)
$def_packed:tt
$arg_tts_packed:tt
$ret_packed:tt
[ ; $($rem:tt)* ]
) => {
const_ptr_api!( (parseargs) $def_packed {} $arg_tts_packed $ret_packed );
const_ptr_api!( (extern) [ $($rem)* ] );
};
// not ";" - all other tokens are part of the return type.
// don't expand return type yet; otherwise we'd have to remember in which branch `rem` needs
// to be used to parse further functions.
( (fn)
$def_packed:tt
$arg_tts_packed:tt
[ $($ret_tt:tt)* ]
[ $tt:tt $($rem:tt)* ]
) => {
const_ptr_api!( (fn) $def_packed $arg_tts_packed [ $($ret_tt)* $tt ] [ $($rem)* ] );
};

// ----------------------------------------------------------------
// (extern): in extern block, find next function
// try to split into functions as fast as possible to reduce recursion depth
( (extern) [
$(#[$fn_attr:meta])*
pub fn $fn_name:ident( $($arg_rem:tt)* ) $($rem:tt)*
] ) => {
const_ptr_api!( (fn)
{ $(#[$fn_attr])* pub fn $fn_name } [ $($arg_rem)* ] [] [ $($rem)* ]
);
};
// end of extern block
( (extern) [] ) => {};

// ----------------------------------------------------------------
// macro start; find extern block
( extern "C" { $($rem:tt)* } ) => {
const_ptr_api!( (extern) [ $($rem)* ] );
};
}
Loading