I just started to learn Rust and would like to know whether it is possible to call WinAPI functions without unsafe?
extern crate libc;
fn main() {
unsafe {
libc::funcs::extra::kernel32::GetCurrentProcessId();
}
}
No, it is impossible, because they are direct bindings to functions in external C libraries, just like almost everything else in libc crate. It may be not obvious with functions like GetCurrentProcessId(), but these functions are unsafe because there is a lot of them which take and return raw pointers and null-terminated strings.
In order to call them without unsafe there should be an appropriate safe wrapper, just like for any other C library. There is no such wrapper yet, as far as I know. But you can write one just for the subset of WinAPI functions you need, it shouldn't be too hard. You can find more details on how to write safe wrappers for external libraries here and here.
Related
I'm new to learning rust and I saw that rust uses generic lifetimes to validate references at compile time which is very nice. I didn't dig much around building a dll or shared library in rust but from what I saw a function can be exported from dll (like in c++). But if I want to export a function that takes a reference as a parameter or returns a reference other than static references, how will this work ? the dll and the app are not in the same project so the compiler can't check lifetimes in this case so this is simply not possible like exporting templated functions in c++ is not possible without instantiation but I don't know how instantiate a generic lifetime function in rust.
Why ask this question ? rust is aimed to be a system programming language and shared libraries are mandatory in any system so how a system built in rust will provide its api in pure rust without going through c ?
In c++ this is possible like in c :
struct some_type_c
{
int i;
float f;
void* p;
};
// vary between windows and unix likes
#define EXPORT some_platform_export
EXPORT void use_some_type_c(some_type_c* s) { ++s->i; }
struct some_type_cpp
{
int i;
float f;
void* p;
// may be implemented in a cpp file
EXPORT void use() { ++i; }
};
Since rust has no stable ABI, exported functions need to go through the C ABI and deal with raw pointers along the way.
When going through C, it's common practice to create more ergonomic functions that wrap the underlying unsafe FFI (foreign function interface) calls and have the right lifetime annotations in order to represent the relationship between different references.
Crates that dynamically load system libraries are often composed of two crates, one with a -sys suffix, containing the FFI bindings, and the more ergonomic version (e.g. openssl depends on openssl-sys, containing generated C-compatible types, using bindgen).
When exporting functions, the references lifetimes are lost when converting them to raw pointers.
However it's worth noting that all rust crates are statically linked at compile time, and lifetime checks are enforced across crate boundaries.
How do I declare an external MFC function that has LPCTSTR tokens?
I have the following C function in a library I wish to use:
DLL_PUBLIC void output( LPCTSTR format, ... )
Where DLL_PUBLIC is resolved to
__declspec(dllimport) void output( LPCTSTR format, ...)
In Rust, I was able to get things to build with:
use winapi::um::winnt::CHAR;
type LPCTSTR = *const CHAR;
#[link(name="mylib", kind="static")]
extern {
#[link_name = "output"]
fn output( format:LPCTSTR, ...);
}
I'm not sure this is the best approach, but it seems to get me part way down. Although the module is declared in a DLL module, the symbol decorations in the native DLL are such that it does not have _imp prepended to it in the binary. So I find that "static" seems to look for the correct module, although I still have not been able to get it to link.
The dumpbin output for the module (this target function) in "mylib.dll" is:
31 ?output##YAXPEBDZZ (void __cdecl output(char const *,...))
This is assuming that what you are trying to accomplish here is to link Rust code against a custom DLL implementation. If that is the case, then things are looking good.
First things first, though, you'll need to do some sanity cleanup. LPCTSTR is not a type. It is a preprocessor symbol that either expands to LPCSTR (aka char const*) or LPCWSTR (aka wchar_t const*).
When the library gets built the compiler commits to either one of those, and that decision is made for all eternity. Clients, on the other hand, that #inlcude the header are still free to choose, and you have no control over this. Lucky you, if you're using C++ linkage, and have the linker save you. But we aren't using C++ linkage.
The first order of action is to change the C function signature using an explicit type, so that clients and implementation always agree. I will be using char const* here.
C++ library
Building the library is fairly straight forward. The following is a bare-bones C++ library implementation that simply outputs a formatted string to STDOUT.
dll.cpp:
#include <stdio.h>
#include <stdarg.h>
extern "C" __declspec(dllexport) void output(char const* format, ...)
{
va_list argptr{};
va_start(argptr, format);
vprintf(format, argptr);
va_end(argptr);
}
The following changes to the original code are required:
extern "C": This is requesting C linkage, controlling how symbols are decorated as seen by the linker. It's the only reasonable choice when planning to cross language boundaries.
__declspec(dllexport): This is telling the compiler to inform the linker to export the symbol. C and C++ clients will use a declaration with a corresponding __declspec(dllimport) directive.
char const*: See above.
This is all that's required to build the library. With MSVC the target architecture is implied by the toolchain used. Open up a Visual Studio command prompt that matches the architecture eventually used by Rust's toolchain, and run the following command:
cl.exe /LD dll.cpp
This produces, among other artifacts, dll.dll and dll.lib. The latter being the import library that needs to be discoverable by Rust. Copying it to the Rust client's crate's root directory is sufficient.
Consuming the library from Rust
Let's start from scratch here and make a new binary crate:
cargo new --bin client
Since we don't need any other dependencies, the default Cargo.toml can remain unchanged. As a sanity check you can cargo run to verify that everything is properly set up.
If that all went down well it's time to import the only public symbol exported by dll.dll. Add the following to src/main.rs:
#[link(name = "dll", kind = "dylib")]
extern "C" {
pub fn output(format: *const u8, ...);
}
And that's all there is to it. Again, a few details are important here, namely:
name = "dll": Specifies the import library. The .lib extension is implied, and must not be appended.
kind = "dylib": We're importing from a dynamic link library. This is the default and can be omitted, though I'm keeping it for posterity.
extern "C": As in the C++ code this controls name decoration and the calling convention. For variadic functions the C calling convention (__cdecl) is required.
*const u8: This is Rust's native type that corresponds to char const* in C and C++. Using type aliases (whether those provided by the winapi crate or otherwise) is not required. It wouldn't hurt either, but let's just keep this simple.
With that everything is set up and we can take this out for a spin. Replace the default generated fn main() with the following code in src/main.rs:
fn main() {
unsafe { output("Hello, world!\0".as_ptr()) };
}
and there you have it. cargo running this produces the famous output:
Hello, world!
So, all is fine, right? Well, no, not really. Actually, nothing is fine. You could have just as well written, compiled, and executed the following:
fn main() {
unsafe { output(b"Make sure this has reasons to crash: %f".as_ptr(), "💩") };
}
which produces the following output for me:
Make sure this has reasons to crash: 0.000000💩
though any other observable behavior is possible, too. After all, the behavior is undefined. There are two bugs: 1 The format specifier doesn't match the argument, and 2 the format string isn't NUL terminated.
Either one can be fixed, trivially even, though you have opted out of Rust's safety guarantees. Rust can't help you detect either issue, and when control reaches the library implementation, it cannot detect this either. It will just do what it was asked to do, subverting each and every one of Rust's safety guarantees.
Remarks
A few words of caution: Getting developers interested in Rust is great, and I will do my best to try whenever I get a chance to. Getting Rust-curious developers excited about Rust is often just a natural progression.
Though I will say that trying to get developers excited about Rust by starting out with unsafe Rust isn't going to be successful. It's eventually going to provoke a response like: "Look, ma, a steep learning curve with absolutely no benefit whatsoever, who could possibly resist?!" (I'm exaggerating, I know).
If your ultimate goal is to establish Rust as a superior alternative to C (and in part C++), don't start by evaluating how not to benefit from Rust. Specifically, trying to import a variadic function (the unsafest language construct in all of C++) and exposing it as an unsafe function to Rust is almost guaranteed to be the beginning of a lost battle.
Now, this may read bad as it is already, but this isn't over yet. In an attempt to make your C++ code accessible from Rust, things have gotten worse! With a C++ compiler and static code analysis tools (assuming the format string is known at compile time, and the tools understand the semantics), the tooling can and frequently will warn about mismatches. That option is now gone, forever, and there's not even a base level of protection.
If you absolutely want to make some sort of logging available to Rust, export a function from the library that takes a single char const*, use Rust's format! macro, and provide a variadic wrapper to C and C++ clients.
This question already has an answer here:
Rust Can't import Singleton From global space into another module in another file
(1 answer)
Closed 4 years ago.
I am trying to use the lazy_static crate to create a singleton and use it in a different module. Is that possible or even recommended? I'm still learning how Rust programs should be structured and have been making every file its own module.
I have the following in main.rs and I can access its values
lazy_static! {
static ref GAMEDATA: gamedata::data::GameDataS =
gamedata::data::load_data("./src/assets/data.json".to_string());
}
fn main() {
println!("data{}", GAMEDATA.width);
}
When trying to access GAMEDATA in a different module, I get
not found in this scope
for example in a module called game
pub struct Game {}
impl Game {
println!("data{}", GAMEDATA.width);
}
Is it possible to make a global variable across all modules? Is there some other way I should be thinking about it? Perhaps not using modules as often?
If your static variable is in another non-parent module, your problem seems to be a missing pub modifier before static. Also, as others pointed out, the code in which you use the variable (the impl block) is not valid Rust syntax.
Besides that, you will need to import the static variable with use (E.g. use GAMEDATA;), see Quan Brew's answer.
However, I want to discuss about the use of static and singleton pattern in Rust.
Static variables in Rust
In Rust we generally avoid static variables. In most cases they could be replaced with a proper constant via const. Because static variables may be shared between threads, having them with external mutability is unsafe in Rust. This is why you cannot have external mutability with lazy_static.
Although statics with external mutability do have their uses, they are kind of specific, should be justified and avoided otherwise. Interior mutability, as described in this section of the Rust Book is not even allowed to be shared among threads.
Singleton Pattern in Rust
I don't think it is a good idea to use static to have singleton pattern. This pattern is not common in Rust. We generally pass all mutable things as arguments.
Solutions if you need immutable data
Make it a constant with const.
If there is too much data, use static.
If you need non-constant initialization, you can keep lazy_static.
Solutions if you need to mutate data
Put your singleton into a Mutex or another lock. This will ensure correct concurrent accesses.
Make it thread local with thread_local macro + inner mutability with RefCell
Give up the "singleton pattern" idea and pass the structure via arguments (recommended).
You need use to import GAMEDATA into the current scope, as described in the modules section in the book.
Example code (playground):
#[macro_use]
extern crate lazy_static; // 1.1.0
lazy_static! {
static ref GAMEDATA: String = "hello".to_string();
}
mod foo {
use GAMEDATA;
pub fn bar() {
println!("{}", *GAMEDATA);
}
}
fn main() {
foo::bar();
}
However, the singleton pattern is not recommended in Rust. For beginners in the learning phase, you'd best avoid singletons. (see bzim's answer)
I'm writing a bare-metal application for an AMR board in Rust that involves interrupt service routines. Currently, I use #naked functions with my own assembler prolog/epilog. However, I wonder whether there is a better (and hopefully more portable) way I've missed, maybe an #interrupt-like attribute in Rust nightly or any other compiler support. I think along the lines of GCC's __attribute__ ((interrupt ("IRQ"))), since Rust's backend LLVM provides such an attribute.
Interrupts are simply another type of calling convention. For the AVR port of Rust, we added two new types of calling convention, one for each kind of interrupt that AVR supports.
The authoritative list of calling conventions is the source code. Rust 1.16 lists these:
#[derive(PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)]
pub enum Abi {
// NB: This ordering MUST match the AbiDatas array below.
// (This is ensured by the test indices_are_correct().)
// Single platform ABIs
Cdecl,
Stdcall,
Fastcall,
Vectorcall,
Aapcs,
Win64,
SysV64,
PtxKernel,
Msp430Interrupt,
// Multiplatform / generic ABIs
Rust,
C,
System,
RustIntrinsic,
RustCall,
PlatformIntrinsic,
Unadjusted
}
The unstable book also mentions that the different calling conventions exist.
To use these, you'd declare your function with it:
#![feature(abi_msp430_interrupt)]
extern "msp430-interrupt" fn handler() {}
It's still up to you to register the function as an exception handler with the interrupt vector table (or equivalent).
Of course, you may need to submit a PR that informs the Rust frontend of the specific LLVM calling convention to use, if yours isn't already in this list.
copy the information here, shamelessly ;)
https://github.com/nix-rust/nix
https://users.rust-lang.org/t/unix-signals-in-rust/733/3
use nix::sys::signal;
extern fn handle_sigint(_:i32) {
println!("Interrupted!");
panic!();
}
fn main() {
let sig_action = signal::SigAction::new(handle_sigint,
signal::SockFlag::empty(),
signal::SigSet::empty());
signal::sigaction(signal::SIGINT, &sig_action);
}
I've toyed with writing library bindings in Rust before, and it wasn't difficult. Now, however, I'm stuck: I'm trying to write a binding for librsync, and some of its functions expect you to pass an open file handle (a FILE* in C).
For primitive types, there's a straightforward way to pass them into C, (the same for pointers to primitive types). And, to be clear, I'm aware that the libc crate implements fopen, which in turn gives me a mut FILE* (which would eventually do the job). However, I was wondering if there is something in the Rust standard library that gives me a FILE* to pass to librsync — maybe something analog to std::ffi::CString.
You could of course use a RawFd, transmute and call libc::funcs::posix88::stdio::fdopen(_, mode) with it. That would be highly unportable though.
cfile (crate docs) looks like a lightweight wrapper around libcs FILE* that implements the io::Read/Write/Seek traits.