Git Product home page Git Product logo

libffi-rs's Introduction

libffi-rs: Rust bindings for libffi

GitHub Workflow Status Documentation Crates.io License: MIT License: Apache 2.0

The C libffi library provides two main facilities: assembling calls to functions dynamically, and creating closures that can be called as ordinary C functions. In Rust, the latter means that we can turn a Rust lambda (or any object implementing Fn/FnMut) into an ordinary C function pointer that we can pass as a callback to C.

Repository Layout

This repository is a Cargo workspace containing both libffi and libffi-sys.

Usage

Building libffi will build lifbffi-sys, which will in turn build the libffi C library from github, which requires that you have a working make, C compiler, automake, and autoconf first. It’s on crates.io, so you can add

[dependencies]
libffi = "2.0.0"

to your Cargo.toml.

This crate depends on the libffi-sys crate, which by default attempts to build its own version of the C libffi library. In order to use your system’s C libffi instead, enable this crate’s system feature in your Cargo.toml:

[features]
libffi = { version = "2.0.0", features = ["system"] }

See the libffi-sys documentation for more information about how it finds C libffi.

This crate supports Rust version 1.48 and later.

Examples

In this example, we convert a Rust lambda containing a free variable into an ordinary C code pointer. The type of fun below is extern "C" fn(u64, u64) -> u64.

use libffi::high::Closure2;

let x = 5u64;
let f = |y: u64, z: u64| x + y + z;

let closure = Closure2::new(&f);
let fun     = closure.code_ptr();

assert_eq!(18, fun(6, 7));

libffi-rs's People

Contributors

aapoalas avatar andrewgaspar avatar catamorphism avatar chenx97 avatar cholcombe973 avatar dependabot-preview[bot] avatar dependabot-support avatar fracek avatar heiher avatar littledivy avatar mdekstrand avatar messense avatar monadic-cat avatar ngkz avatar pfmooney avatar piggynl avatar ralfjung avatar ry avatar syrel avatar timfish avatar tov avatar uweigand avatar xtldr avatar yorickpeterse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

libffi-rs's Issues

unresolved import `crate::raw::ffi_type_longdouble`

I started to get an error in my crate which uses libffi today.
Any ideas?

Compiling libffi v2.0.0
error[E0432]: unresolved import `crate::raw::ffi_type_longdouble`
   --> /Users/../.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-2.0.0/src/low.rs:140:13
    |
140 |     pub use crate::raw::ffi_type_longdouble as longdouble;
    |             ^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^
    |             |           |
    |             |           help: a similar name exists in the module: `FFI_TYPE_LONGDOUBLE`
    |             no `ffi_type_longdouble` in `raw`

For more information about this error, try `rustc --explain E0432`.

libffi-sys refuses to build with gnu toolchain on Windows

   Compiling libffi-sys v1.1.0
     Running `<MY_RUST_PROJECT_PATH>\target\release\build\libffi-sys-bcfb47f615dc8bff\build-script-build`
error: failed to run custom build command for `libffi-sys v1.1.0`

Caused by:
  process didn't exit successfully: `<MY_RUST_PROJECT_PATH>\target\release\build\libffi-sys-bcfb47f615dc8bff\build-script-build` (exit code:101)
  --- stderr
  thread 'main' panicked at 'Copying libffi into the build directory: Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }', <...>\rust-lang\.cargo\registry\src\github.com-1285ae84e5963aae\libffi-sys-1.1.0\build\common.rs:8:26
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

This looks similar to this issue:
tov/libffi-sys-rs#16

Shell command:

$> cargo +nightly-i686-pc-windows-gnu build --release --verbose --all --jobs 1 --target i686-pc-windows-gnu

My setup:

$> cargo -Vv

cargo 1.51.0 (43b129a20 2021-03-16)
release: 1.51.0
commit-hash: 43b129a20fbf1ede0df411396ccf0c024bf34134
commit-date: 2021-03-16

$> rustc -Vv

rustc 1.51.0 (2fd73fabe 2021-03-23)
binary: rustc
commit-hash: 2fd73fabe469357a12c2c974c140f67e7cdd76d0
commit-date: 2021-03-23
host: x86_64-pc-windows-gnu
release: 1.51.0
LLVM version: 11.0.1

GCC version:

gcc (i686-win32-dwarf-rev0, Built by MinGW-W64 project) 8.1.0
i686-8.1.0-win32-dwarf-rt_v6-rev0

Need some beginner documentation

Hi, thanks for this great crate.

I'm not sure how to store the intermediate types in a struct, could an example of this be added?

I'll give some context.

This works:

        let user_f = |s: &str| {
            println!("User got: {}", s);
        };

        let inner_f = |c_str| {
            let c_str = unsafe { CStr::from_ptr(c_str) };
            let str_slice = c_str.to_str().unwrap();
            user_f(str_slice);
        };
        let libffi_f = Closure1::new(&inner_f);

        let fun = libffi_f.code_ptr();

        MyStruct::new_with_callbacks(fun).unwrap();

However, I would like this user API to only need to specify the first closure. So something like:

        let user_f = |s: &str| {
            println!("User got: {}", s);
        };

        MyStruct::new_with_callbacks(user_f).unwrap();

This means I have to do the other work further down in the call-chain, and store all the functions somewhere.

My assumptions:

  • If user_f is dropped, the inner_f closure won't work since it uses that closure
  • If inner_f is dropped, libffi_f's reference is invalid
  • If libffi_f is dropped, any use of code_ptr() is invalid

Please correct me if I am wrong on any of those.

So my attempt is to create something like:

    struct MyStruct {
        user_f: Box<dyn Fn(String)>,
        inner_f: Box<dyn Fn(*const i8)>,
        libffi_f: Closure1<*const i8, ()>,
    }

But I am getting errors with needing named lifetime parameters on the pointers, and this struct references stuff in itself so I'm in a lot of trouble.

Could you help me out?

I will gladly contribute a PR with a test that shows the correct use if you teach me.
So others can benefit as well.

Support no_std + alloc

Hi!

I'm currently running a local fork of this project in order to do some FFI things in a no_std application (with alloc). Of course it'd be a lot nicer to simply rely on the upstream repo.

If you take a look at the comparison against my fork (where I put all changes behind a no_std feature flag) you see its 90% just importing things from core rather than std. Would this be something feasible to get in libffi-rs?

master...val3rius:libffi-rs:no_std

Thanks a bunch!

Build error in vscode dev container

I run into errors when trying to build/use the library in a nightly project inside an docker container (visual studio code dev container).

Cargo tells me the following when trying to build.

error: failed to run custom build command for `libffi-sys v2.1.0`
note: To improve backtraces for build dependencies, set the CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable to enable debug information generation.

Caused by:
  process didn't exit successfully: `/workspaces/serverless/target/debug/build/libffi-sys-5ecfe1cce31411db/build-script-build` (exit status: 101)
  --- stdout
  checking build system type... x86_64-pc-linux-gnu
  checking host system type... x86_64-pc-linux-gnu
  checking target system type... x86_64-pc-linux-gnu
  continue configure in default builddir "./x86_64-unknown-linux-gnu"
  ....exec /bin/bash ../configure "--srcdir=.." "--enable-builddir=x86_64-unknown-linux-gnu" "linux
  gnu"

  --- stderr
  ../configure: line 2251: config.log: No such file or directory
  ../configure: line 2261: config.log: No such file or directory
  cat: standard output: No such file or directory
  thread 'main' panicked at 'Configuring libffi', /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/libffi-sys-2.1.0/build/common.rs:8:5
  stack backtrace:
     0: rust_begin_unwind
               at /rustc/2036fdd24f77d607dcfaa24c48fbe85d3f785823/library/std/src/panicking.rs:577:5
     1: core::panicking::panic_fmt
               at /rustc/2036fdd24f77d607dcfaa24c48fbe85d3f785823/library/core/src/panicking.rs:67:14
     2: core::panicking::panic_display
     3: build_script_build::common::run_command
     4: build_script_build::not_msvc::configure_libffi
     5: build_script_build::not_msvc::build_and_link
     6: build_script_build::main
     7: core::ops::function::FnOnce::call_once
  note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Versions:

rustc 1.70.0-nightly (2036fdd24 2023-03-27)
cargo 1.70.0-nightly (145219a9f 2023-03-27)

Environment:

Container Image: mcr.microsoft.com/devcontainers/rust:0-1-bullseye
(Guess it is debian because of the bullseye)

If any other information is needed, please tell me. It builds finde on my linux machine (arch) and on windows direct, only inside the container it does not build.

Release 1.0.0

Once libffi-sys-rs 1.0.0 is released (tov/libffi-sys-rs#39), we can start working towards version 1.0.0 of the libffi crate. For this release it would be nice to also include ARMv7 support as added in #14, though that PR may need to be rebased after updating libffi-rs for libffi-sys-rs 1.0.0

TODO

  • Release libffi-sys-rs 1.0.0
  • Update master to use this new version
  • Merge #14 For a future release
  • Publish to crates.io

Outdated version of vendored `libffi` causes build error on macOS Big Sur with M1 processor

FYI, I'm testing this from the RustPython project, whose jit feature imports an outdated version of this library. RustPython/RustPython#3050 updates the libffi crate to v2.0.0, which unfortunately still has this problem. A workaround is to specify the system feature.

Output from cargo build
   Compiling libffi-sys v1.1.3
error: failed to run custom build command for `libffi-sys v1.1.3`

Caused by:
  process didn't exit successfully: `~/Documents/GitHub/RustPython/target/release/build/libffi-sys-d3f96f963a2ec199/build-script-build` (exit status: 101)
  --- stdout
  glibtoolize: putting auxiliary files in '.'.
  glibtoolize: copying file './ltmain.sh'
  glibtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
  glibtoolize: copying file 'm4/libtool.m4'
  glibtoolize: copying file 'm4/ltoptions.m4'
  glibtoolize: copying file 'm4/ltsugar.m4'
  glibtoolize: copying file 'm4/ltversion.m4'
  glibtoolize: copying file 'm4/lt~obsolete.m4'
  checking build system type... arm-apple-darwin20.6.0
  checking host system type... arm-apple-darwin20.6.0
  checking target system type... arm-apple-darwin20.6.0
  continue configure in default builddir "./aarch64-apple-darwin"
  ....exec /bin/sh ../configure "--srcdir=.." "--enable-builddir=aarch64-apple-darwin" "darwin20.6.0"
  checking build system type... arm-apple-darwin20.6.0
  checking host system type... arm-apple-darwin20.6.0
  checking target system type... arm-apple-darwin20.6.0
  checking for gsed... sed
  checking for a BSD-compatible install... /usr/bin/install -c
  checking whether build environment is sane... yes
  checking for a race-free mkdir -p... ../install-sh -c -d
  checking for gawk... no
  checking for mawk... no
  checking for nawk... no
  checking for awk... awk
  checking whether make sets $(MAKE)... yes
  checking whether make supports nested variables... yes
  checking for gcc... gcc
  checking whether the C compiler works... yes
  checking for C compiler default output file name... a.out
  checking for suffix of executables... 
  checking whether we are cross compiling... no
  checking for suffix of object files... o
  checking whether the compiler supports GNU C... yes
  checking whether gcc accepts -g... yes
  checking for gcc option to enable C11 features... none needed
  checking whether gcc understands -c and -o together... yes
  checking whether make supports the include directive... yes (GNU style)
  checking dependency style of gcc... gcc3
  checking for g++... g++
  checking whether the compiler supports GNU C++... yes
  checking whether g++ accepts -g... yes
  checking for g++ option to enable C++11 features... none needed
  checking dependency style of g++... gcc3
  checking dependency style of gcc... gcc3
  checking how to print strings... printf
  checking for a sed that does not truncate output... /usr/bin/sed
  checking for grep that handles long lines and -e... /usr/bin/grep
  checking for egrep... /usr/bin/grep -E
  checking for fgrep... /usr/bin/grep -F
  checking for ld used by gcc... /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
  checking if the linker (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld) is GNU ld... no
  checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
  checking the name lister (/usr/bin/nm -B) interface... BSD nm
  checking whether ln -s works... yes
  checking the maximum length of command line arguments... 786432
  checking how to convert arm-apple-darwin20.6.0 file names to arm-apple-darwin20.6.0 format... func_convert_file_noop
  checking how to convert arm-apple-darwin20.6.0 file names to toolchain format... func_convert_file_noop
  checking for /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld option to reload object files... -r
  checking for objdump... objdump
  checking how to recognize dependent libraries... pass_all
  checking for dlltool... no
  checking how to associate runtime and link libraries... printf %s\n
  checking for ar... ar
  checking for archiver @FILE support... no
  checking for strip... strip
  checking for ranlib... ranlib
  checking command to parse /usr/bin/nm -B output from gcc object... ok
  checking for sysroot... no
  checking for a working dd... /bin/dd
  checking how to truncate binary pipes... /bin/dd bs=4096 count=1
  checking for mt... no
  checking if : is a manifest tool... no
  checking for dsymutil... dsymutil
  checking for nmedit... nmedit
  checking for lipo... lipo
  checking for otool... otool
  checking for otool64... no
  checking for -single_module linker flag... yes
  checking for -exported_symbols_list linker flag... yes
  checking for -force_load linker flag... yes
  checking for stdio.h... yes
  checking for stdlib.h... yes
  checking for string.h... yes
  checking for inttypes.h... yes
  checking for stdint.h... yes
  checking for strings.h... yes
  checking for sys/stat.h... yes
  checking for sys/types.h... yes
  checking for unistd.h... yes
  checking for dlfcn.h... yes
  checking for objdir... .libs
  checking if gcc supports -fno-rtti -fno-exceptions... yes
  checking for gcc option to produce PIC... -fno-common -DPIC
  checking if gcc PIC flag -fno-common -DPIC works... yes
  checking if gcc static flag -static works... no
  checking if gcc supports -c -o file.o... yes
  checking if gcc supports -c -o file.o... (cached) yes
  checking whether the gcc linker (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld) supports shared libraries... yes
  checking dynamic linker characteristics... darwin20.6.0 dyld
  checking how to hardcode library paths into programs... immediate
  checking whether stripping libraries is possible... yes
  checking if libtool supports shared libraries... yes
  checking whether to build shared libraries... yes
  checking whether to build static libraries... yes
  checking how to run the C++ preprocessor... g++ -E
  checking for ld used by g++... /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
  checking if the linker (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld) is GNU ld... no
  checking whether the g++ linker (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld) supports shared libraries... yes
  checking for g++ option to produce PIC... -fno-common -DPIC
  checking if g++ PIC flag -fno-common -DPIC works... yes
  checking if g++ static flag -static works... no
  checking if g++ supports -c -o file.o... yes
  checking if g++ supports -c -o file.o... (cached) yes
  checking whether the g++ linker (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld) supports shared libraries... yes
  checking dynamic linker characteristics... darwin20.6.0 dyld
  checking how to hardcode library paths into programs... immediate
  checking size of size_t... 8
  checking for C compiler vendor... clang

  ********************************************************
  * WARNING: Don't know the best CFLAGS for this system  *
  * Use ./configure CFLAGS=... to specify your own flags *
  * (otherwise, a default of CFLAGS=-O3 will be used)    *
  ********************************************************

  checking whether C compiler accepts -O3... yes
  checking CFLAGS for maximum warnings... -Wall
  checking whether to enable maintainer-specific portions of Makefiles... no
  checking for sys/mman.h... yes
  checking for mmap... yes
  checking for mkostemp... yes
  checking for sys/mman.h... (cached) yes
  checking for mmap... (cached) yes
  checking whether read-only mmap of a plain file works... yes
  checking whether mmap from /dev/zero works... no
  checking for MAP_ANON(YMOUS)... yes
  checking whether mmap with MAP_ANON(YMOUS) works... yes
  checking for egrep... (cached) /usr/bin/grep -E
  checking for memcpy... yes
  checking for size_t... yes
  checking for working alloca.h... yes
  checking for alloca... yes
  checking size of double... 8
  checking size of long double... 8
  checking whether byte ordering is bigendian... no
  checking assembler .cfi pseudo-op support... no
  checking for _ prefix in compiled symbols... yes
  checking whether .eh_frame section should be read-only... no
  checking for __attribute__((visibility("hidden")))... yes
  checking for ld used by gcc... (cached) /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
  checking if the linker (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld) is GNU ld... (cached) no
  configure: versioning on shared library symbols is no
  checking that generated files are newer than configure... done
  configure: creating ./config.status
  config.status: creating include/Makefile
  config.status: creating include/ffi.h
  config.status: creating Makefile
  config.status: creating testsuite/Makefile
  config.status: creating man/Makefile
  config.status: creating doc/Makefile
  config.status: creating libffi.pc
  config.status: creating fficonfig.h
  config.status: executing buildir commands
  config.status: create top_srcdir/Makefile guessed from local Makefile
  config.status: build in aarch64-apple-darwin (HOST=aarch64-apple-darwin)
  config.status: executing depfiles commands
  config.status: executing libtool commands
  config.status: executing include commands
  config.status: executing src commands
  MAKE aarch64-apple-darwin :        1 * install
  Making install in include
  make[3]: Nothing to be done for `install-exec-am'.
   ../../install-sh -c -d '~/Documents/GitHub/RustPython/target/release/build/libffi-sys-dc92f43a95626daf/out/libffi-root/include'
   /usr/bin/install -c -m 644 ffi.h ffitarget.h '~/Documents/GitHub/RustPython/target/release/build/libffi-sys-dc92f43a95626daf/out/libffi-root/include'
  Making install in testsuite
  make[3]: Nothing to be done for `install-exec-am'.
  make[3]: Nothing to be done for `install-data-am'.
  Making install in man
  make[3]: Nothing to be done for `install-exec-am'.
   ../../install-sh -c -d '~/Documents/GitHub/RustPython/target/release/build/libffi-sys-dc92f43a95626daf/out/libffi-root/share/man/man3'
   /usr/bin/install -c -m 644 ../../man/ffi.3 ../../man/ffi_call.3 ../../man/ffi_prep_cif.3 ../../man/ffi_prep_cif_var.3 '~/Documents/GitHub/RustPython/target/release/build/libffi-sys-dc92f43a95626daf/out/libffi-root/share/man/man3'
  depbase=`echo src/prep_cif.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src   -O3 -Wall -fexceptions -MT src/prep_cif.lo -MD -MP -MF $depbase.Tpo -c -o src/prep_cif.lo ../src/prep_cif.c &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/prep_cif.lo -MD -MP -MF src/.deps/prep_cif.Tpo -c ../src/prep_cif.c  -fno-common -DPIC -o src/.libs/prep_cif.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/prep_cif.lo -MD -MP -MF src/.deps/prep_cif.Tpo -c ../src/prep_cif.c  -fno-common -DPIC -o src/prep_cif.o >/dev/null 2>&1
  depbase=`echo src/types.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src   -O3 -Wall -fexceptions -MT src/types.lo -MD -MP -MF $depbase.Tpo -c -o src/types.lo ../src/types.c &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/types.lo -MD -MP -MF src/.deps/types.Tpo -c ../src/types.c  -fno-common -DPIC -o src/.libs/types.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/types.lo -MD -MP -MF src/.deps/types.Tpo -c ../src/types.c  -fno-common -DPIC -o src/types.o >/dev/null 2>&1
  depbase=`echo src/raw_api.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src   -O3 -Wall -fexceptions -MT src/raw_api.lo -MD -MP -MF $depbase.Tpo -c -o src/raw_api.lo ../src/raw_api.c &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/raw_api.lo -MD -MP -MF src/.deps/raw_api.Tpo -c ../src/raw_api.c  -fno-common -DPIC -o src/.libs/raw_api.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/raw_api.lo -MD -MP -MF src/.deps/raw_api.Tpo -c ../src/raw_api.c  -fno-common -DPIC -o src/raw_api.o >/dev/null 2>&1
  depbase=`echo src/java_raw_api.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src   -O3 -Wall -fexceptions -MT src/java_raw_api.lo -MD -MP -MF $depbase.Tpo -c -o src/java_raw_api.lo ../src/java_raw_api.c &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/java_raw_api.lo -MD -MP -MF src/.deps/java_raw_api.Tpo -c ../src/java_raw_api.c  -fno-common -DPIC -o src/.libs/java_raw_api.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/java_raw_api.lo -MD -MP -MF src/.deps/java_raw_api.Tpo -c ../src/java_raw_api.c  -fno-common -DPIC -o src/java_raw_api.o >/dev/null 2>&1
  depbase=`echo src/closures.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src   -O3 -Wall -fexceptions -MT src/closures.lo -MD -MP -MF $depbase.Tpo -c -o src/closures.lo ../src/closures.c &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/closures.lo -MD -MP -MF src/.deps/closures.Tpo -c ../src/closures.c  -fno-common -DPIC -o src/.libs/closures.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/closures.lo -MD -MP -MF src/.deps/closures.Tpo -c ../src/closures.c  -fno-common -DPIC -o src/closures.o >/dev/null 2>&1
  depbase=`echo src/arm/ffi.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src   -O3 -Wall -fexceptions -MT src/arm/ffi.lo -MD -MP -MF $depbase.Tpo -c -o src/arm/ffi.lo ../src/arm/ffi.c &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/arm/ffi.lo -MD -MP -MF src/arm/.deps/ffi.Tpo -c ../src/arm/ffi.c  -fno-common -DPIC -o src/arm/.libs/ffi.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -O3 -Wall -fexceptions -MT src/arm/ffi.lo -MD -MP -MF src/arm/.deps/ffi.Tpo -c ../src/arm/ffi.c  -fno-common -DPIC -o src/arm/ffi.o >/dev/null 2>&1
  depbase=`echo src/arm/sysv.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
  	/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I. -I../include -Iinclude -I../src  -I. -I../include -Iinclude -I../src  -MT src/arm/sysv.lo -MD -MP -MF $depbase.Tpo -c -o src/arm/sysv.lo ../src/arm/sysv.S &&\
  	mv -f $depbase.Tpo $depbase.Plo
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -I. -I../include -Iinclude -I../src -MT src/arm/sysv.lo -MD -MP -MF src/arm/.deps/sysv.Tpo -c ../src/arm/sysv.S  -fno-common -DPIC -o src/arm/.libs/sysv.o
  libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I. -I../include -Iinclude -I../src -I. -I../include -Iinclude -I../src -MT src/arm/sysv.lo -MD -MP -MF src/arm/.deps/sysv.Tpo -c ../src/arm/sysv.S  -fno-common -DPIC -o src/arm/sysv.o >/dev/null 2>&1
  /bin/sh ./libtool  --tag=CC   --mode=link gcc  -O3 -Wall -fexceptions   -o libffi_convenience.la  src/prep_cif.lo src/types.lo src/raw_api.lo src/java_raw_api.lo src/closures.lo   src/arm/ffi.lo src/arm/sysv.lo 
  libtool: link: ar cru .libs/libffi_convenience.a src/.libs/prep_cif.o src/.libs/types.o src/.libs/raw_api.o src/.libs/java_raw_api.o src/.libs/closures.o src/arm/.libs/ffi.o src/arm/.libs/sysv.o 
  libtool: link: ranlib .libs/libffi_convenience.a
  libtool: link: ( cd ".libs" && rm -f "libffi_convenience.la" && ln -s "../libffi_convenience.la" "libffi_convenience.la" )
  /bin/sh ./libtool  --tag=CC   --mode=link gcc  -O3 -Wall -fexceptions -no-undefined -version-info `grep -v '^#' ../libtool-version`     -o libffi.la -rpath ~/Documents/GitHub/RustPython/target/release/build/libffi-sys-dc92f43a95626daf/out/libffi-root/lib src/prep_cif.lo src/types.lo src/raw_api.lo src/java_raw_api.lo src/closures.lo  src/arm/ffi.lo src/arm/sysv.lo 
  libtool: link: gcc -dynamiclib  -o .libs/libffi.7.dylib  src/.libs/prep_cif.o src/.libs/types.o src/.libs/raw_api.o src/.libs/java_raw_api.o src/.libs/closures.o src/arm/.libs/ffi.o src/arm/.libs/sysv.o    -O3   -install_name  ~/Documents/GitHub/RustPython/target/release/build/libffi-sys-dc92f43a95626daf/out/libffi-root/lib/libffi.7.dylib -compatibility_version 9 -current_version 9.0 -Wl,-single_module

  --- stderr
  autoreconf: export WARNINGS=
  autoreconf: Entering directory '.'
  autoreconf: configure.ac: not using Gettext
  autoreconf: running: aclocal -I m4
  autoreconf: configure.ac: tracing
  autoreconf: running: glibtoolize --copy
  autoreconf: configure.ac: not using Intltool
  autoreconf: configure.ac: not using Gtkdoc
  autoreconf: running: aclocal -I m4
  autoreconf: running: /opt/homebrew/Cellar/autoconf/2.71/bin/autoconf
  configure.ac:8: warning: The macro `AC_CANONICAL_SYSTEM' is obsolete.
  configure.ac:8: You should run autoupdate.
  ./lib/autoconf/general.m4:2081: AC_CANONICAL_SYSTEM is expanded from...
  configure.ac:8: the top level
  configure.ac:41: warning: The macro `AC_PROG_LIBTOOL' is obsolete.
  configure.ac:41: You should run autoupdate.
  m4/libtool.m4:99: AC_PROG_LIBTOOL is expanded from...
  configure.ac:41: the top level
  configure.ac:68: warning: The macro `AC_TRY_COMPILE' is obsolete.
  configure.ac:68: You should run autoupdate.
  ./lib/autoconf/general.m4:2847: AC_TRY_COMPILE is expanded from...
  lib/m4sugar/m4sh.m4:692: _AS_IF_ELSE is expanded from...
  lib/m4sugar/m4sh.m4:699: AS_IF is expanded from...
  ./lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from...
  ./lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from...
  acinclude.m4:3: AC_FUNC_MMAP_BLACKLIST is expanded from...
  configure.ac:68: the top level
  configure.ac:85: warning: The macro `AC_HEADER_STDC' is obsolete.
  configure.ac:85: You should run autoupdate.
  ./lib/autoconf/headers.m4:704: AC_HEADER_STDC is expanded from...
  configure.ac:85: the top level
  configure.ac:112: warning: The macro `AC_TRY_COMPILE' is obsolete.
  configure.ac:112: You should run autoupdate.
  ./lib/autoconf/general.m4:2847: AC_TRY_COMPILE is expanded from...
  lib/m4sugar/m4sh.m4:692: _AS_IF_ELSE is expanded from...
  lib/m4sugar/m4sh.m4:699: AS_IF is expanded from...
  ./lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from...
  ./lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from...
  m4/asmcfi.m4:1: GCC_AS_CFI_PSEUDO_OP is expanded from...
  configure.ac:112: the top level
  configure.ac:116: warning: The macro `AC_TRY_LINK' is obsolete.
  configure.ac:116: You should run autoupdate.
  ./lib/autoconf/general.m4:2920: AC_TRY_LINK is expanded from...
  lib/m4sugar/m4sh.m4:692: _AS_IF_ELSE is expanded from...
  lib/m4sugar/m4sh.m4:699: AS_IF is expanded from...
  ./lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from...
  ./lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from...
  configure.ac:116: the top level
  configure.ac:132: warning: The macro `AC_TRY_COMPILE' is obsolete.
  configure.ac:132: You should run autoupdate.
  ./lib/autoconf/general.m4:2847: AC_TRY_COMPILE is expanded from...
  lib/m4sugar/m4sh.m4:692: _AS_IF_ELSE is expanded from...
  lib/m4sugar/m4sh.m4:699: AS_IF is expanded from...
  ./lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from...
  ./lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from...
  configure.ac:132: the top level
  configure.ac:286: warning: The macro `AC_HELP_STRING' is obsolete.
  configure.ac:286: You should run autoupdate.
  ./lib/autoconf/general.m4:204: AC_HELP_STRING is expanded from...
  configure.ac:286: the top level
  configure.ac:380: warning: The macro `AC_HELP_STRING' is obsolete.
  configure.ac:380: You should run autoupdate.
  ./lib/autoconf/general.m4:204: AC_HELP_STRING is expanded from...
  acinclude.m4:353: LIBFFI_ENABLE_SYMVERS is expanded from...
  configure.ac:380: the top level
  configure.ac:380: warning: The macro `AC_PROG_LD' is obsolete.
  configure.ac:380: You should run autoupdate.
  m4/libtool.m4:3325: AC_PROG_LD is expanded from...
  acinclude.m4:251: LIBFFI_CHECK_LINKER_FEATURES is expanded from...
  acinclude.m4:353: LIBFFI_ENABLE_SYMVERS is expanded from...
  configure.ac:380: the top level
  configure.ac:380: warning: The macro `AC_TRY_RUN' is obsolete.
  configure.ac:380: You should run autoupdate.
  ./lib/autoconf/general.m4:2997: AC_TRY_RUN is expanded from...
  acinclude.m4:251: LIBFFI_CHECK_LINKER_FEATURES is expanded from...
  acinclude.m4:353: LIBFFI_ENABLE_SYMVERS is expanded from...
  configure.ac:380: the top level
  configure.ac:380: warning: The macro `AC_TRY_LINK' is obsolete.
  configure.ac:380: You should run autoupdate.
  ./lib/autoconf/general.m4:2920: AC_TRY_LINK is expanded from...
  acinclude.m4:353: LIBFFI_ENABLE_SYMVERS is expanded from...
  configure.ac:380: the top level
  autoreconf: running: /opt/homebrew/Cellar/autoconf/2.71/bin/autoheader
  autoreconf: running: automake --add-missing --copy --no-force
  configure.ac:31: installing './compile'
  configure.ac:19: installing './install-sh'
  configure.ac:19: installing './missing'
  Makefile.am: installing './depcomp'
  doc/Makefile.am:3: installing 'doc/mdate-sh'
  doc/Makefile.am:3: installing 'doc/texinfo.tex'
  autoreconf: Leaving directory '.'
  clang: error: unsupported option '-print-multi-os-directory'
  clang: error: no input files
  ../src/java_raw_api.c:328:46: warning: 'ffi_java_raw_size' is deprecated [-Wdeprecated-declarations]
    ffi_java_raw *raw = (ffi_java_raw*)alloca (ffi_java_raw_size (cif));
                                               ^
  include/ffi.h:299:56: note: 'ffi_java_raw_size' has been explicitly marked deprecated here
  size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated));
                                                         ^
  ../src/java_raw_api.c:331:3: warning: 'ffi_java_ptrarray_to_raw' is deprecated [-Wdeprecated-declarations]
    ffi_java_ptrarray_to_raw (cif, avalue, raw);
    ^
  include/ffi.h:295:93: note: 'ffi_java_ptrarray_to_raw' has been explicitly marked deprecated here
  void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) __attribute__((deprecated));
                                                                                              ^
  2 warnings generated.
  Undefined symbols for architecture arm64:
    "_ffi_call", referenced from:
        _ffi_raw_call in raw_api.o
        _ffi_java_raw_call in java_raw_api.o
    "_ffi_closure_trampoline_table_page", referenced from:
        _ffi_closure_alloc in closures.o
    "_ffi_prep_cif_machdep", referenced from:
        _ffi_prep_cif_core in prep_cif.o
    "_ffi_prep_cif_machdep_var", referenced from:
        _ffi_prep_cif_core in prep_cif.o
    "_ffi_prep_closure_loc", referenced from:
        _ffi_prep_closure in prep_cif.o
        _ffi_prep_raw_closure_loc in raw_api.o
        _ffi_prep_raw_closure in raw_api.o
        _ffi_prep_java_raw_closure_loc in java_raw_api.o
        _ffi_prep_java_raw_closure in java_raw_api.o
  ld: symbol(s) not found for architecture arm64
  clang: error: linker command failed with exit code 1 (use -v to see invocation)
  make[2]: *** [libffi.la] Error 1
  make[1]: *** [install-recursive] Error 1
  make: *** [install] Error 2
  thread 'main' panicked at 'Building libffi', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-sys-1.1.3/build/common.rs:8:5
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The current version of libffi is v3.4.2, while this crate vendors v3.3. v3.4.2 contains libffi/libffi#565, which adds some support for the M1 processor.

Build failure with clang-16 or later

Attempting to build libffi-rs using clang-16 or later as the C compiler fails with:

  ../src/tramp.c:262:22: error: call to undeclared function 'open_temp_exec_file'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    tramp_globals.fd = open_temp_exec_file ();
                       ^
  1 error generated.

(This is the same problem pointed out here #69 (comment), pulled out into a new issue since it is really unrelated to that pull request.)

The C source code is in fact invalid, C99 and later do not support implicit function declarations. However, most compilers up to now have treated this as simply a warning (and you do indeed see that warning when building libffi-rs with older clang versions or GCC), but as of clang-16, this is now treated as hard error by default. (See https://reviews.llvm.org/D122983 for the upstream discussion.)

That invalid source code was introduced into the libffi sources here libffi/libffi@fc6b939, which made its way into the 3.4.4 release. The bug was subsequently fixed via libffi/libffi#760 and libffi/libffi#764, which landed upstream but is not yet part of any official release.

This is unfortunate as clang-16 starts to become more frequently used, as this will mean the current libffi-rs release will not build out of the box when that compiler is used as default. In particular, this showed up as failure preventing moving rust's miri tool to the latest libffi-rs release (see rust-lang/rust#109771), as some of the rust regression test builders already use clang-16.

I've been investigating options to fix this problem and make libffi-rs buildable again. These all boil down to one of two approaches: fix the actual problem in the C sources, or else downgrade the error back to a warning as it used to be:

  1. Wait until libffi upstream creates the next release which will contain the fix, and pull that release into libffi-rs. This has the drawback that a significant amount of time may pass until an upstream release happens (they typically tend to release once a year or so).
  2. Apply the fix from libffi/libffi#764 to the copy of the libffi sources embedded in libffi-rs. I understand you're hesitant to maintain a set of patches; however, I don't think this is actually necessary. My suggestion would be to simply apply the fix directly to the libffi-rs repo. Once the next upstream libffi release happens, you can still simply fully replace the embedded copy with code from the next release - as this will already contain the fix, there's no need to maintain or track that fix separately in any way. Also, the fix is small and self-contained and has no user-visible impact apart from fixing the build error.
  3. Disable or downgrade the error to a warning. This could be done by adding -Wno-implicit-function-declaration or -Wno-error=implicit-function-declaration to the CFLAGS when building the C portions of libffi, which could be done automatically e.g. by updating the libffi-sys-rs/build/not_msvc.rs script. However, there might be some issue with compilers that do not recognize this flag (GCC and clang do, but I'm not sure if there are any other compilers that could possibly be used to build libffi-rs).
  4. Recommend to users of libffi-rs to add that flag when building libffi-rs, either manually or as part of their automated build processes. This has the obvious drawback of requiring action from all those users

My preference would be option 2, but the decision is of course up to you. I'd be happy to help implement any of those if needed.

PowerPC builds are failing with a core dump

This can be seen in the tests from #23, but it's been around for a while (e.g. I saw it with other PRs/comits).

I don't know anything about PowerPC, nor do I have access to PowerPC hardware. The error provided is also completely useless. Either way, we should either find a way to fix these tests or somehow allow them to fail.

Kernel windows not known to work with OS gnu

I have the same problem in apple M2:

error: failed to run custom build command for `libffi-sys v2.3.0`

Caused by:
  process didn't exit successfully: `/home/ub/target/release/build/libffi-sys-bac7e949b60e9201/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-env-changed=CC_x86_64-pc-windows-gnu
  CC_x86_64-pc-windows-gnu = None
  cargo:rerun-if-env-changed=CC_x86_64_pc_windows_gnu
  CC_x86_64_pc_windows_gnu = None
  cargo:rerun-if-env-changed=TARGET_CC
  TARGET_CC = Some("x86_64-w64-mingw32-gcc")
  cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
  CRATE_CC_NO_DEFAULTS = None
  CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2")
  cargo:rerun-if-env-changed=CFLAGS_x86_64-pc-windows-gnu
  CFLAGS_x86_64-pc-windows-gnu = None
  cargo:rerun-if-env-changed=CFLAGS_x86_64_pc_windows_gnu
  CFLAGS_x86_64_pc_windows_gnu = None
  cargo:rerun-if-env-changed=TARGET_CFLAGS
  TARGET_CFLAGS = None
  cargo:rerun-if-env-changed=CFLAGS
  CFLAGS = None
  checking build system type... aarch64-unknown-linux-gnu
  checking host system type... 
  --- stderr
  Invalid configuration `x86_64-pc-windows-gnu': Kernel `windows' not known to work with OS `gnu'.
  configure: error: /bin/bash ./config.sub x86_64-pc-windows-gnu failed
  thread 'main' panicked at /home/ub/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-2eab394af869c8a2/libffi-sys-2.3.0/build/common.rs:8:5:
  Configuring libffi
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

in config.toml

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-ar"

and in env TARGET_CC=x86_64-w64-mingw32-gcc TARGET_AR=x86_64-w64-mingw32-ar

Uninitialized data read in safe code

Problem

The following code is safe but results in reading uninitialized data twice (which is undefined behavior):

use libffi::high::{Callback0, Cif0, Closure0, CType};
use libffi::low::ffi_cif;

extern "C" fn callback(_cif: &ffi_cif, result: &mut i32, _args: &(), _userdata: &()) {
    println!("Reading uninitialized result: {}", *result);
}

fn main() {
    println!("Hello, world!");
    let c: Callback0<(), i32> = callback;
    let closure = Closure0::from_parts(Cif0::new(i32::reify()), c, &());
    println!("Result = {}", closure.code_ptr().call());
}

First, we read uninitialized data inside the callback, since there is no guarantee result actually refers to a valid i32. Second, we read uninitialized data inside main, since the result of closure.code_ptr.call() is uninitialized.

There are two issues. The first is that Callbackn is defined to take result: &mut R instead of result: &mut MaybeUninit<R> or result: *mut R. The second is that there is no static way of enforcing the requirement that callbacks actually write to result.

Note that all issues raised here also apply to the Mut and Once versions, and to closures/callbacks of all arities (not just 0-ary). The same is true for the solutions.

Potential solutions

A mostly non-breaking solution

All the types which implement CType share a convenient property; they can be safely zero-initialized. Instead of using MaybeUninit::new_uninit() to "initialize" the result and then passing a pointer to the callback, we could instead call MaybeUninit::zeroed().assume_init() to initialize the result before invoking the callback. Since CType is an unsafe trait and there is no documented way to safely implement it, this technically wouldn't be a breaking change. This would probably warrant updating the documentation for CType, but I think it's fairly intuitive that all C types should be zero-initializable.

Costs: the runtime cost of zero-initialization.

Edit: it appears to be impossible to fix this in a non-breaking way from the Rust side, since we don't actually control how the code pointer is used except when we do dynamic calling. Unfortunately, any change would have to be breaking.

A breaking solution

Change the definition of Callbackn so that it takes result: &mut MaybeUninit<R>. Mark from_parts as unsafe.

Costs: breaks all code which relies on the definition of Callbackn or from_parts. Requires use of unsafe to call from_parts (but not to actually write the callbacks - the MaybeUninit API has enough safe functions that this is unnecessary).

How to safely use the middle API when the signature isn't known until runtime.

Hi,

I've recently needed to use the libffi crate to allow an interpreter to make native calls to external functions whose signatures are not known until runtime.

The examples in the repo demonstrate using statically-known signatures (and thus static arrays of arguments). The examples are of limited utility, because if you knew the signatures you wanted to call ahead of time, you'd just call an extern-declared symbol directly without libffi. As far as I know, libffi is intended for scenarios where the type signatures are dynamic.

Once you start dealing with calls with dynamic types, it becomes unclear how to best safely use the crate. For example, my first attempt looked a bit like:

use libffi::middle::*;
use std::ffi::c_void;

// Pretend that this function is from an external dynamic C library.
fn f(a: u64, b: u64, c:u64) {
    println!("a={}, b={}, c={}", a, b, c);
}

fn call_ext(addr: *mut c_void, num_args: usize) {
    let mut args = Vec::new();
    let mut builder = Builder::new();
    for i in 0..num_args {
        args.push(arg(&i)); // Bad!
        builder = builder.arg(Type::u64());
    }
    builder = builder.res(Type::void());
    let cif = builder.into_cif();
    unsafe {cif.call::<()>(CodePtr(addr), &args)};
}

fn main() {
    call_ext(&f as *const _ as *mut c_void, 3);
}

This program is UB because arg() calls Arg::new(), which looks like:

    pub fn new<T>(r: &T) -> Self {
        Arg(r as *const T as *mut c_void)
    }

So it stashes a raw pointer to its argument, but in the case of my example above:

  • The same memory is re-used for &i on each iteration of the loop, so we'd unintentionally be doing the call with 3 identical arguments.
  • The storage for the i dies once the loop finishes, so the Arg stores a dangling pointer. Using the resulting pointers invokes UB.

(Another gotcha here, is that we've inadvertently made a vector of usize args, since we didn't add explicit type annotations. But that's another story)

My next attempt was to do something like:

use libffi::middle::*;
use std::ffi::c_void;

// Pretend that this function is from an external dynamic C library.
fn f(a: u64, b: u64, c:u64) {
    println!("a={}, b={}, c={}", a, b, c);
}

fn call_ext(addr: *mut c_void, num_args: usize) {
    let mut builder = Builder::new();
    let mut args: Vec<u64> = Vec::new(); // <-----------------
    for i in 0..num_args {
        args.push(u64::try_from(i).unwrap());
        builder = builder.arg(Type::u64());
    }
    let cif = builder.into_cif();
    let ffi_args = args.iter().map(|a| arg(a)).collect::<Vec<Arg>>(); // <-----------------
    unsafe {cif.call::<()>(CodePtr(addr), &ffi_args)};
}

fn main() {
    call_ext(&f as *const _ as *mut c_void, 3);
    println!("Hello, world!");
}

This solves the above problems by:

  • ensuring that the storage for each argument is a distinct memory address
  • ensuring that the storage out-lives the ffi call.

But I'm still not certain that this is correct. The example assumes that the backing storage of the vector holding the arguments is not moved: a guarantee I don't think we have(?).

My next attempt would be to take a slice from the argument vector. By taking a slice, Rust cannot move the vector's backing storage (if it wanted to, the program would (hopefully?) not compile). But having shown this to colleagues, they have concerns about pointer aliasing rules.

So my question is: what is the correct and safe way to use libffi::middle to create dynamically-typed calls to external functions?

The only solution I can see is to manually manage an unmovable chunk of memory with malloc() (or using a something like the alloc crate). There has to be a better way.

(FWIW, all of the programs I've shown so far seg-fault, although when I used the approach from the latter example in my interpreter, it did work, but perhaps by chance).

(Side question: You can't use libffi::high to do dynamic calls, can you? You'd need to ability to dynamically create a Rust type signature as far as i can see, and if you could do that, you wouldn't need libffi)

Thanks!

libffi-rs with msvc win11x64, mingw, and wsl ubuntu

I have a system that includes msys2 and wsl. I was having trouble and still am having trouble in wsl linux. My focus was on a msvc build and I found a work around.

I was attempting to get this project to build.
svix/svix-webhooks#1128

fatal error C1083: Cannot open include file: 'fficonfig.h': No such file or **directory**

The windows build was erroring with a missing header file. The ubuntu build is failing without any real detail and I'm not sure how to debug or resolve that.

I was able to get the windows build working using the following before doing a cargo build:

set INCLUDE=%INCLUDE%;libffi\include;libffi-sys-2.3.0\libffi\src\x86\

I hope this helps someone else if they encounter the windows build issue. I'd really like to help resolve the issue without a work around. Please have a look at the associated ticket and let me know if there is anything I can test or help with further.

thanks.

Unnecessary build dependency on autotools

Because libffi is included as a git submodule, autotools are unnecessarily required to build. This is not the intended release strategy for autoconf - the configure script is meant to be generated as part of the release.

Would you accept a PR to include the libffi source code (not as a git submodule) plus the generated configure script to reduce the build dependencies?

The crates.io version of libffi-rs no longer builds

You get these errors:
...
Compiling bindgen v0.22.0
Compiling libffi-sys v0.4.7
Compiling libffi v0.4.0
error[E0432]: unresolved import raw::FFI_DEFAULT_ABI
--> /home/joris/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-0.4.0/src/low.rs:118:24
|
118 | pub use raw::{ffi_abi, FFI_DEFAULT_ABI, _ffi_type as ffi_type, ffi_status,
| ^^^^^^^^^^^^^^^ no FFI_DEFAULT_ABI in raw

error[E0432]: unresolved import middle::FFI_DEFAULT_ABI
--> /home/joris/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-0.4.0/src/high/mod.rs:71:26
|
71 | pub use middle::{FfiAbi, FFI_DEFAULT_ABI};
| ^^^^^^^^^^^^^^^ no FFI_DEFAULT_ABI in middle

error: aborting due to 2 previous errors

error: Could not compile libffi.

You need to publish a version on crates.io with this commit included:

d4b6edf

Adding support for mips and mips64

Hi everyone,

Currently, there is no support for mips and mips64 architecture. If I build libffi with the command -

cargo build --target mips64el-unknown-linux-gnuabi64

the compilation throws the following error -

error[E0425]: cannot find value `FFI_TRAMPOLINE_SIZE` in this scope
   --> libffi-sys-rs/src/lib.rs:165:25
    |
165 |     pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
    |                         ^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
note: these constants exist but are inaccessible

This seems to be sorted with the following changes in arch.rs file as follows:

#[cfg(all(target_arch = "mips64", unix))]
pub use x86::x86_64::*;

#[cfg(all(target_arch = "mips", unix))]
pub use x86::x86::*;

Are these appropriate changes to make and apt for the problem mentioned?

Building with MSVC toolchain under Windows

I encounter some strange behavior under Windows while using clang that is bundled with Visual studio; the solution to the original issue was reported here. With Visual Studio 2022, official LLVM 15.0.7 and rust 1.69, I've managed to compile a project using libffi-rs and libffi-sys-rs. After updating the rust toolchain to 1.70, I get the error:

libffi/src/x86/win64_intel.S(2): fatal error C1083: Cannot open include file: 'fficonfig.h': No such file or directory

After trying various LLVM combos (none of them worked), I reverted to LLVM 15.0.7 and Rust 1.69, but it still fails with the same message with missing fficonfig.h.

Has anyone had this kind of issue under Windows?

libffi 0.7.0 on docs.rs failed to build

Hi, I'm not sure if this is an issue with libffi-rs/libffi-sys-rs or with docs.rs, but the current page for libffi-rs 0.7.0 on docs.rs says it failed to build. You can see the build output here, although the interesting bits in the output have \n escaped, so I attempted to fix the output:

make[2]: Entering directory \'/home/cratesfyi/cratesfyi/debug/build/libffi-sys-7b10269bbdd70d1a/out/libffi-build/x86_64-unknown-linux-gnu\'
restore=: && backupdir=\".am$$\" && \\
am__cwd=`pwd` && CDPATH=\"${ZSH_VERSION+.}:\" && cd .. && \\
rm -rf $backupdir && mkdir $backupdir && \\
if (/bin/bash /home/cratesfyi/cratesfyi/debug/build/libffi-sys-7b10269bbdd70d1a/out/libffi-build/missing makeinfo  --version) >/dev/null 2>&1; then \\
  for f in ../doc/libffi.info ../doc/libffi.info-[0-9] ../doc/libffi.info-[0-9][0-9] ../doc/libffi.i[0-9] ../doc/libffi.i[0-9][0-9]; do \\
    if test -f $f; then mv $f $backupdir; restore=mv; else :; fi; \\
  done; \\
else :; fi && \\
cd \"$am__cwd\"; \\
if /bin/bash /home/cratesfyi/cratesfyi/debug/build/libffi-sys-7b10269bbdd70d1a/out/libffi-build/missing makeinfo    -I doc -I ../doc \\
 -o ../doc/libffi.info ../doc/libffi.texi; \\
then \\
  rc=0; \\
  CDPATH=\"${ZSH_VERSION+.}:\" && cd ..; \\
else \\
  rc=$?; \\
  CDPATH=\"${ZSH_VERSION+.}:\" && cd .. && \\
  $restore $backupdir/* `echo \"./../doc/libffi.info\" | sed \'s|[^/]*$||\'`; \\
fi; \\
rm -rf $backupdir; exit $rc
Makefile:1419: recipe for target \'../doc/libffi.info\' failed
make[2]: Leaving directory \'/home/cratesfyi/cratesfyi/debug/build/libffi-sys-7b10269bbdd70d1a/out/libffi-build/x86_64-unknown-linux-gnu\'
Makefile:1604: recipe for target \'install-recursive\' failed
make[1]: Leaving directory \'/home/cratesfyi/cratesfyi/debug/build/libffi-sys-7b10269bbdd70d1a/out/libffi-build/x86_64-unknown-linux-gnu\'
Makefile:3153: recipe for target \'install\' failed
--- stderr
autoreconf: Entering directory `.\'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: running: libtoolize --copy --force
autoreconf: running: /usr/bin/autoconf --force
autoreconf: running: /usr/bin/autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:31: installing \'./compile\'
configure.ac:8: installing \'./config.guess\'
configure.ac:8: installing \'./config.sub\'
configure.ac:19: installing \'./install-sh\'
configure.ac:19: installing \'./missing\'
Makefile.am: installing \'./depcomp\'
Makefile.am:56: installing \'./mdate-sh\'
autoreconf: Leaving directory `.\'
/home/cratesfyi/cratesfyi/debug/build/libffi-sys-7b10269bbdd70d1a/out/libffi-build/missing: line 81: makeinfo: command not found
WARNING: \'makeinfo\' is missing on your system.
         You should only need it if you modified a \'.texi\' file, or
         any other file indirectly affecting the aspect of the manual.
         You might want to install the Texinfo package:
         <http://www.gnu.org/software/texinfo/>
         The spurious makeinfo call might also be the consequence of
         using a buggy \'make\' (AIX, DU, IRIX), in which case you might
         want to install GNU make:
         <http://www.gnu.org/software/make/>
make[2]: *** [../doc/libffi.info] Error 127
make[1]: *** [install-recursive] Error 1
make: *** [install] Error 2
thread \'main\' panicked at \'Building libffi\', /home/cratesfyi/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-sys-0.7.0/build.rs:41:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

Unfortunately I don't have much experience with building C projects/libffi, or using make/texinfo, so I can't help figure out what's going on here. The docs for libffi-rs 0.6.4 appear to have compiled correctly, and the changelog entry for 0.7.0 doesn't mention any big API changes, so in the mean time people can just use the docs from 0.6.4.

middle::Cif needs a variadic variation for its new function

While transitioning from the low api to the middle api, I found that there is no new_variadic function for Cif, which is a must for me. I can't create a pull request, so I'm pasting the function I created for myself here in hope that some variation of this function will be merged :)

    /// Creates a new variadic [CIF](Cif) for the given argument and result
    /// types.
    ///
    /// Takes ownership of the argument and result [`Type`]s, because
    /// the resulting [`Cif`] retains references to them. Defaults to
    /// the platform’s default calling convention; this can be adjusted
    /// using [`Cif::set_abi`].
    pub fn new_variadic<I>(args: I, fixed_args: usize, result: Type) -> Self
    where
        I: IntoIterator<Item = Type>,
        I::IntoIter: ExactSizeIterator<Item = Type>,
    {
        let args = args.into_iter();
        let nargs = args.len();
        let args = types::TypeArray::new(args);
        let mut cif: low::ffi_cif = Default::default();

        unsafe {
            low::prep_cif_var(
                &mut cif,
                low::ffi_abi_FFI_DEFAULT_ABI,
                fixed_args,
                nargs,
                result.as_raw_ptr(),
                args.as_raw_ptr(),
            )
        }
        .expect("low::prep_cif_var");

        // Note that cif retains references to args and result,
        // which is why we hold onto them here.
        Cif { cif, args, result }
    }

Structure argument data gets corrupted on cloning `libffi::middle::Cif`

Steps to reproduce

  1. Create a libffi::middle::Cif::new() with one of the parameters containing a structure type argument.
  2. Place the resulting cif into a struct that derives Clone.
  3. Create a clone of the struct.
  4. Using cloned_struct.cif.as_raw_ptr() observe the structure type argument's libffi::low::ffi_type data.

Expected result

The cif in the copied struct should contain expected size, alignment and elements for .

Actual result

The cif in the copy has zero's as its size and alignment.

Issue with nested structs

The code below triggers reading freed memory:

use libffi::middle::Type;

fn main() {
    let inner_struct = Type::structure(vec!(Type::c_int()));

    println!("Inner struct: {:?}", inner_struct);

    let outer = Type::structure(vec!(inner_struct, Type::c_int()));

    let mut offsets = Vec::new();
    offsets.resize_with(2, Default::default);
    
    unsafe {
        libffi::raw::ffi_get_struct_offsets(
            libffi::low::ffi_abi_FFI_DEFAULT_ABI,
            outer.as_raw_ptr(),
            offsets.as_mut_ptr())
    };
    println!("Offsets: {:?}", offsets);
}

The output is:

Offsets: [0, 94089412172272]

When running the program through valgrind --tool=memcheck I get the output:

Inner struct: Type(0x4a6ab00)

==4739== Invalid read of size 8
==4739==    at 0x118215: ffi_get_struct_offsets (in /home/jesho/tmp/fffi/target/debug/fffi)
==4739==    by 0x110B6E: fffi::main (src/main.rs:16)
[...]
==4739==  Address 0x4a6ab00 is 0 bytes inside a block of size 24 free'd
==4739==    at 0x48399AB: free (vg_replace_malloc.c:538)
==4739==    by 0x114371: libffi::middle::types::ffi_type_destroy (libffi-rs/libffi-rs/src/middle/types.rs:169)
==4739==    by 0x114980: <libffi::middle::types::Type as core::ops::drop::Drop>::drop (libffi-rs/libffi-rs/src/middle/types.rs:175)
==4739==    by 0x11465E: core::ptr::drop_in_place<libffi::middle::types::Type> (mod.rs:179)
==4739==    by 0x113FAC: libffi::middle::types::ffi_type_array_create (libffi-rs/libffi-rs/src/middle/types.rs:106)
==4739==    by 0x1113D1: libffi::middle::types::ffi_type_struct_create (types.rs:130)
==4739==    by 0x111437: libffi::middle::types::Type::structure (types.rs:408)
==4739==    by 0x110AF6: fffi::main (src/main.rs:10)

inner_struct is dropped in libffi::middle::types::ffi_type_array_create can be accessed through outer.

If I change the loop in ffi_type_array_create to:

    for (i, element) in elements.enumerate() {
        *new.add(i) = *element.0;
        std::mem::forget(element); // Forget element
    }

I get the correct output ("Offsets: [0, 4]"). Not sure if this introduces leaks, but Valgrind doesn't complain.

libffi-rs does not accommodate return type promotion

The libffi implementation has a special historical quirk about promoting return types. This is documented here:
http://www.chiark.greenend.org.uk/doc/libffi-dev/html/The-Basics.html

In most situations, ‘libffi’ will handle promotion according to the ABI. However, for historical reasons, there is a special case with return values that must be handled by your code. In particular, for integral (not struct) types that are narrower than the system register size, the return value will be widened by ‘libffi’. ‘libffi’ provides a type, ffi_arg, that can be used as the return type. For example, if the CIF was defined with a return type of char, ‘libffi’ will try to store a full ffi_arg into the return value.

The current libffi-rs code base does not appear to accommodate that behavior at all anywhere. For example:

pub unsafe fn call<R>(cif: *mut ffi_cif, fun: CodePtr, args: *mut *mut c_void) -> R {
    let mut result = mem::MaybeUninit::<R>::uninit();
    raw::ffi_call(
        cif,
        Some(*fun.as_safe_fun()),
        result.as_mut_ptr() as *mut c_void,
        args,
    );
    result.assume_init()
}

When called with a small integer type for R, like i8 or i16, this will allocate only a small buffer as result and pass its address to the C implementation - but that implementation will actually write a full ffi_arg into it.

Now, on little-endian platforms, this mostly works transparently - but it is strictly speaking clobbering some memory on the Rust caller's stack. (Which probably has no practical effect due to stack slot alignment rules - but who knows what might happen if this is inlined into a more complicated caller in a LTO compilation ...)

However, on a big-endian platform, the return value will simply always be wrong. This is the problem I'm currently seeing as I'm working on enabling libffi-rs for the s390x architecture.

Note that in addition to ffi_call, the same promotion rule also applies with closures - when a closure callback writes to its return value pointer, it is likewise expected to write a full ffi_arg if the return type is a small integer.

I'd be happy to work on a fix, but it seems challenging to fix this across all the low/med/high layers without changing the external API, specifically for the closures. Any suggestions would be appreciated!

Note on installing

Just a quick note for ubuntu 14.04. I had to install texinfo to get cargo to compile libffi-sys. I didn't see that in the .travis.yaml so I was a little confused how you got it working.

Unable to build in windows with WSL

I'm trying to build deno in WSL which depends on this create. I'm running into the following error when configuring libffi:

Caused by:
  process didn't exit successfully: `/home/marvinh/dev/deno/target/debug/build/libffi-sys-31e669a8307ea709/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-env-changed=CC_x86_64-unknown-linux-gnu
  CC_x86_64-unknown-linux-gnu = None
  cargo:rerun-if-env-changed=CC_x86_64_unknown_linux_gnu
  CC_x86_64_unknown_linux_gnu = None
  cargo:rerun-if-env-changed=HOST_CC
  HOST_CC = None
  cargo:rerun-if-env-changed=CC
  CC = None
  cargo:rerun-if-env-changed=CFLAGS_x86_64-unknown-linux-gnu
  CFLAGS_x86_64-unknown-linux-gnu = None
  cargo:rerun-if-env-changed=CFLAGS_x86_64_unknown_linux_gnu
  CFLAGS_x86_64_unknown_linux_gnu = None
  cargo:rerun-if-env-changed=HOST_CFLAGS
  HOST_CFLAGS = None
  cargo:rerun-if-env-changed=CFLAGS
  CFLAGS = None
  cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
  CRATE_CC_NO_DEFAULTS = None
  CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2")
  checking build system type... x86_64-pc-linux-gnu
  checking host system type... x86_64-pc-linux-gnu
  checking target system type... x86_64-pc-linux-gnu
  continue configure in default builddir "./x86_64-unknown-linux-gnu"
  ....exec /bin/bash .././configure "--srcdir=.." "--enable-builddir=x86_64-unknown-linux-gnu" "linux
  gnu"
  checking build system type... x86_64-pc-linux-gnu
  checking host system type... x86_64-pc-linux-gnu
  checking target system type... x86_64-pc-linux-gnu
  checking for gsed... sed
  checking for a BSD-compatible install... /usr/bin/install -c
  checking whether build environment is sane... yes
  checking for a race-free mkdir -p... /usr/bin/mkdir -p
  checking for gawk... gawk
  checking whether make sets $(MAKE)... no
  checking whether make supports nested variables... no
  checking for gcc... cc
  checking whether the C compiler works... yes
  checking for C compiler default output file name... a.out
  checking for suffix of executables...
  checking whether we are cross compiling... no
  checking for suffix of object files... o
  checking whether the compiler supports GNU C... yes
  checking whether cc accepts -g... yes
  checking for cc option to enable C11 features... none needed
  checking whether cc understands -c and -o together... yes
  checking whether make supports the include directive... no
  checking dependency style of cc... none
  checking for g++... no
  checking for c++... c++
  checking whether the compiler supports GNU C++... yes
  checking whether c++ accepts -g... yes
  checking for c++ option to enable C++11 features... none needed
  checking dependency style of c++... none
  checking dependency style of cc... none
  checking for grep that handles long lines and -e... /usr/bin/grep
  checking for egrep... /usr/bin/grep -E
  checking how to print strings... printf
  checking for a sed that does not truncate output... /usr/bin/sed
  checking for fgrep... /usr/bin/grep -F
  checking for ld used by cc... /usr/bin/ld
  checking if the linker (/usr/bin/ld) is GNU ld... yes
  checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
  checking the name lister (/usr/bin/nm -B) interface... BSD nm
  checking whether ln -s works... yes
  checking the maximum length of command line arguments... 1572864
  checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
  checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
  checking for /usr/bin/ld option to reload object files... -r
  checking for file... file
  checking for objdump... objdump
  checking how to recognize dependent libraries... pass_all
  checking for dlltool... no
  checking how to associate runtime and link libraries... printf %s\n
  checking for ar... ar
  checking for archiver @FILE support... @
  checking for strip... strip
  checking for ranlib... ranlib
  checking command to parse /usr/bin/nm -B output from cc object... ok
  checking for sysroot... no
  checking for a working dd... /usr/bin/dd
  checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
  checking for mt... mt
  checking if mt is a manifest tool... no
  checking for stdio.h... yes
  checking for stdlib.h... yes
  checking for string.h... yes
  checking for inttypes.h... yes
  checking for stdint.h... yes
  checking for strings.h... yes
  checking for sys/stat.h... yes
  checking for sys/types.h... yes
  checking for unistd.h... yes
  checking for dlfcn.h... yes
  checking for objdir... .libs
  checking if cc supports -fno-rtti -fno-exceptions... no
  checking for cc option to produce PIC... -fPIC -DPIC
  checking if cc PIC flag -fPIC -DPIC works... yes
  checking if cc static flag -static works... yes
  checking if cc supports -c -o file.o... yes
  checking if cc supports -c -o file.o... (cached) yes
  checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
  checking dynamic linker characteristics... GNU/Linux ld.so
  checking how to hardcode library paths into programs... immediate
  checking whether stripping libraries is possible... yes
  checking if libtool supports shared libraries... yes
  checking whether to build shared libraries... no
  checking whether to build static libraries... yes
  checking how to run the C++ preprocessor... c++ -E
  checking for ld used by c++... /usr/bin/ld -m elf_x86_64
  checking if the linker (/usr/bin/ld -m elf_x86_64) is GNU ld... yes
  checking whether the c++ linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
  checking for c++ option to produce PIC... -fPIC -DPIC
  checking if c++ PIC flag -fPIC -DPIC works... yes
  checking if c++ static flag -static works... yes
  checking if c++ supports -c -o file.o... yes
  checking if c++ supports -c -o file.o... (cached) yes
  checking whether the c++ linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
  checking dynamic linker characteristics... (cached) GNU/Linux ld.so
  checking how to hardcode library paths into programs... immediate
  checking for readelf... readelf
  checking size of size_t... 8
  checking for C compiler vendor... gnu
  checking CFLAGS for most reasonable warnings... -Wall
  checking whether to enable maintainer-specific portions of Makefiles... no
  checking for sys/memfd.h... no
  checking for memfd_create... yes
  checking for sys/mman.h... yes
  checking for mmap... yes
  checking for mkostemp... yes
  checking for mkstemp... yes
  checking for sys/mman.h... (cached) yes
  checking for mmap... (cached) yes
  checking whether read-only mmap of a plain file works... yes
  checking whether mmap from /dev/zero works... yes
  checking for MAP_ANON(YMOUS)... yes
  checking whether mmap with MAP_ANON(YMOUS) works... yes
  checking for egrep... (cached) /usr/bin/grep -E
  checking for memcpy... yes
  checking for size_t... yes
  checking for working alloca.h... yes
  checking for alloca... yes
  checking size of double... 8
  checking size of long double... 16
  checking whether byte ordering is bigendian... no
  checking assembler .cfi pseudo-op support... yes
  checking assembler supports pc related relocs... yes
  checking whether compiler supports pointer authentication... no
  checking for _ prefix in compiled symbols... no
  checking toolchain supports unwind section type... yes
  checking whether C compiler accepts -fno-lto... yes
  checking whether .eh_frame section should be read-only... yes
  checking for __attribute__((visibility("hidden")))... yes
  configure: versioning on shared library symbols is no
  checking that generated files are newer than configure... done
  configure: creating ./config.status
  config.status: creating include/Makefile
  config.status: creating include/ffi.h
  config.status: creating Makefile
  config.status: creating testsuite/Makefile
  config.status: creating man/Makefile
  config.status: creating doc/Makefile
  config.status: creating libffi.pc
  config.status: creating fficonfig.h
  config.status: executing buildir commands
  config.status: create top_srcdir/Makefile guessed from local Makefile
  config.status: build in x86_64-unknown-linux-gnu (HOST=x86_64-unknown-linux-gnu)
  config.status: executing depfiles commands

  --- stderr
  config.status: error: in `/home/marvinh/dev/deno/target/debug/build/libffi-sys-89a8cf0f07f9140e/out/libffi-build/x86_64-unknown-linux-gnu':
  config.status: error: Something went wrong bootstrapping makefile fragments
      for automatic dependency tracking.  If GNU make was not used, consider
      re-running the configure script with MAKE="gmake" (or whatever is
      necessary).  You can also try re-running configure with the
      '--disable-dependency-tracking' option to at least be able to build
      the package (albeit without support for automatic dependency tracking).
  See `config.log' for more details
  thread 'main' panicked at 'Configuring libffi', /home/marvinh/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-sys-2.3.0/build/common.rs:8:5
  stack backtrace:
     0: rust_begin_unwind
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/std/src/panicking.rs:575:5
     1: core::panicking::panic_fmt
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:64:14
     2: core::panicking::panic_display
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:147:5
     3: build_script_build::common::run_command
               at ./build/common.rs:8:5
     4: build_script_build::not_msvc::configure_libffi
               at ./build/not_msvc.rs:123:5
     5: build_script_build::not_msvc::build_and_link
               at ./build/not_msvc.rs:26:5
     6: build_script_build::main
               at ./build/build.rs:16:9
     7: core::ops::function::FnOnce::call_once
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/ops/function.rs:250:5
  note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

I'm not entirely sure if this is the appropriate repo to report the error. Happy to transfer this issue to another one if this one isn't correct.

libffi-sys-rs fails to build on OpenBSD amd64

I'm trying to build libffi-sys on OpenBSD current amd64, but get error:

$ RUST_BACKTRACE=full AUTOCONF_VERSION=2.69 AUTOMAKE_VERSION=1.16 cargo build
   Compiling libffi-sys v1.1.2 (/home/bukhalo/tmp/libffi-rs/libffi-sys-rs)
error: failed to run custom build command for `libffi-sys v1.1.2 (/home/bukhalo/tmp/libffi-rs/libffi-sys-rs)`

Caused by:
  process didn't exit successfully: `/home/bukhalo/tmp/libffi-rs/target/debug/build/libffi-sys-66b9400313667f38/build-script-build` (exit status: 101)
  --- stdout
  checking build system type... x86_64-unknown-openbsd7.0
  checking host system type... x86_64-unknown-openbsd7.0
  checking target system type... x86_64-unknown-openbsd7.0
  continue configure in default builddir "./x86_64-unknown-openbsd"
  ....exec /bin/sh ../configure "--srcdir=.." "--enable-builddir=x86_64-unknown-openbsd" "openbsd7.0"
  checking build system type... x86_64-unknown-openbsd7.0
  checking host system type... x86_64-unknown-openbsd7.0
  checking target system type... x86_64-unknown-openbsd7.0
  checking for gsed... sed
  checking for a BSD-compatible install... /usr/bin/install -c
  checking whether build environment is sane... yes
  checking for a thread-safe mkdir -p... ../install-sh -c -d
  checking for gawk... no
  checking for mawk... no
  checking for nawk... no
  checking for awk... awk
  checking whether make sets $(MAKE)... yes
  checking whether make supports nested variables... yes
  checking for gcc... gcc
  checking whether the C compiler works... yes
  checking for C compiler default output file name... a.out
  checking for suffix of executables... 
  checking whether we are cross compiling... no
  checking for suffix of object files... o
  checking whether we are using the GNU C compiler... yes
  checking whether gcc accepts -g... yes
  checking for gcc option to accept ISO C89... none needed
  checking whether gcc understands -c and -o together... yes
  checking whether make supports the include directive... yes (GNU style)
  checking dependency style of gcc... gcc3
  checking for g++... g++
  checking whether we are using the GNU C++ compiler... yes
  checking whether g++ accepts -g... yes
  checking dependency style of g++... gcc3
  checking dependency style of gcc... gcc3
  checking how to print strings... print -r
  checking for a sed that does not truncate output... /usr/bin/sed
  checking for grep that handles long lines and -e... /usr/bin/grep
  checking for egrep... /usr/bin/grep -E
  checking for fgrep... /usr/bin/grep -F
  checking for ld used by gcc... /usr/bin/ld
  checking if the linker (/usr/bin/ld) is GNU ld... yes
  checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
  checking the name lister (/usr/bin/nm -B) interface... BSD nm
  checking whether ln -s works... yes
  checking the maximum length of command line arguments... 393216
  checking whether the shell understands some XSI constructs... yes
  checking whether the shell understands "+="... no
  checking how to convert x86_64-unknown-openbsd7.0 file names to x86_64-unknown-openbsd7.0 format... func_convert_file_noop
  checking how to convert x86_64-unknown-openbsd7.0 file names to toolchain format... func_convert_file_noop
  checking for /usr/bin/ld option to reload object files... -r
  checking for objdump... objdump
  checking how to recognize dependent libraries... match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$
  checking for dlltool... no
  checking how to associate runtime and link libraries... print -r --
  checking for ar... ar
  checking for archiver @FILE support... @
  checking for strip... strip
  checking for ranlib... ranlib
  checking command to parse /usr/bin/nm -B output from gcc object... ok
  checking for sysroot... no
  checking for mt... mt
  checking if mt is a manifest tool... no
  checking how to run the C preprocessor... gcc -E
  checking for ANSI C header files... yes
  checking for sys/types.h... yes
  checking for sys/stat.h... yes
  checking for stdlib.h... yes
  checking for string.h... yes
  checking for memory.h... yes
  checking for strings.h... yes
  checking for inttypes.h... yes
  checking for stdint.h... yes
  checking for unistd.h... yes
  checking for dlfcn.h... yes
  checking for objdir... .libs
  checking if gcc supports -fno-rtti -fno-exceptions... no
  checking for gcc option to produce PIC... -fPIC -DPIC
  checking if gcc PIC flag -fPIC -DPIC works... yes
  checking if gcc static flag -static works... yes
  checking if gcc supports -c -o file.o... yes
  checking if gcc supports -c -o file.o... (cached) yes
  checking whether the gcc linker (/usr/bin/ld) supports shared libraries... yes
  checking whether -lc should be explicitly linked in... yes
  checking dynamic linker characteristics... openbsd7.0 ld.so
  checking how to hardcode library paths into programs... immediate
  checking whether stripping libraries is possible... yes
  checking if libtool supports shared libraries... yes
  checking whether to build shared libraries... yes
  checking whether to build static libraries... yes
  checking how to run the C++ preprocessor... g++ -E
  checking for ld used by g++... /usr/bin/ld
  checking if the linker (/usr/bin/ld) is GNU ld... yes
  checking whether the g++ linker (/usr/bin/ld) supports shared libraries... yes
  checking for g++ option to produce PIC... -fPIC -DPIC
  checking if g++ PIC flag -fPIC -DPIC works... yes
  checking if g++ static flag -static works... yes
  checking if g++ supports -c -o file.o... yes
  checking if g++ supports -c -o file.o... (cached) yes
  checking whether the g++ linker (/usr/bin/ld) supports shared libraries... yes
  checking dynamic linker characteristics... openbsd7.0 ld.so
  checking how to hardcode library paths into programs... immediate
  checking size of size_t... 8
  checking for C compiler vendor... gnu
  checking whether C compiler accepts -fstrict-aliasing... yes
  checking whether C compiler accepts -ffast-math... yes
  checking for gcc architecture flag... 
  checking for x86 cpuid 0 output... d:68747541:444d4163:69746e65
  checking for x86 cpuid 1 output... 810f81:2040800:7ed8320b:178bfbff
  checking whether C compiler accepts -march=amdfam10... yes
  checking for gcc architecture flag... -march=amdfam10
  checking whether C compiler accepts -O3 -fomit-frame-pointer -fstrict-aliasing -ffast-math -march=amdfam10... yes
  checking CFLAGS for maximum warnings... -Wall
  checking whether to enable maintainer-specific portions of Makefiles... no
  checking sys/mman.h usability... yes
  checking sys/mman.h presence... yes
  checking for sys/mman.h... yes
  checking for mmap... yes
  checking for mkostemp... yes
  checking for sys/mman.h... (cached) yes
  checking for mmap... (cached) yes
  checking whether read-only mmap of a plain file works... yes
  checking whether mmap from /dev/zero works... yes
  checking for MAP_ANON(YMOUS)... yes
  checking whether mmap with MAP_ANON(YMOUS) works... yes
  checking for ANSI C header files... (cached) yes
  checking for memcpy... yes
  checking for size_t... yes
  checking for working alloca.h... no
  checking for alloca... yes
  checking size of double... 8
  checking size of long double... 16
  checking whether byte ordering is bigendian... no
  checking assembler .cfi pseudo-op support... yes
  checking assembler supports pc related relocs... yes
  checking for _ prefix in compiled symbols... no
  checking toolchain supports unwind section type... yes
  checking whether .eh_frame section should be read-only... yes
  checking for __attribute__((visibility("hidden")))... yes
  checking for ld used by gcc... (cached) /usr/bin/ld
  checking if the linker (/usr/bin/ld) is GNU ld... (cached) no
  configure: versioning on shared library symbols is no
  checking that generated files are newer than configure... done
  configure: creating ./config.status
  config.status: creating include/Makefile
  config.status: creating include/ffi.h
  config.status: creating Makefile
  config.status: creating testsuite/Makefile
  config.status: creating man/Makefile
  config.status: creating doc/Makefile
  config.status: creating libffi.pc
  config.status: creating fficonfig.h
  config.status: executing buildir commands
  config.status: create top_srcdir/Makefile guessed from local Makefile
  config.status: build in x86_64-unknown-openbsd (HOST=x86_64-unknown-openbsd)
  config.status: executing depfiles commands
  config.status: executing libtool commands
  config.status: executing include commands
  config.status: executing src commands

  --- stderr
  autoreconf-2.69: Entering directory `.'
  autoreconf-2.69: configure.ac: not using Gettext
  autoreconf-2.69: running: aclocal -I m4
  autoreconf-2.69: configure.ac: tracing
  autoreconf-2.69: running: libtoolize --copy
  autoreconf-2.69: running: /usr/local/bin/autoconf-2.69
  autoreconf-2.69: running: /usr/local/bin/autoheader-2.69
  autoreconf-2.69: running: automake --add-missing --copy --no-force
  autoreconf-2.69: Leaving directory `.'
  thread 'main' panicked at 'Building libffi: Os { code: 2, kind: NotFound, message: "No such file or directory" }', libffi-sys-rs/build/common.rs:8:26
  stack backtrace:
     0:      0xe5d678546bd - <unknown>
     1:      0xe5d6787d53c - <unknown>
     2:      0xe5d67841ef3 - <unknown>
     3:      0xe5d6784f23b - <unknown>
     4:      0xe5d6784edc8 - <unknown>
     5:      0xe5d6784f926 - <unknown>
     6:      0xe5d67854bdc - <unknown>
     7:      0xe5d67854820 - <unknown>
     8:      0xe5d6784f3f6 - <unknown>
     9:      0xe5d6787f550 - <unknown>
    10:      0xe5d6787c176 - <unknown>
    11:      0xe5d6783c305 - <unknown>
    12:      0xe5d6783a1f5 - <unknown>
    13:      0xe5d6783cf4f - <unknown>
    14:      0xe5d67840a99 - <unknown>
    15:      0xe5d6783e75e - <unknown>
    16:      0xe5d67840b81 - <unknown>
    17:      0xe5d67840534 - <unknown>
    18:      0xe5d67866366 - <unknown>
    19:      0xe5d67840512 - <unknown>
    20:      0xe5d67840acb - <unknown>
    21:      0xe5d67839198 - <unknown>

Unfortunately, I don't write in Rust, so I can't fix the error. Maybe someone can help me?

If there is a need, I can help with debugging on my computer

`.code_ptr()` method unsound

The code_ptr method on the ClosureN structs in the high interface is unsound, as fn(...) -> R pointers are Copy, so you can copy the returned function pointer out from behind the reference with the appropriate lifetime and "safely" call them after the backing closure has been dropped.

LibFFI fails to build

I get the following error when trying to build libffi:

   Compiling libffi-sys v0.5.4
   Compiling libffi v0.6.1
error[E0432]: unresolved import `raw::ffi_status`
  --> /home/guillaume/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-0.6.1/src/low.rs:29:14
   |
29 |     use raw::ffi_status::*;
   |              ^^^^^^^^^^ Not a module `ffi_status`

error[E0599]: no associated item named `STRUCT` found for type `u32` in the current scope
   --> /home/guillaume/.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-0.6.1/src/low.rs:190:35
    |
190 |     pub const STRUCT:  c_ushort = raw::ffi_type_enum::STRUCT as c_ushort;
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

error: Could not compile `libffi`.
warning: build failed, waiting for other jobs to finish...

Any idea where this could come from?

I am on Linux Centos 7, with the latest stable rustc.

libffi-rs fails to build

Ubuntu 17.10

$ rustc --version
rustc 1.25.0-nightly (f62f77403 2018-01-10)
--- stderr
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: running: libtoolize --copy --force
autoreconf: running: /usr/bin/autoconf --force
autoreconf: running: /usr/bin/autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:31: installing './compile'
configure.ac:8: installing './config.guess'
configure.ac:8: installing './config.sub'
configure.ac:19: installing './install-sh'
configure.ac:19: installing './missing'
Makefile.am: installing './depcomp'
Makefile.am:56: installing './mdate-sh'
autoreconf: Leaving directory `.'
../src/closures.c: In function ‘dlmmap_locked’:
../src/closures.c:488:7: warning: ignoring return value of ‘ftruncate’, declared with attribute warn_unused_result [-Wunused-result]
       ftruncate (execfd, offset);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~
../src/closures.c:500:7: warning: ignoring return value of ‘ftruncate’, declared with attribute warn_unused_result [-Wunused-result]
       ftruncate (execfd, offset);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~
ar: `u' modifier ignored since `D' is the default (see `U')
ar: `u' modifier ignored since `D' is the default (see `U')
/home/ehiggs/src/home/ripawk/target/release/build/libffi-sys-075697e5eb3875eb/out/libffi-root/lib/libffi-3.2.1/include/ffi.h:75:10: fatal error: 'stddef.h' file not found
/home/ehiggs/src/home/ripawk/target/release/build/libffi-sys-075697e5eb3875eb/out/libffi-root/lib/libffi-3.2.1/include/ffi.h:75:10: fatal error: 'stddef.h' file not found, err: true
thread 'main' panicked at '
        **********
        Bindgen generation failed. Please file a bug report.
        **********
        : ()', libcore/result.rs:916:5

If I make the following test file, I can build it using gcc ((Ubuntu 7.2.0-8ubuntu3) 7.2.0):

$ cat test.c
#include <stddef.h>
int main () {}
$ gcc test.c
$

I have libffi-dev installed so it would be nice if pkg-config and just used that version:

$ pkg-config --libs --cflags libffi
-lffi

Support libffi error status FFI_BAD_ARGTYPE

Currently we recognize only FFI_BAD_ABI and FFI_BAD_TYPEDEF, which we translate to Error::Typedef and Error::Abi. As of now, FFI_BAD_ARGTYPE gets translated to Error::Abi (which maybe isn’t strictly incorrect?). But it would be better to add a third enumerator, Error::Argtype for representing FFI_BAD_ARGTYPE. This isn’t difficult, but it will require a major version bump.

libffi-rs fails to build on amazon linux

I'm trying to build an application that uses libffi-rs to use in a aws lambda function. I've spent quite some time on this the last two weeks and I just can't get it to work. Works fine on ubuntu and manjaro when I've tried on those.

The output I get is here

I've tried to distill this as much as I can and have made a repo a with a simple rust project and a Dockerfile, just run ./build.sh && ./run.sh and it will build the image and then run cargo run within the container.

I you would find the time to take a look I would be very grateful.

Also thanks for your work on this lib

`libffi-sys` fails to build on `riscv64gc-unknown-linux-gnu`

Rust uses riscv64gc-unknown-linux-gnu while ./configure uses riscv64-unknown-linux-gnu. One solution is the patch below. Is there a better way to handle this?

diff --git a/libffi-sys-rs/build/not_msvc.rs b/libffi-sys-rs/build/not_msvc.rs
index e41e076..634b710 100644
--- a/libffi-sys-rs/build/not_msvc.rs
+++ b/libffi-sys-rs/build/not_msvc.rs
@@ -53,7 +53,11 @@ pub fn configure_libffi(prefix: PathBuf, build_dir: &Path) {
 
     let target = std::env::var("TARGET").unwrap();
     if target != std::env::var("HOST").unwrap() {
-        command.arg(format!("--host={}", target.to_string()));
+        if target == "riscv64gc-unknown-linux-gnu" {
+            command.arg("--host=riscv64-unknown-linux-gnu");
+        } else {
+            command.arg(format!("--host={}", target));
+        }
     }
 
     command.current_dir(&build_dir);

Support for creating closures that take bindgen generated types

I'm trying to pass a rust closure to a C library as a callback using the high interface and the code_ptr function. The callback is passed a C struct as the only argument. I'm running into issues using the high API as the rust type that bindgen generates that maps to this argument doesn't implement the required CType trait.

This struct is declared repr(C) so I imagine this all should be possible, but I'm not sure if I'm missing something or if this is something that would have to be added to libffi-rs. Maybe I'm misunderstanding things here and this just isn't possible.

I have tried digging into the libffi-rs code to try to implement this trait but all the required functionality doesn't seem to be exported.

Get function pointer from high-level `FnPtrX`

The soundness fixes of #27 are great, but now I don't see an obvious means of passing the FnPtrX struct across a C API as an extern "C" fn pointer directly as before. The func member is private so what would the correct means of getting that pointer be?

`high` interface soundness

These are the soundness issues I'm aware of in the high interface:

  • It erases all auto trait information attached to closure captures (read: Send and Sync)
  • It erases mutability required to call closures (read: ClosureMutN can be called by shared reference)

There may be more that I'm not aware of, though the pattern seems to be that the high interface erases too much information to be able to effectively lean on the compiler checking things for us.

I'd like to work on fixing these, though I'm having trouble forming a solid idea of how to fix the auto trait problem.

Support alternative ABIs/calling conventions (specifically "stdcall")

A small issue with this crate is that it doesn't support any calling conventions other than the system's default ABI, even though libffi supports many different calling conventions. Unfortunately, I have a Windows API that uses the "stdcall" calling convention. This is more-or-less OK because most of my users are on x86-64 where "stdcall" is equivalent to "C" on x86-64, but it is different on 32-bit x86.

Supporting 32-bit Windows isn't that important to me, so this isn't a big priority, but I'd like to at least register that it's a small issue.

Kernel `windows` not known to work with OS `gnu`

On M1 Mac, running rust with target x86_64-pc-windows-gnu

process didn't exit successfully: `target/release/build/libffi-sys-7f2a7ab9ea025606/build-script-build` (exit status: 101)
--- stdout
checking build system type... aarch64-apple-darwin21.6.0
checking host system type... 
--- stderr
Invalid configuration `x86_64-pc-windows-gnu': Kernel `windows' not known to work with OS `gnu'.
configure: error: /bin/sh ./config.sub x86_64-pc-windows-gnu failed
thread 'main' panicked at 'Configuring libffi', /.cargo/registry/src/github.com-1ecc6299db9ec823/libffi-sys-2.0.1/build/common.rs:8:5

Backtrace

  stack backtrace:
    0: rust_begin_unwind
              at /rustc/95a3a7277b44bbd2dd3485703d9a05f64652b60e/library/std/src/panicking.rs:575:5
    1: core::panicking::panic_fmt
              at /rustc/95a3a7277b44bbd2dd3485703d9a05f64652b60e/library/core/src/panicking.rs:65:14
    2: core::panicking::panic_display
    3: build_script_build::common::run_command
    4: build_script_build::not_msvc::configure_libffi
    5: build_script_build::not_msvc::build_and_link
    6: build_script_build::main
    7: core::ops::function::FnOnce::call_once

Support function pointer type

Upstream issue: denoland/deno#15292.
Downstream issue: libffi/libffi#725.

It seems that libffi-rs doesn't provide a function pointer type, but after further investigation, it seems that this is because the C libffi does not support this, so I have opened an issue there too; feel free to subscribe to the downstream issue.

Nonetheless, in the meanwhile, it does seem that libffi-rs misuses *const c_void as fn(), which can still be fixed here.

See https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html and https://c-faq.com/ptrs/generic.html.

Rust claims that Rust's extern "ABI" fn(...) -> R has the same size/alignment/etc. as C's void (*)(), and that it may not necessarily map to C's void *.

Furthermore, Rust's fn documentation requests that code use fn primitives for FFI.

As a result, some present usage here is unsound (on some platforms), such as https://docs.rs/libffi/latest/libffi/low/struct.CodePtr.html.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.