Code Monkey home page Code Monkey logo

libfringe's Introduction

crates travis rustdoc irccloud

libfringe

libfringe is a library implementing safe, lightweight context switches, without relying on kernel services. It can be used in hosted environments (using std) as well as on bare metal (using core).

It provides the following safe abstractions:

  • an implementation of generators, Generator.

It also provides the necessary low-level building blocks:

  • a trait that can be implemented by stack allocators, Stack;
  • a wrapper for using slice references as stacks, SliceStack;
  • a stack allocator based on Box<[u8]>, OwnedStack;
  • a stack allocator based on anonymous memory mappings with guard pages, OsStack.

libfringe emphasizes safety and correctness, and goes to great lengths to never violate the platform ABI.

Usage example

extern crate fringe;

use fringe::{OsStack, Generator};

fn main() {
  let stack = OsStack::new(1 << 16).unwrap();
  let mut gen = Generator::new(stack, move |yielder, ()| {
    for i in 1..4 { yielder.suspend(i) }
  });

  println!("{:?}", gen.resume(())); // Some(1)
  println!("{:?}", gen.resume(())); // Some(2)
  println!("{:?}", gen.resume(())); // Some(3)
  println!("{:?}", gen.resume(())); // None
}

Performance

libfringe does context switches in 3ns flat on x86 and x86_64!

test swap ... bench:         6 ns/iter (+/- 0)

Debuggability

Uniquely among libraries implementing context switching, libfringe ensures that the call stack does not abruptly end at the boundary of a generator. Let's consider this buggy code:

extern crate fringe;

use fringe::{OsStack, Generator};

fn main() {
  let stack = OsStack::new(1 << 16).unwrap();
  let mut gen = Generator::new(stack, move |yielder, mut index| {
    let values = [1, 2, 3];
    loop { index = yielder.suspend(values[index]) }
  });

  println!("{:?}", gen.resume(5));
}

It crashes with the following backtrace:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 5', /checkout/src/libcore/slice.rs:658
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: <usize as core::slice::SliceIndex<T>>::index
             at /checkout/src/libcore/slice.rs:658
   1: core::slice::<impl core::ops::Index<I> for [T]>::index
             at /checkout/src/libcore/slice.rs:560
   2: crash_test::main::{{closure}}
             at ./src/main.rs:9
   3: <fringe::generator::Generator<'a, Input, Output, Stack>>::unsafe_new::generator_wrapper
             at /home/edef/src/github.com/edef1c/libfringe/src/generator.rs:137
   4: fringe::arch::imp::init::trampoline_2
             at /home/edef/src/github.com/edef1c/libfringe/src/arch/x86_64.rs:116
   5: fringe::arch::imp::init::trampoline_1
             at /home/edef/src/github.com/edef1c/libfringe/src/arch/x86_64.rs:61
   6: <fringe::generator::Generator<'a, Input, Output, Stack>>::resume
             at /home/edef/src/github.com/edef1c/libfringe/src/arch/x86_64.rs:184
             at /home/edef/src/github.com/edef1c/libfringe/src/generator.rs:171
   7: crash_test::main
             at ./src/main.rs:12

Similarly, debuggers, profilers, and all other tools using the DWARF debug information have full insight into the call stacks.

Note that the stack should be deep enough for the panic machinery to store its state—at any point there should be at least 8 KiB of free stack space, or panicking will result in a segfault.

Limitations

The architectures currently supported are: x86, x86_64, aarch64, or1k.

The platforms currently supported are: bare metal, Linux (any libc), FreeBSD, DragonFly BSD, macOS. Windows is not supported (see explanation below).

Installation

libfringe is a Cargo package. Add this to your Cargo.toml:

[dependencies.fringe]
version = "1.2.1"

To use libfringe on a bare-metal target, add the no-default-features key:

[dependencies.fringe]
version = "1.2.1"
no-default-features = true

Feature flags

libfringe provides some optional features through Cargo's feature flags. Currently, all of them are enabled by default.

alloc

This flag enables dependency on the alloc crate, which is required for the OwnedStack.

valgrind

This flag enables Valgrind integration. libfringe will register context stacks with Valgrind.

Internals

libfringe uses two key implementation techniques.

Compiler-assisted register spilling

Traditionally, libraries implementing context switches in userspace have to spill all callee-saved registers. On the other hand, libfringe fully inlines calls to every function that eventually results in a context switch, and uses an inline assembly statement marking every register as clobbered to implement the context switching itself.

As a result, only minimal work needs to be performed in the context switching code (LLVM does not support spilling the frame pointer), which is especially important on architectures with lots of callee-saved registers.

Call stack splicing

Non-Windows platforms use DWARF for both stack unwinding and debugging. DWARF call frame information is very generic to be ABI-agnostic—it defines a bytecode that describes the actions that need to be performed to simulate returning from a function. libfringe uses this bytecode to specify that, after the generator function has returned, execution continues at the point where the generator function was resumed the last time.

Windows compatibility

As was said, libfringe emphasizes following the platform ABI. On Windows, the platform ABI does not allow moving the stack pointer from the range designated by the OS during thread creation. Therefore, the technique used by libfringe on *nix platforms is not applicable, and libfringe does not provide Windows support.

You might ask, "but what about mioco?" The mioco library uses the context library to implement context switches, which is little more than a wrapper of boost::context. The boost::context library changes undocumented fields in the TIB during every context switch to try and work around the restrictions placed by the Windows platform ABI. This has failed before and it is bound to fail again, breaking existing code that uses boost::context in unexpected and complicated ways. The authors of libfringe consider this unacceptable.

The only supported way to implement user-mode context switching on Windows is fibers. There are no reasons the safe abstractions provided by libfringe could not be implemented on top of that; it is simply not yet done. This should be straightforward and an implementation is welcome. Note that while UMS threads are capable of providing user-mode context switching, they involve managing scheduler threads to run UMS threads on, which is incompatible with libfringe's design.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

libfringe's People

Contributors

amanieu avatar edef1c avatar emberian avatar ericson2314 avatar gz avatar jcsoo avatar markswanson avatar retep998 avatar steveklabnik avatar whitequark 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  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

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

libfringe's Issues

osx support?

I tried building libfringe on OSX 10.10.5 using

rustc 1.13.0-nightly (eac41469d 2016-08-30)
cargo 0.13.0-nightly (3e41b6b 2016-08-29)
Darwin basho.local 14.5.0 Darwin Kernel Version 14.5.0: Thu Jun 16 19:58:21 PDT 2016; root:xnu-2782.50.4~1/RELEASE_X86_64 x86_64

libc::MAP_STACK

(x.env) basho:libfringe basho$ cargo test
   Compiling fringe v1.0.2 (file:///Users/basho/w/days/rust-fringe/libfringe)
error[E0425]: unresolved name `libc::MAP_STACK`
  --> src/os/sys.rs:21:28
   |
21 | const STACK_FLAGS: c_int = libc::MAP_STACK
   |                            ^^^^^^^^^^^^^^^

then I modified src/os/sys.rs to include macos in the same set as FreeBSD and Dragonfly. Then I got

(x.env) basho:libfringe basho$ cargo test
   Compiling fringe v1.0.2 (file:///Users/basho/w/days/rust-fringe/libfringe)
error: <inline asm>:8:7: error: unknown directive
      .local __morestack
      ^

  --> src/arch/x86_64.rs:54:5
   |
54 |     asm!(
   |     ^

Release a new version

There have been several changes over time since the last release. Please publish the new changes to crates.io if everything is green on the current master.

Crash when run test on linux

Below is the output

$ cargo test --release
   Compiling fringe v1.2.1 (file:///home/ubuntu/Project/rust/libfringe)
    Finished release [optimized] target(s) in 5.91 secs
     Running target/release/deps/fringe-cfa403e779d7269b

running 5 tests
test arch::tests::context ... ok
test arch::tests::context_simd ... ok
test arch::tests::swap ... ok
error: process didn't exit successfully: `/home/ubuntu/Project/rust/libfringe/target/release/deps/fringe-cfa403e779d7269b` (signal: 4, SIGILL: illegal instruction)
cargo test --release  7.44s user 3.98s system 179% cpu 6.352 total

$ rustc --version
rustc 1.25.0-nightly (a0dcecff9 2018-01-24)

seems that could not hanle panic properly.

Crash with the example from the readme

When running the example from the readme or anything else that uses libfringe like tokio-fibers i'm getting a segmenetation fault. Here's the stacktrace

#0  0x000055555555e5a1 in fringe::arch::imp::init::trampoline_2 ()
    at /home/arturo/.cargo/registry/src/github.com-1ecc6299db9ec823/fringe-1.2.1/src/arch/x86_64.rs:115
#1  0x00007fffffffd420 in ?? ()
#2  0x000055555555e592 in fringe::arch::imp::init::trampoline_1 ()
    at /home/arturo/.cargo/registry/src/github.com-1ecc6299db9ec823/fringe-1.2.1/src/arch/x86_64.rs:60
#3  0x000055555555c420 in ?? () at /checkout/src/libcore/option.rs:157
#4  0x0000000000000000 in ?? ()

nightly changes

fyi...

warning: use of deprecated item 'stack::owned_stack::alloc::allocator::Heap': type renamed to `Global`
  --> src/stack/owned_stack.rs:22:23
   |
22 |             let ptr = Heap.alloc(Layout::from_size_align_unchecked(aligned_size, ::STACK_ALIGNMENT)).unwrap();
   |                       ^^^^

error[E0308]: mismatched types
  --> src/stack/owned_stack.rs:23:64
   |
23 |             OwnedStack(Box::from_raw(slice::from_raw_parts_mut(ptr, aligned_size)))
   |                                                                ^^^ expected *-ptr, found struct `core::ptr::NonNull`
   |
   = note: expected type `*mut _`
              found type `core::ptr::NonNull<core::alloc::Opaque>`

...

Allow stack providers to fail

Currently, the signature of StackSource::get_stack doesn't allow for returning failure, forcing stack providers to panic if stack allocation fails.
An associated Error type should be added, and get_stack should return Result<Self::Output, Self::Error>.

project abandoned?

This project is quite interesting and perhaps the best implementation of user mode context switch for rust. It seems that development has stalled. If it is, can the README be updated? If not is there some avenue for discussing future direction of this crate?

swap ... bench: 29 ns/iter (not 6?)

$ cargo bench
...
swap ... bench: 29 ns/iter (+/- 0)

I'm curious what CPU was used (and perhaps Rust version?).
I'm using Rust 1.13 nightly
machine: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz

Any ideas why I'm 5x slower?

Thanks!

Yielded values are dropped by the generator

repro

extern crate fringe;
use fringe::Generator;

struct Dropper;

impl Drop for Dropper {
  fn drop(&mut self) {
    println!("drop!")
  }
}

fn main() {
  let stack = fringe::OsStack::new(1<<16).unwrap();
  let mut generator = Generator::new(stack, |yielder, ()| {
    yielder.suspend(Dropper);
  });
  generator.resume(());
  generator.resume(());
}

expected output

drop!

actual output

drop!
drop!

Keep docs in sync

The website and the crates.io package docs are out of sync. Please enable multiversion support (similar to docs.rs) for docs so that it is easy to use the project.

Name of `top` function is misleading

Quote from the docs:

*fn top(&self) -> mut u8
Returns the top of the stack. On all modern architectures, the stack grows downwards, so this is the highest address.

If the stack grows downwards, then the top of the stack is at the lowest address. Presumably this function actually gets the base of the stack.

Relicense under dual MIT/Apache-2.0

The project maintainer explicitly asked for this issue to be opened.

TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.

Why?

The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.

Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it
.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.

How?

To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:

## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):

// Copyright 2016 libfringe Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.

Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these
from the Rust repo for a plain-text
version.

And don't forget to update the license metadata in your Cargo.toml to:

license = "MIT OR Apache-2.0"

I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!

Contributor checkoff

To agree to relicensing, comment with :

I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.

improve Valgrind integration, and figure out where it fits in

Currently, os::Stack uses the native functions provided by platform.c to register the allocated stacks with Valgrind. We don't currently expose these functions.

Having them as extern "C" functions instead of inline assembly in Rust is also suboptimal, but might save us some implementation complexity. Performing a Valgrind call while running natively only takes about 2ns.

Stacks should always be registered with Valgrind, even if a custom StackSource is being used — the cost is minimal, and this should work fine even in freestanding environments.

I'm not sure if this responsibility should lie with the Stack, or with the Context. Technically, it isn't stack memory until the context is invoked, and it only ceases to be stack memory when the context finishes execution. However, the Context's main function is intended to never return (this causes an intentional abort when the trampoline function returns), so the point for stack deregistration is unclear in this case.

Stack alignment

Some platforms have requirements regarding stack alignment on function entry (16 bytes for x86, x86_64 and aarch64, 8 bytes for arm). Should it be the Stack's responsibility to ensure alignment or should the context initialization perform a suitable alignment (by aligning the address returned by Stack::base)?

Windows Fiber Support

I threw together this gist using Windows Fibers to make something akin to libfringe.

The big difference is there isn't any way (as far as I can tell) for the user to provide their own pre-allocated stack. This is makes Fibers somewhat incompatible with libfringe's design.

I can see a couple ways around this:

  1. Have OsStack on Windows correspond to a pre-allocated fiber which can be passed different FnOnces as trait objects. This would introduce extra runtime cost (dynamic dispatch and possibly boxing) and wouldn't work for SliceStacks. It's also misleading, since OsStack wouldn't really be a "stack" in the traditional sense-- just a pointer to a fiber.
  2. Just use OsStack on Windows as a way to store the desired stack size (i.e. OsStack would just be the stack config, not the real stack itself). This would allow the API to match across systems, but would be misleading to users. It also wouldn't work for SliceStacks.
  3. Provide slightly different APIs on different systems and force users to cfg their code. This is kind of lame, but possibly justified given the inherent difference in design between the systems.
  4. Create a higher-level API that doesn't expose stacks in the same direct way, making it compatible with both designs. This would probably require some performance tradeoffs.

Thoughts?

Loosen the lifetime bound on Context::new

Currently, Context::new takes an F: FnOnce() + Send + 'static. This disallows a lot of interesting use-cases. Internally, Registers::new only requires F: FnOnce().
— issue #2

The 'static bound is more problematic, because it disallows many useful forms of fork-join concurrency. At the level of this library, we don't have the level of control required to guarantee memory safety anyway, and it might be worth giving up on this entirely, leaving it to the actual threading runtime.

Context design

Currently, Context::swap means either "swap into the context associated with Context.stack" or "swap into the original context". The correspondence between Context and Stack is unclear.
While not necessarily intuitive, this model is clearly useful: a scheduler running in a native context can swap into contexts to run tasks, and the tasks can kick back to the scheduler.

However, this forbids models where tasks switch directly to each other, like regular coroutines.

File not found or module 'imp'

Compiling fringe v1.0.5 (https://github.com/nathan7/libfringe.git#1df75900) /home/kamal/.cargo/git/checkouts/libfringe-2dc7659ef57cab6f/master/src/arch/mod.rs:15:5: 15:8 error: file not found for module imp/home/kamal/.cargo/git/checkouts/libfringe-2dc7659ef57cab6f/master/src/arch/mod.rs:15 mod imp; ^~~ /home/kamal/.cargo/git/checkouts/libfringe-2dc7659ef57cab6f/master/src/arch/mod.rs:15:5: 15:8 help: name the file either imp.rs or imp/mod.rs inside the directory "/home/kamal/.cargo/git/checkouts/libfringe-2dc7659ef57cab6f/master/src/arch" error: aborting due to previous error error: Could not compilefringe.

I've tried fixing it myself, but some modules from the arch-specific files are for some reason not being imported, and I don't really know what to do further

Stack should be an unsafe trait

The Stack trait allows returning arbitrary raw pointers which can be used to write to arbitrary addresses using only safe code.

support more architectures

We currently only support x86_64, because this library grew out of an experiment for my kernel, which also only targets x86_64.
We'd like to support a few more:

  • x86
  • ARM
  • AArch64
  • MIPS

Unsoudness?

I was testing certain scenario, and I think I've discovered an unsafety:

extern crate fringe;                                                                                                    
                                                                                                                        
use fringe::{OsStack, Generator};                                                                                       
                                                                                                                        
fn main() {                                                                                                             
    let stack = OsStack::new(1 << 16).unwrap();                                                                         
    let mut gen = Generator::new(stack, move |yielder, ()| {                                                            
                                                                                                                        
        {                                                                                                               
            let mut x = 3u32;                                                                                           
            yielder.suspend(&mut x)                                                                                     
        }                                                                                                               
                                                                                                                        
        {                                                                                                               
            let mut y = 3u32;                                                                                           
            for _ in 1..4 { yielder.suspend(&mut y) }                                                                   
        }                                                                                                               
    });                                                                                                                 
                                                                                                                        
    let x = gen.resume(());                                                                                             
    println!("{:?}", gen.resume(()));                                             
    println!("{:?}", gen.resume(()));                                         
    *x.unwrap() = 6;                                                                                                    
    println!("{:?}", gen.resume(()));                                                          
    println!("{:?}", gen.resume(()));                                                                           
}

As you can see, I can modify x long after it is no longer in scope. Depending on release/debug I'm getting different results.

investigate loosening the function bounds

Currently, Context::new takes an F: FnOnce() + Send + 'static. This disallows a lot of interesting use-cases. Internally, Registers::new only requires F: FnOnce().

It's not clear how Send should relate to custom threading runtimes, and this was mostly chosen as a safe bet. We might have to make decisions on how low-level this library should be exactly.
#6 covers the 'static bound.

Releasing owned resources on Generator drop

I notice that there's no Drop implementation for Generator, and so it looks like it's owned stack won't get unwound, and so any resources owned by a Generator's stack will get leaked.

So, it seems that that the only way currently to forcefully unwind a generator's stack is to pass in a value that asks it to panic, such as in this example. Is that right?

I notice that context-rs has the ability to spawn a function on top of a recovered stack, which might be an option for future implementation. But that seems quite risky.

automated verification of clobbers

I'd like to have some form of automated verification that we're not unintentionally modifying processor state that we're not declaring as clobbered.
Preferably, we would automatically generate a list of processor state from a third-party source (such as Capstone) and use this to generate our clobber lists.

Additionally, we could pattern-match the stack-swap code in real programs, and use this to statically check for state being carried across contexts.

fPIC troubles? relocation R_X86_64_PC32 against symbol

Edit: a quicker/easier way to test is to paste this into libfringe/cargo.toml:

[lib]
name = "libfringe"
path = "src/lib.rs"
crate-type = ["dylib"]

Hello,

I'm unable to use libfringe with my DSO. Small test case pasted below.

  = note: /usr/bin/ld: /home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o: relocation R_X86_64_PC32 against symbol `_ZN6fringe4arch3imp4swap10trampoline17h9a2ce236cc1b16f6E' can not be used when making a shared object; recompile with -fPIC

I maintain that my little test is compiled as PIC. Evidence: libfringefpic.0.o (pic) and also:

$ file libfringefpic.0.o 
/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o: ELF 64-bit LSB  relocatable, x86-64, version 1 (SYSV), not stripped

I'm quite fascinated with libfringe. I hope it's possible to use with DSOs.

Any suggestions / help would be appreciated!

  • Cargo.toml
[package]
name = "libfringefpic"
version = "1.0.0"
authors = ["Mark Swanson [email protected]"]

[dependencies.fringe]
no-default-features = true
git = "https://github.com/nathan7/libfringe.git"

[lib]
name = "libfringefpic"
path = "src/lib.rs"
crate-type = ["dylib"]
  • .cargo/config
[build]
# rustflags = ["-C", "prefer-dynamic", "-Z", "incremental=/tmp/rustc_incremental", "-Z", "incremental-info"]

rustflags = ["-C", "prefer-dynamic", "-C", "link-args=-fPIC"]
# rustflags = ["-C", "relocation-model=pic", "-C", "link-args=-fPIC"]
# :-)
  • src/lib.rs
extern crate fringe;

use fringe::{OsStack, Generator};

pub fn x() {
  let stack = OsStack::new(1 << 16).unwrap();
  let mut gen = Generator::new(stack, move |yielder, mut index| {
    let values = [1, 2, 3];
    loop { index = yielder.suspend(values[index]) }
  });

  println!("{:?}", gen.resume(5));
}

Running rustc src/lib.rs --crate-name libfringefpic --crate-type dylib -g -C metadata=63492654b52cf958 --out-dir /home/maswanso/src/external/rust/libfringefpic/target/debug/deps --emit=dep-info,link -L dependency=/home/maswanso/src/external/rust/libfringefpic/target/debug/deps --extern fringe=/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringe-88227e5bfb249863.rlib -C prefer-dynamic -C link-args=-fPIC


error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/maswanso/.multirust/toolchains/nightly-2016-09-09-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o" "-o" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/liblibfringefpic.so" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.metadata.o" "-nodefaultlibs" "-L" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps" "-L" "/home/maswanso/.multirust/toolchains/nightly-2016-09-09-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "-Wl,--whole-archive" "/tmp/rustc.5dtQdVsxlbYQ/libfringe-88227e5bfb249863.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.5dtQdVsxlbYQ/libvalgrind_request-c9df0ba26d15ec95.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.5dtQdVsxlbYQ/liblibc-ad32fde1bd850538.rlib" "-Wl,--no-whole-archive" "-L" "/home/maswanso/.multirust/toolchains/nightly-2016-09-09-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-l" "std-411f48d3" "-l" "util" "-l" "dl" "-l" "pthread" "-l" "gcc_s" "-l" "pthread" "-l" "c" "-l" "m" "-l" "rt" "-l" "util" "-shared" "-fPIC" "-l" "compiler-rt"
  = note: /usr/bin/ld: /home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o: relocation R_X86_64_PC32 against symbol `_ZN6fringe4arch3imp4swap10trampoline17h9a2ce236cc1b16f6E' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value

Crash when non-move closure passed to Generator::new

Using a move closure inside a struct::fn which borrows a struct field results in corrupted memory when that closure is not move.

Example:

extern crate fringe;
use std::iter::Iterator;
use fringe::generator::Yielder;
use fringe::{OsStack, Generator};

struct Gpx {
    creator: String,
}

type Generator_<T> = fringe::Generator<(), T, fringe::OsStack>;

impl Gpx {
    pub fn events<'a>(&'a self) -> Generator_<&'a str> {
        let stack = OsStack::new(1 << 24).unwrap();
        Generator::new(stack, |ctx, ()| { // broken
        // Generator::new(stack, move |ctx, ()| { // working
            ctx.suspend(self.creator.as_str());
        })
    }
}

fn main() {
    let data = Gpx{ creator: String::from("xyz") };
    println!("{:?}", data.events().next());
}

Unfortunately, I don't know if it's a problem with type checking or the unsafe portion. Given some pointers, I will try to debug it myself.

unions may not contain fields that need dropping

master fails to compile on latest rustc (rustc 1.40.0-nightly (b520af6fd 2019-11-03)):

error[E0740]: unions may not contain fields that need dropping
  --> src/generator.rs:95:3
   |
95 |   inner: T
   |   ^^^^^^^^
   |

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.