Skip to content

Commit d6dbe7d

Browse files
authored
Add Process.debugger_present? for Windows and Linux (#16248)
1 parent a554e10 commit d6dbe7d

File tree

7 files changed

+47
-0
lines changed

7 files changed

+47
-0
lines changed

spec/std/process_spec.cr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,12 @@ describe Process do
442442

443443
typeof(Process.new(*standing_command).terminate(graceful: false))
444444

445+
describe ".debugger_present?" do
446+
it "compiles" do
447+
typeof(Process.debugger_present?)
448+
end
449+
end
450+
445451
it ".exists?" do
446452
# On Windows killing a parent process does not reparent its children to
447453
# another existing process, so the following isn't guaranteed to work

src/crystal/system/process.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ struct Crystal::System::Process
5656
# Restores default handling of interrupt requests.
5757
# def self.restore_interrupts!
5858

59+
# Returns whether a debugger is attached to the current process.
60+
# def self.debugger_present? : Bool
61+
5962
# Spawns a fiber responsible for executing interrupt handlers on the main
6063
# thread.
6164
# def self.start_interrupt_loop

src/crystal/system/unix/process.cr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ struct Crystal::System::Process
100100
# do nothing; `Crystal::System::Signal.start_loop` takes care of this
101101
end
102102

103+
def self.debugger_present? : Bool
104+
{% if flag?(:linux) %}
105+
::File.each_line("/proc/self/status") do |line|
106+
if tracer_pid = line.lchop?("TracerPid:").try(&.to_i?)
107+
return true if tracer_pid != 0
108+
end
109+
end
110+
{% end %}
111+
112+
# TODO: [Darwin](https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x)
113+
# TODO: other BSDs
114+
# TODO: [Solaris](https://docs.oracle.com/cd/E23824_01/html/821-1473/proc-4.html)
115+
false
116+
end
117+
103118
def self.exists?(pid)
104119
ret = LibC.kill(pid, 0)
105120
if ret == 0

src/crystal/system/wasi/process.cr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ struct Crystal::System::Process
6868
def self.start_interrupt_loop : Nil
6969
end
7070

71+
def self.debugger_present? : Bool
72+
false
73+
end
74+
7175
def self.exists?(pid)
7276
raise NotImplementedError.new("Process.exists?")
7377
end

src/crystal/system/win32/process.cr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ require "c/handleapi"
33
require "c/jobapi2"
44
require "c/synchapi"
55
require "c/tlhelp32"
6+
require "c/debugapi"
67
require "process/shell"
78
require "crystal/atomic_semaphore"
89

@@ -229,6 +230,10 @@ struct Crystal::System::Process
229230
end
230231
end
231232

233+
def self.debugger_present? : Bool
234+
LibC.IsDebuggerPresent != 0
235+
end
236+
232237
def self.exists?(pid)
233238
handle = LibC.OpenProcess(LibC::PROCESS_QUERY_INFORMATION, 0, pid)
234239
return false unless handle
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require "c/win_def"
2+
3+
lib LibC
4+
fun IsDebuggerPresent : BOOL
5+
end

src/process.cr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@ class Process
110110
Crystal::System::Process.restore_interrupts!
111111
end
112112

113+
# Returns whether a debugger is attached to the current process.
114+
#
115+
# Currently supported on Windows and Linux. Always returns `false` on other
116+
# systems.
117+
@[Experimental]
118+
def self.debugger_present? : Bool
119+
Crystal::System::Process.debugger_present?
120+
end
121+
113122
# Returns `true` if the process identified by *pid* is valid for
114123
# a currently registered process, `false` otherwise. Note that this
115124
# returns `true` for a process in the zombie or similar state.

0 commit comments

Comments
 (0)