1use crate::stack::{Stack, pop, push};
60use crate::value::Value;
61use std::sync::atomic::{AtomicBool, Ordering};
62
63const MAX_SIGNAL: usize = 32;
65
66static SIGNAL_FLAGS: [AtomicBool; MAX_SIGNAL] = [
68 AtomicBool::new(false),
69 AtomicBool::new(false),
70 AtomicBool::new(false),
71 AtomicBool::new(false),
72 AtomicBool::new(false),
73 AtomicBool::new(false),
74 AtomicBool::new(false),
75 AtomicBool::new(false),
76 AtomicBool::new(false),
77 AtomicBool::new(false),
78 AtomicBool::new(false),
79 AtomicBool::new(false),
80 AtomicBool::new(false),
81 AtomicBool::new(false),
82 AtomicBool::new(false),
83 AtomicBool::new(false),
84 AtomicBool::new(false),
85 AtomicBool::new(false),
86 AtomicBool::new(false),
87 AtomicBool::new(false),
88 AtomicBool::new(false),
89 AtomicBool::new(false),
90 AtomicBool::new(false),
91 AtomicBool::new(false),
92 AtomicBool::new(false),
93 AtomicBool::new(false),
94 AtomicBool::new(false),
95 AtomicBool::new(false),
96 AtomicBool::new(false),
97 AtomicBool::new(false),
98 AtomicBool::new(false),
99 AtomicBool::new(false),
100];
101
102#[cfg(unix)]
104static SIGNAL_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(());
105
106#[cfg(unix)]
109extern "C" fn flag_signal_handler(sig: libc::c_int) {
110 let sig_num = sig as usize;
111 if sig_num < MAX_SIGNAL {
112 SIGNAL_FLAGS[sig_num].store(true, Ordering::Release);
113 }
114}
115
116#[cfg(unix)]
127#[unsafe(no_mangle)]
128pub unsafe extern "C" fn patch_seq_signal_sigint(stack: Stack) -> Stack {
129 unsafe { push(stack, Value::Int(libc::SIGINT as i64)) }
130}
131
132#[cfg(unix)]
139#[unsafe(no_mangle)]
140pub unsafe extern "C" fn patch_seq_signal_sigterm(stack: Stack) -> Stack {
141 unsafe { push(stack, Value::Int(libc::SIGTERM as i64)) }
142}
143
144#[cfg(unix)]
151#[unsafe(no_mangle)]
152pub unsafe extern "C" fn patch_seq_signal_sighup(stack: Stack) -> Stack {
153 unsafe { push(stack, Value::Int(libc::SIGHUP as i64)) }
154}
155
156#[cfg(unix)]
163#[unsafe(no_mangle)]
164pub unsafe extern "C" fn patch_seq_signal_sigpipe(stack: Stack) -> Stack {
165 unsafe { push(stack, Value::Int(libc::SIGPIPE as i64)) }
166}
167
168#[cfg(unix)]
175#[unsafe(no_mangle)]
176pub unsafe extern "C" fn patch_seq_signal_sigusr1(stack: Stack) -> Stack {
177 unsafe { push(stack, Value::Int(libc::SIGUSR1 as i64)) }
178}
179
180#[cfg(unix)]
187#[unsafe(no_mangle)]
188pub unsafe extern "C" fn patch_seq_signal_sigusr2(stack: Stack) -> Stack {
189 unsafe { push(stack, Value::Int(libc::SIGUSR2 as i64)) }
190}
191
192#[cfg(unix)]
199#[unsafe(no_mangle)]
200pub unsafe extern "C" fn patch_seq_signal_sigchld(stack: Stack) -> Stack {
201 unsafe { push(stack, Value::Int(libc::SIGCHLD as i64)) }
202}
203
204#[cfg(unix)]
211#[unsafe(no_mangle)]
212pub unsafe extern "C" fn patch_seq_signal_sigalrm(stack: Stack) -> Stack {
213 unsafe { push(stack, Value::Int(libc::SIGALRM as i64)) }
214}
215
216#[cfg(unix)]
223#[unsafe(no_mangle)]
224pub unsafe extern "C" fn patch_seq_signal_sigcont(stack: Stack) -> Stack {
225 unsafe { push(stack, Value::Int(libc::SIGCONT as i64)) }
226}
227
228#[cfg(not(unix))]
234#[unsafe(no_mangle)]
235pub unsafe extern "C" fn patch_seq_signal_sigint(stack: Stack) -> Stack {
236 unsafe { push(stack, Value::Int(0)) }
237}
238
239#[cfg(not(unix))]
242#[unsafe(no_mangle)]
243pub unsafe extern "C" fn patch_seq_signal_sigterm(stack: Stack) -> Stack {
244 unsafe { push(stack, Value::Int(0)) }
245}
246
247#[cfg(not(unix))]
250#[unsafe(no_mangle)]
251pub unsafe extern "C" fn patch_seq_signal_sighup(stack: Stack) -> Stack {
252 unsafe { push(stack, Value::Int(0)) }
253}
254
255#[cfg(not(unix))]
258#[unsafe(no_mangle)]
259pub unsafe extern "C" fn patch_seq_signal_sigpipe(stack: Stack) -> Stack {
260 unsafe { push(stack, Value::Int(0)) }
261}
262
263#[cfg(not(unix))]
266#[unsafe(no_mangle)]
267pub unsafe extern "C" fn patch_seq_signal_sigusr1(stack: Stack) -> Stack {
268 unsafe { push(stack, Value::Int(0)) }
269}
270
271#[cfg(not(unix))]
274#[unsafe(no_mangle)]
275pub unsafe extern "C" fn patch_seq_signal_sigusr2(stack: Stack) -> Stack {
276 unsafe { push(stack, Value::Int(0)) }
277}
278
279#[cfg(not(unix))]
282#[unsafe(no_mangle)]
283pub unsafe extern "C" fn patch_seq_signal_sigchld(stack: Stack) -> Stack {
284 unsafe { push(stack, Value::Int(0)) }
285}
286
287#[cfg(not(unix))]
290#[unsafe(no_mangle)]
291pub unsafe extern "C" fn patch_seq_signal_sigalrm(stack: Stack) -> Stack {
292 unsafe { push(stack, Value::Int(0)) }
293}
294
295#[cfg(not(unix))]
298#[unsafe(no_mangle)]
299pub unsafe extern "C" fn patch_seq_signal_sigcont(stack: Stack) -> Stack {
300 unsafe { push(stack, Value::Int(0)) }
301}
302
303#[cfg(unix)]
310fn install_signal_handler(sig_num: libc::c_int) -> Result<(), std::io::Error> {
311 use std::mem::MaybeUninit;
312
313 let _guard = SIGNAL_MUTEX
314 .lock()
315 .expect("signal: mutex poisoned during handler installation");
316
317 unsafe {
318 let mut action: libc::sigaction = MaybeUninit::zeroed().assume_init();
319 action.sa_sigaction = flag_signal_handler as libc::sighandler_t;
321 action.sa_flags = libc::SA_RESTART;
322 libc::sigemptyset(&mut action.sa_mask);
323
324 let result = libc::sigaction(sig_num, &action, std::ptr::null_mut());
325 if result != 0 {
326 return Err(std::io::Error::last_os_error());
327 }
328 }
329 Ok(())
330}
331
332#[cfg(unix)]
334fn restore_default_handler(sig_num: libc::c_int) -> Result<(), std::io::Error> {
335 use std::mem::MaybeUninit;
336
337 let _guard = SIGNAL_MUTEX
338 .lock()
339 .expect("signal: mutex poisoned during handler restoration");
340
341 unsafe {
342 let mut action: libc::sigaction = MaybeUninit::zeroed().assume_init();
343 action.sa_sigaction = libc::SIG_DFL as libc::sighandler_t;
345 action.sa_flags = 0;
346 libc::sigemptyset(&mut action.sa_mask);
347
348 let result = libc::sigaction(sig_num, &action, std::ptr::null_mut());
349 if result != 0 {
350 return Err(std::io::Error::last_os_error());
351 }
352 }
353 Ok(())
354}
355
356#[cfg(unix)]
358fn ignore_signal(sig_num: libc::c_int) -> Result<(), std::io::Error> {
359 use std::mem::MaybeUninit;
360
361 let _guard = SIGNAL_MUTEX
362 .lock()
363 .expect("signal: mutex poisoned during ignore");
364
365 unsafe {
366 let mut action: libc::sigaction = MaybeUninit::zeroed().assume_init();
367 action.sa_sigaction = libc::SIG_IGN as libc::sighandler_t;
369 action.sa_flags = 0;
370 libc::sigemptyset(&mut action.sa_mask);
371
372 let result = libc::sigaction(sig_num, &action, std::ptr::null_mut());
373 if result != 0 {
374 return Err(std::io::Error::last_os_error());
375 }
376 }
377 Ok(())
378}
379
380#[cfg(unix)]
391#[unsafe(no_mangle)]
392pub unsafe extern "C" fn patch_seq_signal_trap(stack: Stack) -> Stack {
393 unsafe {
394 let (stack, sig_val) = pop(stack);
395 let sig_num = match sig_val {
396 Value::Int(n) => {
397 if n < 0 || n as usize >= MAX_SIGNAL {
398 panic!("signal.trap: invalid signal number {}", n);
399 }
400 n as libc::c_int
401 }
402 _ => panic!(
403 "signal.trap: expected Int (signal number), got {:?}",
404 sig_val
405 ),
406 };
407
408 if let Err(e) = install_signal_handler(sig_num) {
410 panic!(
411 "signal.trap: failed to install handler for signal {}: {}",
412 sig_num, e
413 );
414 }
415 stack
416 }
417}
418
419#[cfg(unix)]
429#[unsafe(no_mangle)]
430pub unsafe extern "C" fn patch_seq_signal_received(stack: Stack) -> Stack {
431 unsafe {
432 let (stack, sig_val) = pop(stack);
433 let sig_num = match sig_val {
434 Value::Int(n) => {
435 if n < 0 || n as usize >= MAX_SIGNAL {
436 panic!("signal.received?: invalid signal number {}", n);
437 }
438 n as usize
439 }
440 _ => panic!(
441 "signal.received?: expected Int (signal number), got {:?}",
442 sig_val
443 ),
444 };
445
446 let was_set = SIGNAL_FLAGS[sig_num].swap(false, Ordering::Acquire);
448 push(stack, Value::Bool(was_set))
449 }
450}
451
452#[cfg(unix)]
462#[unsafe(no_mangle)]
463pub unsafe extern "C" fn patch_seq_signal_pending(stack: Stack) -> Stack {
464 unsafe {
465 let (stack, sig_val) = pop(stack);
466 let sig_num = match sig_val {
467 Value::Int(n) => {
468 if n < 0 || n as usize >= MAX_SIGNAL {
469 panic!("signal.pending?: invalid signal number {}", n);
470 }
471 n as usize
472 }
473 _ => panic!(
474 "signal.pending?: expected Int (signal number), got {:?}",
475 sig_val
476 ),
477 };
478
479 let is_set = SIGNAL_FLAGS[sig_num].load(Ordering::Acquire);
480 push(stack, Value::Bool(is_set))
481 }
482}
483
484#[cfg(unix)]
493#[unsafe(no_mangle)]
494pub unsafe extern "C" fn patch_seq_signal_default(stack: Stack) -> Stack {
495 unsafe {
496 let (stack, sig_val) = pop(stack);
497 let sig_num = match sig_val {
498 Value::Int(n) => {
499 if n < 0 || n as usize >= MAX_SIGNAL {
500 panic!("signal.default: invalid signal number {}", n);
501 }
502 n as libc::c_int
503 }
504 _ => panic!(
505 "signal.default: expected Int (signal number), got {:?}",
506 sig_val
507 ),
508 };
509
510 if let Err(e) = restore_default_handler(sig_num) {
511 panic!(
512 "signal.default: failed to restore default handler for signal {}: {}",
513 sig_num, e
514 );
515 }
516 stack
517 }
518}
519
520#[cfg(unix)]
530#[unsafe(no_mangle)]
531pub unsafe extern "C" fn patch_seq_signal_ignore(stack: Stack) -> Stack {
532 unsafe {
533 let (stack, sig_val) = pop(stack);
534 let sig_num = match sig_val {
535 Value::Int(n) => {
536 if n < 0 || n as usize >= MAX_SIGNAL {
537 panic!("signal.ignore: invalid signal number {}", n);
538 }
539 n as libc::c_int
540 }
541 _ => panic!(
542 "signal.ignore: expected Int (signal number), got {:?}",
543 sig_val
544 ),
545 };
546
547 if let Err(e) = ignore_signal(sig_num) {
548 panic!("signal.ignore: failed to ignore signal {}: {}", sig_num, e);
549 }
550 stack
551 }
552}
553
554#[cfg(unix)]
563#[unsafe(no_mangle)]
564pub unsafe extern "C" fn patch_seq_signal_clear(stack: Stack) -> Stack {
565 unsafe {
566 let (stack, sig_val) = pop(stack);
567 let sig_num = match sig_val {
568 Value::Int(n) => {
569 if n < 0 || n as usize >= MAX_SIGNAL {
570 panic!("signal.clear: invalid signal number {}", n);
571 }
572 n as usize
573 }
574 _ => panic!(
575 "signal.clear: expected Int (signal number), got {:?}",
576 sig_val
577 ),
578 };
579
580 SIGNAL_FLAGS[sig_num].store(false, Ordering::Release);
581 stack
582 }
583}
584
585#[cfg(not(unix))]
591#[unsafe(no_mangle)]
592pub unsafe extern "C" fn patch_seq_signal_trap(stack: Stack) -> Stack {
593 let (stack, _) = unsafe { pop(stack) };
594 stack
596}
597
598#[cfg(not(unix))]
601#[unsafe(no_mangle)]
602pub unsafe extern "C" fn patch_seq_signal_default(stack: Stack) -> Stack {
603 let (stack, _) = unsafe { pop(stack) };
604 stack
605}
606
607#[cfg(not(unix))]
610#[unsafe(no_mangle)]
611pub unsafe extern "C" fn patch_seq_signal_ignore(stack: Stack) -> Stack {
612 let (stack, _) = unsafe { pop(stack) };
613 stack
614}
615
616#[cfg(not(unix))]
619#[unsafe(no_mangle)]
620pub unsafe extern "C" fn patch_seq_signal_received(stack: Stack) -> Stack {
621 let (stack, _) = unsafe { pop(stack) };
622 unsafe { push(stack, Value::Bool(false)) }
624}
625
626#[cfg(not(unix))]
629#[unsafe(no_mangle)]
630pub unsafe extern "C" fn patch_seq_signal_pending(stack: Stack) -> Stack {
631 let (stack, _) = unsafe { pop(stack) };
632 unsafe { push(stack, Value::Bool(false)) }
634}
635
636#[cfg(not(unix))]
639#[unsafe(no_mangle)]
640pub unsafe extern "C" fn patch_seq_signal_clear(stack: Stack) -> Stack {
641 let (stack, _) = unsafe { pop(stack) };
642 stack
644}
645
646#[cfg(test)]
647mod tests {
648 use super::*;
649 use serial_test::serial;
650
651 #[test]
652 #[serial]
653 fn test_signal_flag_operations() {
654 const TEST_IDX: usize = 3;
658
659 SIGNAL_FLAGS[TEST_IDX].store(false, Ordering::Release);
661
662 assert!(!SIGNAL_FLAGS[TEST_IDX].load(Ordering::Acquire));
664
665 SIGNAL_FLAGS[TEST_IDX].store(true, Ordering::Release);
667 assert!(SIGNAL_FLAGS[TEST_IDX].load(Ordering::Acquire));
668
669 let was_set = SIGNAL_FLAGS[TEST_IDX].swap(false, Ordering::Acquire);
671 assert!(was_set);
672 assert!(!SIGNAL_FLAGS[TEST_IDX].load(Ordering::Acquire));
673
674 let was_set = SIGNAL_FLAGS[TEST_IDX].swap(false, Ordering::Acquire);
676 assert!(!was_set);
677
678 SIGNAL_FLAGS[TEST_IDX].store(false, Ordering::Release);
680 }
681
682 #[cfg(unix)]
683 #[test]
684 #[serial]
685 fn test_signal_handler_installation() {
686 let result = install_signal_handler(libc::SIGUSR1);
688 assert!(result.is_ok(), "Failed to install SIGUSR1 handler");
689
690 let result = restore_default_handler(libc::SIGUSR1);
692 assert!(result.is_ok(), "Failed to restore SIGUSR1 default handler");
693 }
694
695 #[cfg(unix)]
696 #[test]
697 #[serial]
698 fn test_signal_delivery() {
699 install_signal_handler(libc::SIGUSR1).expect("Failed to install handler");
701
702 SIGNAL_FLAGS[libc::SIGUSR1 as usize].store(false, Ordering::Release);
704
705 unsafe {
707 libc::kill(libc::getpid(), libc::SIGUSR1);
708 }
709
710 std::thread::sleep(std::time::Duration::from_millis(1));
712
713 let received = SIGNAL_FLAGS[libc::SIGUSR1 as usize].swap(false, Ordering::Acquire);
715 assert!(received, "Signal was not received");
716
717 restore_default_handler(libc::SIGUSR1).expect("Failed to restore handler");
719 }
720
721 #[cfg(unix)]
722 #[test]
723 #[serial]
724 fn test_invalid_signal_fails() {
725 let result = install_signal_handler(libc::SIGKILL);
727 assert!(result.is_err(), "SIGKILL should not be catchable");
728
729 let result = install_signal_handler(libc::SIGSTOP);
730 assert!(result.is_err(), "SIGSTOP should not be catchable");
731 }
732
733 #[cfg(unix)]
734 #[test]
735 #[serial]
736 fn test_signal_ignore() {
737 let result = ignore_signal(libc::SIGUSR2);
739 assert!(result.is_ok(), "Failed to ignore SIGUSR2");
740
741 let result = restore_default_handler(libc::SIGUSR2);
743 assert!(result.is_ok(), "Failed to restore SIGUSR2 default handler");
744 }
745
746 #[cfg(unix)]
747 #[test]
748 #[serial]
749 fn test_multiple_signals_independent() {
750 install_signal_handler(libc::SIGUSR1).expect("Failed to install SIGUSR1");
752 install_signal_handler(libc::SIGUSR2).expect("Failed to install SIGUSR2");
753
754 SIGNAL_FLAGS[libc::SIGUSR1 as usize].store(false, Ordering::Release);
756 SIGNAL_FLAGS[libc::SIGUSR2 as usize].store(false, Ordering::Release);
757
758 unsafe {
760 libc::kill(libc::getpid(), libc::SIGUSR1);
761 }
762 std::thread::sleep(std::time::Duration::from_millis(1));
763
764 assert!(SIGNAL_FLAGS[libc::SIGUSR1 as usize].load(Ordering::Acquire));
766 assert!(!SIGNAL_FLAGS[libc::SIGUSR2 as usize].load(Ordering::Acquire));
767
768 restore_default_handler(libc::SIGUSR1).expect("Failed to restore SIGUSR1");
770 restore_default_handler(libc::SIGUSR2).expect("Failed to restore SIGUSR2");
771 }
772
773 #[cfg(unix)]
774 #[test]
775 fn test_signal_constants_valid() {
776 assert!(libc::SIGINT > 0 && (libc::SIGINT as usize) < MAX_SIGNAL);
778 assert!(libc::SIGTERM > 0 && (libc::SIGTERM as usize) < MAX_SIGNAL);
779 assert!(libc::SIGHUP > 0 && (libc::SIGHUP as usize) < MAX_SIGNAL);
780 assert!(libc::SIGPIPE > 0 && (libc::SIGPIPE as usize) < MAX_SIGNAL);
781 assert!(libc::SIGUSR1 > 0 && (libc::SIGUSR1 as usize) < MAX_SIGNAL);
782 assert!(libc::SIGUSR2 > 0 && (libc::SIGUSR2 as usize) < MAX_SIGNAL);
783 }
784}