New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x86_64-unknown-linux-gnu using 'target-feature=+crt-static' exits with: Segmentation fault (core dumped). #100110
Comments
Can you provide or point to enough code that we can use to reproduce this? |
thread.rs use crate::common::consts::{
EVENT_SLOT_PTY_CMD, PTY_FLAG_INIT_BLOCK, PTY_REMOVE_INTERVAL, PTY_WS_MSG,
WS_MSG_TYPE_PTY_ERROR, WS_MSG_TYPE_PTY_INPUT, WS_MSG_TYPE_PTY_OUTPUT, WS_MSG_TYPE_PTY_READY,
WS_MSG_TYPE_PTY_RESIZE, WS_MSG_TYPE_PTY_START, WS_MSG_TYPE_PTY_STOP,
};
use crate::common::evbus::EventBus;
use crate::conpty::{PtySession, PtySystem};
use crate::types::ws_msg::{PtyError, PtyInput, PtyReady, PtyResize, PtyStop, WsMsg};
use crate::types::ws_msg::{PtyOutput, PtyStart};
use log::{error, info};
use serde::Serialize;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::{AtomicU64, Ordering, Ordering::SeqCst};
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::io::AsyncReadExt;
use tokio::runtime::Runtime;
use tokio::time::timeout;
cfg_if::cfg_if! {
if #[cfg(unix)] {
use super::unix::install_scripts;
use super::unix::ConPtySystem;
use users::get_current_username;
} else if #[cfg(windows)] {
use super::windows::ConPtySystem;
use crate::executor::powershell_command::get_current_user;
}
}
#[derive(Clone)]
pub(crate) struct Session {
session_id: String,
pty_session: Arc<dyn PtySession + Send + Sync>,
writer: Arc<Mutex<File>>,
last_input_time: Arc<AtomicU64>,
is_stoped: Arc<AtomicBool>,
}
#[derive(Clone)]
pub(crate) struct SessionManager {
ws_seq_num: Arc<AtomicU64>,
running_task_num: Arc<AtomicU64>,
pub(crate) session_map: Arc<RwLock<HashMap<String, Arc<Session>>>>,
pub(crate) event_bus: Arc<EventBus>,
runtime: Arc<Runtime>,
}
pub fn run(dispatcher: &Arc<EventBus>, running_task_num: &Arc<AtomicU64>) {
#[cfg(unix)]
install_scripts();
let context = Arc::new(SessionManager {
event_bus: dispatcher.clone(),
session_map: Arc::new(RwLock::new(HashMap::default())),
running_task_num: running_task_num.clone(),
ws_seq_num: Arc::new(AtomicU64::new(0)),
runtime: Arc::new(Runtime::new().unwrap()),
});
register_pty_hander(context.clone());
}
fn register_pty_hander(sm: Arc<SessionManager>) {
let self_0 = sm.clone();
let self_1 = sm.clone();
let self_2 = sm.clone();
let self_3 = sm.clone();
sm.event_bus
.slot_register(
EVENT_SLOT_PTY_CMD,
WS_MSG_TYPE_PTY_START,
move |value: String| {
self_0.handle_pty_start(value);
},
)
.slot_register(
EVENT_SLOT_PTY_CMD,
WS_MSG_TYPE_PTY_STOP,
move |value: String| {
self_1.handle_pty_stop(&value);
},
)
.slot_register(
EVENT_SLOT_PTY_CMD,
WS_MSG_TYPE_PTY_RESIZE,
move |value: String| {
self_2.handle_pty_resize(value);
},
)
.slot_register(
EVENT_SLOT_PTY_CMD,
WS_MSG_TYPE_PTY_INPUT,
move |value: String| {
self_3.handle_pty_input(value);
},
);
}
impl SessionManager {
fn handle_pty_start(&self, value: String) {
info!("=>handle_pty_start {}", value);
let pty_start: PtyStart = match serde_json::from_str(&value) {
Ok(v) => v,
_ => return,
};
let session_id = pty_start.session_id;
let user_name = if pty_start.user_name.len() == 0 {
#[cfg(unix)]
{
let name = get_current_username().unwrap();
String::from(name.to_str().unwrap())
}
#[cfg(windows)]
get_current_user()
} else {
pty_start.user_name
};
let mut flag: u32 = 0;
if pty_start.init_block {
flag = flag | PTY_FLAG_INIT_BLOCK
}
self.running_task_num.fetch_add(1, SeqCst);
let pty_session =
match ConPtySystem::default().openpty(&user_name, pty_start.cols, pty_start.rows, flag)
{
Ok(session) => session,
Err(e) => {
error!("=>openpty err {}", e.to_string());
let msg = self.build_error_msg(session_id.clone(), e);
self.event_bus.dispatch(PTY_WS_MSG, msg);
self.running_task_num.fetch_sub(1, SeqCst);
return;
}
};
let input_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let writer = pty_session.get_writer().unwrap();
let session = Arc::new(Session {
session_id: session_id.clone(),
pty_session,
writer: Arc::new(Mutex::new(writer)),
last_input_time: Arc::new(AtomicU64::new(input_time)),
is_stoped: Arc::new(AtomicBool::new(false)),
});
self.session_map
.write()
.unwrap()
.insert(session_id.clone(), session.clone());
let msg = self.build_ready_msg(session_id.clone());
self.event_bus.dispatch(PTY_WS_MSG, msg);
let self_0 = self.clone();
self.runtime
.spawn(async move { self_0.report_output(session).await });
info!("handle_pty_start success");
}
fn handle_pty_stop(&self, value: &str) {
info!("handle_pty_stop {}", value);
let pty_stop: PtyStop = match serde_json::from_str(&value) {
Ok(v) => v,
_ => return,
};
self.remove_session(&pty_stop.session_id);
info!("handle_pty_stop session {} removed ", &pty_stop.session_id);
}
fn handle_pty_resize(&self, value: String) {
info!("handle_pty_resize {}", value);
let pty_resize: PtyResize = match serde_json::from_str(&value) {
Ok(v) => v,
_ => return,
};
let session_id = pty_resize.session_id.clone();
self.work_in_session(&session_id, move |session| {
let _ = session.pty_session.resize(pty_resize.cols, pty_resize.rows);
});
}
fn handle_pty_input(&self, value: String) {
let pty_input: PtyInput = match serde_json::from_str(&value) {
Ok(v) => v,
_ => return,
};
let input_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
if let Ok(input) = base64::decode(pty_input.input) {
let session_id = pty_input.session_id.clone();
self.work_in_session(&session_id, move |session| {
let _ = session.writer.lock().unwrap().write(&input).unwrap();
session.last_input_time.store(input_time, SeqCst);
})
}
}
async fn report_output(&self, session: Arc<Session>) {
info!("=>report_output {}", session.session_id);
let duration = Duration::from_millis(100);
let mut reader = tokio::fs::File::from_std(session.pty_session.get_reader().unwrap());
loop {
if session.is_stoped.load(SeqCst) {
info!(
"report_output find {} session stoped,break",
session.session_id
);
break;
}
//no input about five miniutes, break
if !self.check_last_input_time(&session) {
info!(
"pty session {} check_last_input_time fail",
session.session_id
);
break;
}
let mut buffer: [u8; 1024] = [0; 1024];
let timeout_read = timeout(duration, reader.read(&mut buffer[..])).await;
if timeout_read.is_err() {
continue;
}
match timeout_read.unwrap() {
Ok(size) => {
if size > 0 {
let msg =
self.build_output_msg(session.session_id.clone(), &mut buffer[0..size]);
self.event_bus.dispatch(PTY_WS_MSG, msg);
} else {
info!("pty session {} read size is 0 close", session.session_id);
break;
}
}
Err(e) => {
info!(
"pty session {} report_output err, {}",
session.session_id, e
);
let msg = self.build_error_msg(
session.session_id.clone(),
format!("Session {} terminated", session.session_id),
);
self.event_bus.dispatch(PTY_WS_MSG, msg);
break;
}
}
}
self.remove_session(&session.session_id);
info!("report_output {} finished", session.session_id);
}
fn remove_session(&self, session_id: &str) {
if let Some(session) = self.session_map.write().unwrap().remove(session_id) {
info!("remove_session {} removed", session_id);
session.is_stoped.store(true, SeqCst);
self.running_task_num.fetch_sub(1, Ordering::SeqCst);
}
}
fn check_last_input_time(&self, session: &Arc<Session>) -> bool {
let last = session.last_input_time.load(SeqCst);
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
return if now - last > PTY_REMOVE_INTERVAL {
false //time out
} else {
true
};
}
pub(crate) fn work_in_session<F>(&self, session_id: &str, func: F)
where
F: Fn(Arc<Session>) + 'static + Sync + Send,
{
if let Some(session) = self.session_map.read().unwrap().get(session_id) {
func(session.clone());
} else {
error!("Session {} not find", session_id);
let msg = self.build_error_msg(
session_id.to_string(),
format!("Session {} not exist", session_id),
);
self.event_bus.dispatch(PTY_WS_MSG, msg);
}
}
fn build_output_msg(&self, session_id: String, buf: &mut [u8]) -> String {
let data = base64::encode(buf);
let pty_output = PtyOutput {
session_id,
output: data,
};
self.build_msg(WS_MSG_TYPE_PTY_OUTPUT, pty_output)
}
fn build_ready_msg(&self, session_id: String) -> String {
let pty_ready = PtyReady { session_id };
self.build_msg(WS_MSG_TYPE_PTY_READY, pty_ready)
}
fn build_error_msg(&self, session_id: String, reason: String) -> String {
let pty_ready = PtyError { session_id, reason };
self.build_msg(WS_MSG_TYPE_PTY_ERROR, pty_ready)
}
fn build_msg<T>(&self, msg_type: &str, msg_body: T) -> String
where
T: Serialize,
{
let value = serde_json::to_value(msg_body).unwrap();
let msg = WsMsg {
r#type: msg_type.to_string(),
seq: self.ws_seq_num.fetch_add(1, SeqCst),
data: Some(value),
};
serde_json::to_string(&msg).unwrap()
}
}
#[cfg(test)]
mod test {
#[cfg(unix)]
use crate::conpty::unix::ConPtySystem;
#[cfg(windows)]
use crate::conpty::windows::ConPtySystem;
use crate::conpty::PtySystem;
#[cfg(windows)]
use crate::executor::powershell_command::get_current_user;
use log::info;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::time::timeout;
#[cfg(unix)]
use users::get_current_username;
#[tokio::test]
async fn test() {
#[cfg(unix)]
let user_name = String::from(get_current_username().unwrap().to_str().unwrap());
#[cfg(windows)]
let user_name = get_current_user();
let session = ConPtySystem::default()
.openpty(&user_name, 200, 100, 0)
.unwrap();
let mut reader = tokio::fs::File::from_std(session.get_reader().unwrap());
let mut writer = tokio::fs::File::from_std(session.get_writer().unwrap());
//consume data
loop {
let mut temp: [u8; 1024] = [0; 1024];
let duration = Duration::from_secs(10);
let timeout_read = timeout(duration, reader.read(&mut temp[..])).await;
if timeout_read.is_err() {
break;
}
}
writer.write("echo \"test\" \r".as_bytes()).await.unwrap();
let mut buffer: [u8; 1024] = [0; 1024];
let mut len = 0;
//read pwd output
loop {
let duration = Duration::from_secs(4);
let timeout_read = timeout(duration, reader.read(&mut buffer[len..])).await;
if timeout_read.is_err() {
break;
}
len += timeout_read.unwrap().unwrap()
}
let output = String::from_utf8_lossy(&buffer[..len]);
info!("output is {}", output);
let result = output.to_string().contains("test");
std::mem::drop(session);
assert!(result);
}
} |
unix.rs use super::{PtySession, PtySystem};
use crate::common::consts::{
self, BASH_PREEXC, BLOCK_INIT, COREOS_BASH_PREEXC, COREOS_BLOCK_INIT, PTY_FLAG_INIT_BLOCK,
};
use crate::conpty::utmpx::{LoginContext, DEFAULT_DEVICE, FD_PATH};
use crate::executor::proc::BaseCommand;
use crate::executor::shell_command::{build_envs, cmd_path};
use libc::{self, waitpid, winsize};
use log::{error, info};
use std::fs::read_link;
use std::fs::{create_dir_all, read_to_string, set_permissions, write, File, Permissions};
use std::io::Write;
use std::os::unix::prelude::{AsRawFd, CommandExt, FromRawFd, PermissionsExt, RawFd};
use std::path::Path;
use std::path::PathBuf;
use std::process::{Child, Command};
use std::ptr::null_mut;
use std::sync::{Arc, Mutex};
use std::{io, ptr};
use users::get_user_by_name;
use users::os::unix::UserExt;
use users::User;
struct Inner {
master: File,
slave: File,
child: Child,
}
fn openpty(user: User, cols: u16, rows: u16) -> Result<(File, File), String> {
let mut master: RawFd = -1;
let mut slave: RawFd = -1;
let mut size = winsize {
ws_col: cols,
ws_row: rows,
ws_xpixel: 0,
ws_ypixel: 0,
};
unsafe {
if 0 != libc::openpty(
&mut master,
&mut slave,
ptr::null_mut(),
ptr::null_mut(),
&mut size,
) {
return Err(format!("openpty fail {}", io::Error::last_os_error()));
};
libc::fchown(slave, user.uid(), user.primary_group_id());
}
let master = unsafe { File::from_raw_fd(master) };
let slave = unsafe { File::from_raw_fd(slave) };
Ok((master, slave))
}
#[derive(Default)]
pub struct ConPtySystem {}
impl PtySystem for ConPtySystem {
fn openpty(
&self,
user_name: &str,
cols: u16,
rows: u16,
#[allow(dead_code)] flag: u32,
) -> Result<std::sync::Arc<dyn PtySession + Send + Sync>, String> {
let user = get_user_by_name(user_name).ok_or(format!("user {} not exist", user_name))?;
let shell_path = cmd_path("bash").ok_or("bash not exist".to_string())?;
let home_path = user.home_dir().to_str().unwrap_or_else(|| "/tmp");
let envs = build_envs(user_name, home_path, &shell_path);
let (mut master, slave) = openpty(user.clone(), cols, rows)?;
let mut cmd = Command::new("bash");
unsafe {
cmd.pre_exec(move || {
for signo in &[
libc::SIGCHLD,
libc::SIGINT,
libc::SIGQUIT,
libc::SIGTERM,
libc::SIGALRM,
] {
libc::signal(*signo, libc::SIG_DFL);
}
libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGHUP);
if libc::setsid() == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
});
}
let child = cmd
.args(["--login"])
.uid(0)
.gid(0)
.stdin(slave.try_clone().unwrap())
.stdout(slave.try_clone().unwrap())
.stderr(slave.try_clone().unwrap())
.envs(envs)
.spawn()
.map_err(|e| format!("spwan err {}", e))?;
if (flag & PTY_FLAG_INIT_BLOCK) != 0 {
let init_block = format!("source {};clear\n", BLOCK_INIT);
let _ = master.write(init_block.as_bytes());
}
let pid = child.id() as i32;
let path_buf = PathBuf::from(format!("{}{}", FD_PATH, slave.as_raw_fd()));
let path = read_link(path_buf).unwrap_or(PathBuf::from(DEFAULT_DEVICE));
let path = path.to_str().unwrap_or(DEFAULT_DEVICE);
let lc = LoginContext::new(pid, path, &user_name, "127.0.0.1");
lc.login();
return Ok(Arc::new(UnixPtySession {
inner: Arc::new(Mutex::new(Inner {
master,
slave,
child,
})),
}));
}
}
pub struct UnixPtySession {
inner: Arc<Mutex<Inner>>,
}
impl PtySession for UnixPtySession {
fn resize(&self, cols: u16, rows: u16) -> Result<(), String> {
let size = winsize {
ws_row: rows,
ws_col: cols,
ws_xpixel: 0,
ws_ypixel: 0,
};
let result = unsafe {
let inner = self.inner.lock().unwrap();
libc::ioctl(
inner.master.as_raw_fd(),
libc::TIOCSWINSZ,
&size as *const _,
)
};
if result != 0 {
Err(format!("{}", io::Error::last_os_error()))
} else {
Ok(())
}
}
fn get_reader(&self) -> Result<std::fs::File, std::string::String> {
self.get_writer()
}
fn get_writer(&self) -> Result<std::fs::File, std::string::String> {
let inner = self.inner.lock().unwrap();
inner.master.try_clone().map_err(|e| format!("err {}", e))
}
}
impl Drop for UnixPtySession {
fn drop(&mut self) {
let pid = self.inner.lock().unwrap().child.id() as i32;
let fd = self.inner.lock().unwrap().slave.as_raw_fd();
let path_buf = PathBuf::from(format!("{}{}", FD_PATH, fd));
let path = read_link(path_buf).unwrap_or(PathBuf::from(DEFAULT_DEVICE));
let path = path.to_str().unwrap_or(DEFAULT_DEVICE);
let lc = LoginContext::new(pid, path, "", "127.0.0.1");
lc.logout();
BaseCommand::kill_process_group(pid as u32);
unsafe {
waitpid(pid, null_mut(), 0);
}
}
}
fn install_script(mem_data: String, path: &str) -> io::Result<()> {
let file_data = read_to_string(path).unwrap_or_else(|_| "".to_string());
if mem_data != file_data {
//write
let parent = Path::new(path).parent().unwrap();
create_dir_all(parent)?;
set_permissions(
parent,
Permissions::from_mode(consts::FILE_EXECUTE_PERMISSION_MODE),
)?;
write(path, mem_data)?;
set_permissions(
path,
Permissions::from_mode(consts::FILE_EXECUTE_PERMISSION_MODE),
)?;
}
Ok(())
}
pub(crate) fn install_scripts() {
let is_coreos = match read_to_string("/etc/os-release") {
Ok(data) => data.contains("CoreOS"),
Err(_) => false,
};
info!("install_scripts is_coreos {}", is_coreos);
let (pexec_path, init_path) = if is_coreos {
(COREOS_BASH_PREEXC, COREOS_BLOCK_INIT)
} else {
(BASH_PREEXC, BLOCK_INIT)
};
let mem_data = String::from_utf8_lossy(include_bytes!("../../misc/bash-preexec.sh"));
let _ = install_script(mem_data.to_string(), pexec_path).map_err(|e| {
error!("install_scripts {} fail {}", pexec_path, e);
});
let mem_data = String::from_utf8_lossy(include_bytes!("../../misc/bash-init.sh"));
let _ = install_script(mem_data.to_string(), init_path).map_err(|e| {
error!("install_scripts {} fail {}", init_path, e);
});
} |
In thread.rs, program crashes in handle_pty_start function, but not the same line in every time, I marked it below. fn handle_pty_start(&self, value: String) {
info!("=>handle_pty_start {}", value);
let pty_start: PtyStart = match serde_json::from_str(&value) {
Ok(v) => v,
_ => return,
};
let session_id = pty_start.session_id;
let user_name = if pty_start.user_name.len() == 0 {
#[cfg(unix)]
{
let name = get_current_username().unwrap();<-------------------sometimes here.
String::from(name.to_str().unwrap())
}
#[cfg(windows)]
get_current_user()
} else {
pty_start.user_name
};
let mut flag: u32 = 0;
if pty_start.init_block {
flag = flag | PTY_FLAG_INIT_BLOCK
}
self.running_task_num.fetch_add(1, SeqCst);
let pty_session =
match ConPtySystem::default().openpty(&user_name, pty_start.cols, pty_start.rows, flag)
{
Ok(session) => session,
Err(e) => {
error!("=>openpty err {}", e.to_string());
let msg = self.build_error_msg(session_id.clone(), e);
self.event_bus.dispatch(PTY_WS_MSG, msg);
self.running_task_num.fetch_sub(1, SeqCst);
return;
}
};
let input_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let writer = pty_session.get_writer().unwrap();
let session = Arc::new(Session {
session_id: session_id.clone(),
pty_session,
writer: Arc::new(Mutex::new(writer)),
last_input_time: Arc::new(AtomicU64::new(input_time)),
is_stoped: Arc::new(AtomicBool::new(false)),
});
self.session_map
.write()
.unwrap()
.insert(session_id.clone(), session.clone());
let msg = self.build_ready_msg(session_id.clone());
self.event_bus.dispatch(PTY_WS_MSG, msg);
let self_0 = self.clone();
self.runtime
.spawn(async move { self_0.report_output(session).await });
info!("handle_pty_start success");<-------------------sometimes here.
} |
In unix.rs, it crashes in openpty function. fn openpty(
&self,
user_name: &str,
cols: u16,
rows: u16,
#[allow(dead_code)] flag: u32,
) -> Result<std::sync::Arc<dyn PtySession + Send + Sync>, String> {
let user = get_user_by_name(user_name).ok_or(format!("user {} not exist", user_name))?;<-------------------sometimes here.
let shell_path = cmd_path("bash").ok_or("bash not exist".to_string())?;
let home_path = user.home_dir().to_str().unwrap_or_else(|| "/tmp");
let envs = build_envs(user_name, home_path, &shell_path);
let (mut master, slave) = openpty(user.clone(), cols, rows)?;
let mut cmd = Command::new("bash");
unsafe {
cmd.pre_exec(move || {
for signo in &[
libc::SIGCHLD,
libc::SIGINT,
libc::SIGQUIT,
libc::SIGTERM,
libc::SIGALRM,
] {
libc::signal(*signo, libc::SIG_DFL);
}
libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGHUP);
if libc::setsid() == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
});
}
let child = cmd
.args(["--login"])
.uid(0)
.gid(0)
.stdin(slave.try_clone().unwrap())
.stdout(slave.try_clone().unwrap())
.stderr(slave.try_clone().unwrap())
.envs(envs)
.spawn()
.map_err(|e| format!("spwan err {}", e))?;
if (flag & PTY_FLAG_INIT_BLOCK) != 0 {
let init_block = format!("source {};clear\n", BLOCK_INIT);
let _ = master.write(init_block.as_bytes());
}
let pid = child.id() as i32;
let path_buf = PathBuf::from(format!("{}{}", FD_PATH, slave.as_raw_fd()));
let path = read_link(path_buf).unwrap_or(PathBuf::from(DEFAULT_DEVICE));
let path = path.to_str().unwrap_or(DEFAULT_DEVICE);
let lc = LoginContext::new(pid, path, &user_name, "127.0.0.1");
lc.login();
return Ok(Arc::new(UnixPtySession {
inner: Arc::new(Mutex::new(Inner {
master,
slave,
child,
})),
}));
}
} |
Mmm. Pushing a repo might have been more to-the-point. |
Following builds work as expected, I want to use glibc static linking. |
This is the repo: https://github.com/Tencent/tat-agent Is there a precedent where executable builds with |
The files you pasted into the issue thread are ambiguous, there are multiple files in this repo named The repo in question doesn't link on my machine with
|
Ok, I have forked the repo into my own account. The problem branch is the Command to run the executable: I think you still cannot run the executable as it needs to run in a particular environment. But you can give me more help according to the full code. Thank you for your prompt reply. |
#100711 seems that it might also to be related (also does some networking stuff) and have a much simpler MCVE: use std::net::ToSocketAddrs;
pub fn main() {
println!("before");
let _ = "localhost:8080".to_socket_addrs(); // will segfault
std::net::TcpStream::connect("localhost:8080").unwrap(); // will also segfault
println!("hello world");
} with |
Same here building in Dockerfile rust:1.67.0 image with:
and then copying the file in an
|
I expected to see this happen: complied program with static linking runs normally.
Instead, this happened:
Stop reason: signal SIGSEGV: invalid address (fault address: 0xe5)
Segmentation fault (core dumped)
But when i debug the executable without static linking, it works well. And when i build with '--target x86_64-unknown-linux-musl', it works well, too.
I think it's not a code error, but some config problems.
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: