rust
rust copied to clipboard
Static linking with glibc is ok when compile, but the executable can't run, while the one which is not using 'target-feature=+crt-static' is totally fine.
I expected to see this happen: complied program with static linking runs normally.
Instead, this happened:
- when i debug, it exits with:
Stop reason: signal SIGSEGV: invalid address (fault address: 0xe5) - when i run the executable directly, it exits with:
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:
rustc 1.59.0 (9d1b2106e 2022-02-23)
binary: rustc
commit-hash: 9d1b2106e23b1abd32fce1f17267604a5102f57a
commit-date: 2022-02-23
host: x86_64-unknown-linux-gnu
release: 1.59.0
LLVM version: 13.0.0
Backtrace
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. What is the exact build command you used?
@workingjubilee
RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-unknown-linux-gnu
Following builds work as expected,
cargo build --target x86_64-unknown-linux-gnu
or
RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-unknown-linux-musl
I want to use glibc static linking.
This is the repo: https://github.com/Tencent/tat-agent But the code is not the newest, so it does not have the code that I mentioned before.
Is there a precedent where executable builds with cargo build --target x86_64-unknown-linux-gnu works, but with RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-unknown-linux-gnu doesn't?
@workingjubilee @saethlin
The files you pasted into the issue thread are ambiguous, there are multiple files in this repo named thread.rs for example. If you can link to your own fork of this perhaps which has the modifications you want maybe I could reproduce the issue you are seeing.
The repo in question doesn't link on my machine with target-feature=+crt-static, I see the usual glibc warnings and then:
/usr/bin/ld: /tmp/tat-agent/target/x86_64-unknown-linux-gnu/release/deps/libtokio-860b44f61df069aa.rlib(tokio-860b44f61df069aa.tokio.c88c0eba-cgu.6.rcgu.o): undefined reference to symbol '__tls_get_addr@@GLIBC_2.3'
/usr/bin/ld: /usr/lib/ld-linux-x86-64.so.2: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
Ok, I have forked the repo into my own account. The problem branch is the w-who, and the key source code in the folder src/conpty.
Command to run the executable: target/x86_64-unknown-linux-gnu/debug/tat_agent -c -n -p. -p indicates the agent to work as pty server which makes developer can connect to it using the client code which locates in tests/pty.html.
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.
@saethlin
https://github.com/rust-lang/rust/issues/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 rustc -C target-feature=+crt-static main.rs
Same here building in Dockerfile rust:1.67.0 image with:
RUN RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-unknown-linux-gnu --package app
and then copying the file in an alpine:3 docker image:
Segmentation fault