slideshare://feyeleanor
the art of low-level ruby and other macabre tales
Eleanor McHugh
Never Say, "Never Say Die!"
[2001 edition]
My Dilemma
• Ruby is
a
notoriously high level
progr
a
mming l
a
ngu
a
ge
•
a
nd it's the one I most enjoy using
• but I
a
lso like to work on low-level things
• so I use C
• but do I re
a
lly need to?
[2025 edition]
My Dilemma
• Ruby is
a
notoriously high level
progr
a
mming l
a
ngu
a
ge
•
a
nd it's the one I most enjoy using
• but I
a
lso like to work on low-level things
• so I use Go
• but do I re
a
lly need to?
Ruby 1.9 could get pretty freaky
Semaphores with Kernel::syscall
[Ruby 1.9]
process 1
require ‘fcntl’
Open = 268
W
a
it = 271
Post = 273
Close = 269
s = sysc
a
ll Open, “/tmp/s”, Fcntl::O_CREAT, 1911
sysc
a
ll W
a
it, s
puts “locked
a
t #{Time.now}”
sleep 50
puts “posted
a
t #{Time.now}”
sysc
a
ll Post, s
sysc
a
ll Close, s
produces:
locked
a
t Thu M
a
y 28 01:03:23 +0100 2009
posted
a
t Thu M
a
y 28 01:04:13 +0100 2009
process 2
Open = 268
W
a
it = 271
TryW
a
it = 272
s = sysc
a
ll Open, “/tmp/s”
begin
t = Time.now
sysc
a
ll TryW
a
it, s
puts “locked
a
t #{t}”
rescue Exception => e
puts “busy
a
t #{t}”
sysc
a
ll W
a
it, s
puts “w
a
ited #{Time.now - t} seconds”
end
produces:
busy
a
t Thu M
a
y 28 01:03:36 +0100 2009
w
a
ited 47.056508 seconds
so what about Ruby 3.4?
Semaphores with Kernel::syscall
[Ruby 3.4]
process 1
require ‘fcntl’
Open = 268
W
a
it = 271
Post = 273
Close = 269
s = sysc
a
ll Open, “/tmp/s”, Fcntl::O_CREAT, 1911
sysc
a
ll W
a
it, s
puts “locked
a
t #{Time.now}”
sleep 50
puts “posted
a
t #{Time.now}”
sysc
a
ll Post, s
sysc
a
ll Close, s
produces:
01
a
.rb:6:in '<m
a
in>': sysc
a
ll() function is unimplemented on this m
a
chine
(NotImplementedError)
from 01
a
.rb:6:in '<m
a
in>'
process 2
Open = 268
W
a
it = 271
TryW
a
it = 272
s = sysc
a
ll Open, “/tmp/s”
begin
t = Time.now
sysc
a
ll TryW
a
it, s
puts “locked
a
t #{t}”
rescue Exception => e
puts “busy
a
t #{t}”
sysc
a
ll W
a
it, s
puts “w
a
ited #{Time.now - t} seconds”
end
produces:
01b.rb:5:in '<m
a
in>': sysc
a
ll() function is unimplemented on this m
a
chine
(NotImplementedError)
from 01b.rb:5:in '<m
a
in>'
Semaphores with Kernel::syscall
[Ruby 3.4]
process 1
require ‘fcntl’
Open = 268
W
a
it = 271
Post = 273
Close = 269
s = sysc
a
ll Open, “/tmp/s”, Fcntl::O_CREAT, 1911
sysc
a
ll W
a
it, s
puts “locked
a
t #{Time.now}”
sleep 50
puts “posted
a
t #{Time.now}”
sysc
a
ll Post, s
sysc
a
ll Close, s
produces:
01
a
.rb:6:in '<m
a
in>': sysc
a
ll() function is unimplemented on this m
a
chine
(NotImplementedError)
from 01
a
.rb:6:in '<m
a
in>'
process 2
Open = 268
W
a
it = 271
TryW
a
it = 272
Post = 273
s = sysc
a
ll Open, “/tmp/s”
begin
t = Time.now
sysc
a
ll TryW
a
it, s
puts “locked
a
t #{t}”
rescue Exception => e
puts “busy
a
t #{t}”
sysc
a
ll W
a
it, s
puts “w
a
ited #{Time.now - t} seconds”
end
produces:
01b.rb:5:in '<m
a
in>': sysc
a
ll() function is unimplemented on this m
a
chine
(NotImplementedError)
from 01b.rb:5:in '<m
a
in>'
sysc
a
ll() function is unimplemented on this m
a
chine
Not
implemented on
all platforms...
linux 32-bit
macOS 15.3 64-bit
Windows 11 64-bit
dynamic library loading with DL
[Ruby 1.9]
process 1
require ‘dl’
require ‘fcntl’
LIBC = DL::dlopen ‘libc.dylib’
open = LIBC[‘sem_open’, ‘ISII’]
try_w
a
it = LIBC[‘sem_tryw
a
it’, ‘II’]
w
a
it = LIBC[‘sem_w
a
it’, ‘II’]
post = LIBC[‘sem_post’, ‘II’]
close = LIBC[‘sem_close’, ‘II’]
s = open.c
a
ll(“/tmp/s”, Fcntl::O_CREAT, 1911)[0]
w
a
it.c
a
ll s
puts “locked
a
t #{Time.now}”
sleep 50
puts “posted
a
t #{Time.now}”
post.c
a
ll s
close.c
a
ll s
=> locked
a
t Thu M
a
y 28 01:03:23 +0100 2009
=> posted
a
t Thu M
a
y 28 01:04:13 +0100 2009
process 2
require ‘dl’
require ‘fcntl’
LIBC = DL::dlopen ‘libc.dylib’
open = LIBC[‘sem_open’, ‘ISII’]
try_w
a
it = LIBC[‘sem_tryw
a
it’, ‘II’]
w
a
it = LIBC[‘sem_w
a
it’, ‘II’]
post = LIBC[‘sem_post’, ‘II’]
close = LIBC[‘sem_close’, ‘II’]
s = open.c
a
ll(“/tmp/s”)
t = Time.now
if try_w
a
it.c
a
ll(s)[0] == 0 then
puts “locked
a
t #{t}”
else
puts “busy
a
t #{t}”
w
a
it.c
a
ll s
puts “w
a
ited #{Time.now - t} seconds”
end
=> busy
a
t Thu M
a
y 28 01:03:36 +0100 2009
=> w
a
ited 47.056508 seconds
FFI foreign functions with Fiddle
[Ruby 3.4]
require ‘
f
iddle’
require ‘fcntl’
LIBC = Fiddle::dlopen 'libc++.dylib'
Open = Fiddle::Function.new(
LIBC['sem_open'],
[Fiddle::TYPE_CONST_STRING,
Fiddle::TYPE_INT,
Fiddle::TYPE_INT,
Fiddle::TYPE_UINT],
Fiddle::TYPE_VOIDP)
TryW
a
it = Fiddle::Function.new(
LIBC['sem_tryw
a
it'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
W
a
it = Fiddle::Function.new(
LIBC['sem_w
a
it'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
Post = Fiddle::Function.new(
LIBC['sem_post'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
Close = Fiddle::Function.new(
LIBC['sem_close'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
def report m, r = 0
puts "#{Time.now}: #{m}"
if r != 0
e = Fiddle::l
a
st_error
puts "terror = #{Errors[e]} [#{e}]"
end
end
process 1
report "cre
a
ting sem
a
phore"
s = Open.c
a
ll "/tmp/s", Fcntl::O_CREAT |
Fcntl::O_RDWR, 777, 0
puts s.inspect
report "sem
a
phore cre
a
ted"
sleep 15
r = Post.c
a
ll s
report "posted", r
sleep 5
t = Time.now
r = W
a
it.c
a
ll s
report "w
a
ited #{Time.now - t} seconds", r
r = Close.c
a
ll s
report "sem
a
phore destroyed"
FFI foreign functions with Fiddle
[Ruby 3.4]
require ‘
f
iddle’
require ‘fcntl’
LIBC = Fiddle::dlopen 'libc++.dylib'
Open = Fiddle::Function.new(
LIBC['sem_open'],
[Fiddle::TYPE_CONST_STRING,
Fiddle::TYPE_INT,
Fiddle::TYPE_INT,
Fiddle::TYPE_UINT],
Fiddle::TYPE_VOIDP)
TryW
a
it = Fiddle::Function.new(
LIBC['sem_tryw
a
it'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
W
a
it = Fiddle::Function.new(
LIBC['sem_w
a
it'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
Post = Fiddle::Function.new(
LIBC['sem_post'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
Close = Fiddle::Function.new(
LIBC['sem_close'],
[Fiddle::TYPE_VOIDP],
Fiddle::TYPE_INT)
def report m, r = 0
puts "#{Time.now}: #{m}"
if r != 0
e = Fiddle::l
a
st_error
puts "terror = #{Errors[e]} [#{e}]"
end
end
process 2
report "opening sem
a
phore"
s = Open.c
a
ll "/tmp/s"
puts s.inspect
r = TryW
a
it.c
a
ll s
report "locked"
if r then
report "busy", r
t = Time.now
r = W
a
it.c
a
ll s
report "w
a
ited #{Time.now - t}s", r
end
sleep 10
report "posted", Post.c
a
ll(s)
[Ruby 1.9]
require ‘dl’
memory_bu
ff
er = DL::m
a
lloc 20
=> #<DL::PtrD
a
t
a
:0x2d0870 ptr=0x820600 size=20 free=0x1b0257>
memory_bu
ff
er[0] = “hello world!”
=> “hello world!000000000000000000000000"
memory_bu
ff
er.free
=> #<DL::Symbol:0x40b760 func=0x1b0257 'void (free)(void *);'>
memory_bu
ff
er.nil
=> nil
malloc = fun
[Ruby 1.9]
string = “hello ruby”
memory_bu
ff
er = string.to_ptr
=> #<DL::PtrD
a
t
a
:0x41be
a
0 ptr=0x41be60 size=10 free=0x1b0257>
memory_bu
ff
er[0] = “goodbye world”
memory_bu
ff
er += 1
=> #<DL::PtrD
a
t
a
:0x422000 ptr=0x41be61 size=9 free=0x0>
puts memory_bu
ff
er, memory_bu
ff
er.to_str, string
=> “oodbye world”
=> “oodbye wo”
=> “hello ruby”
memory_bu
ff
er -= 1
=> (irb):51: [BUG] Segment
a
tion f
a
ult
...and frustration
[Ruby 1.9]
Sign
a
l.tr
a
p(:SEGV) { $stderr.puts "segf
a
ult triggered" }
Process.kill :SEGV, 0
$stderr.puts "but I c
a
rry on
a
s usu
a
l"
require 'dl'
memory = DL::m
a
lloc 1
4096.times { |i| memory[0] = 42.chr * i }
$stderr.puts "even genuine segf
a
ults don't ph
a
se me"
should produce:
segf
a
ult triggered
but I c
a
rry on
a
s usu
a
l
but we can
fi
x that?
[Ruby 1.9]
Sign
a
l.tr
a
p(:SEGV) { $stderr.puts "segf
a
ult triggered" }
Process.kill :SEGV, 0
but we can
fi
x that?
SIGSEGV in not
a
tr
a
pp
a
ble sign
a
l
[Ruby 3.4]
Sign
a
l.tr
a
p(:SEGV) { $stderr.puts "segf
a
ult triggered" }
Process.kill :SEGV, 0
but we can
fi
x that?
a
nd it prob
a
bly never will be
[Ruby 1.9]
require 'dl'
require ‘nevers
a
ydie’
memory = DL::m
a
lloc 1
4096.times do |i|
begin
puts "#{i} : #{(memory[1] = 42.chr * i).length}"
rescue NeverS
a
yDie => e
$stderr.puts "even genuine segf
a
ults don't ph
a
se me"
bre
a
k
end
end
produces:
even genuine segf
a
ults don't ph
a
se me
maybe with some tenderlove?
wr
a
ps GNU libsigsegv
a
ctu
a
lly works
[Ruby 3.4] https://github.com/tenderlove/neversaydie
gem inst
a
ll nevers
a
ydie
maybe with some tenderlove?
nevers
a
ydie doesn't build
uses CONFIG r
a
ther th
a
n RbCon
f
ig
[Ruby 1.9]
require 'dl'
SIGSEGV = DL::dlopen('libsigsegv.dylib')
inst
a
ll_h
a
ndler = SIGSEGV['sigsegv_inst
a
ll_h
a
ndler', 'IP']
deinst
a
ll_h
a
ndler = SIGSEGV['sigsegv_deinst
a
ll_h
a
ndler', '0']
le
a
ve_h
a
ndler = SIGSEGV['sigsegv_le
a
ve_h
a
ndler', 'IPPPP']
continu
a
tion = DL.c
a
llb
a
ck('IPPP') do |
a
ddress, b, c|
r
a
ise RuntimeError, "segf
a
ult
a
t #{
a
ddress}"
end
h
a
ndler = DL.c
a
llb
a
ck('IPI') do |f
a
ult_
a
ddress, serious|
le
a
ve_h
a
ndler.c
a
ll continu
a
tion, f
a
ult_
a
ddress, nil, nil
end
inst
a
ll_h
a
ndler.c
a
ll h
a
ndler
could this instead be done with DL?
[Ruby 1.9]
require 'dl'
SIGSEGV = DL::dlopen('libsigsegv.dylib')
inst
a
ll_h
a
ndler = SIGSEGV['sigsegv_inst
a
ll_h
a
ndler', 'IP']
deinst
a
ll_h
a
ndler = SIGSEGV['sigsegv_deinst
a
ll_h
a
ndler', '0']
le
a
ve_h
a
ndler = SIGSEGV['sigsegv_le
a
ve_h
a
ndler', 'IPPPP']
continu
a
tion = DL.c
a
llb
a
ck('IPPP') do |
a
ddress, b, c|
r
a
ise RuntimeError, "segf
a
ult
a
t #{
a
ddress}"
end
h
a
ndler = DL.c
a
llb
a
ck('IPI') do |f
a
ult_
a
ddress, serious|
le
a
ve_h
a
ndler.c
a
ll continu
a
tion, f
a
ult_
a
ddress, nil, nil
end
inst
a
ll_h
a
ndler.c
a
ll h
a
ndler
could this instead be done with DL?
NO!!!!
the registered h
a
ndler is never c
a
lled
watch this space
• https://github.com/tenderlove/nevers
a
ydie
• https://slidesh
a
re.net/feyele
a
nor
further reading

More Related Content

PDF
An (abridged) Ruby Plumber's Guide to *nix
PDF
it's only abuse if it crashes
KEY
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
PPTX
No Callbacks, No Threads - RailsConf 2010
PDF
Low latency in managed code
KEY
Do more than one thing at the same time, the Python way
PDF
The Ring programming language version 1.6 book - Part 48 of 189
PPTX
loopsnote................, b .pptx
An (abridged) Ruby Plumber's Guide to *nix
it's only abuse if it crashes
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
No Callbacks, No Threads - RailsConf 2010
Low latency in managed code
Do more than one thing at the same time, the Python way
The Ring programming language version 1.6 book - Part 48 of 189
loopsnote................, b .pptx

Similar to Never Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales (20)

PDF
drb09
PPTX
MUST CS101 Lab11
PDF
Microarmy - by J2 Labs
KEY
Rubymotion talk
KEY
Servers with Event Machine - David Troy - RailsConf 2011
PDF
Talk Code
PDF
Concurrency: Rubies, plural
PDF
Concurrency: Rubies, Plural
PDF
Ruby Topic Maps Tutorial (2007-10-10)
PDF
Hidden Gems of Ruby 1.9
PPTX
Power of linked list
PDF
Ruxmon cve 2012-2661
PDF
Ruby.new @ VilniusRB
PDF
The Ring programming language version 1.5.1 book - Part 44 of 180
PDF
The Ring programming language version 1.6 book - Part 29 of 189
PDF
Symfony & Javascript. Combining the best of two worlds
PDF
Node.js Event Loop & EventEmitter
PDF
The Ring programming language version 1.9 book - Part 56 of 210
PPTX
Tokyo APAC Groundbreakers tour - The Complete Java Developer
KEY
Playing With Fire - An Introduction to Node.js
drb09
MUST CS101 Lab11
Microarmy - by J2 Labs
Rubymotion talk
Servers with Event Machine - David Troy - RailsConf 2011
Talk Code
Concurrency: Rubies, plural
Concurrency: Rubies, Plural
Ruby Topic Maps Tutorial (2007-10-10)
Hidden Gems of Ruby 1.9
Power of linked list
Ruxmon cve 2012-2661
Ruby.new @ VilniusRB
The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.6 book - Part 29 of 189
Symfony & Javascript. Combining the best of two worlds
Node.js Event Loop & EventEmitter
The Ring programming language version 1.9 book - Part 56 of 210
Tokyo APAC Groundbreakers tour - The Complete Java Developer
Playing With Fire - An Introduction to Node.js
Ad

More from Eleanor McHugh (20)

PDF
Go for the Paranoid Network Programmer, 2025 Edition
PDF
Y - Recursion The Hard Way GopherCon EU 2025
PDF
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
PDF
[2023] Putting the R! in R&D.pdf
PDF
Generics, Reflection, and Efficient Collections
PDF
The Relevance of Liveness - Biometrics and Data Integrity
PDF
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
PDF
The Browser Environment - A Systems Programmer's Perspective
PDF
Go for the paranoid network programmer, 3rd edition
PDF
An introduction to functional programming with Go [redux]
PDF
An introduction to functional programming with go
PDF
Implementing virtual machines in go & c 2018 redux
PDF
Identity & trust in Monitored Spaces
PDF
Don't Ask, Don't Tell - The Virtues of Privacy By Design
PDF
Don't ask, don't tell the virtues of privacy by design
PDF
Anonymity, identity, trust
PDF
Going Loopy - Adventures in Iteration with Google Go
PDF
Distributed Ledgers: Anonymity & Immutability at Scale
PDF
Hello Go
PDF
Go for the paranoid network programmer, 2nd edition
Go for the Paranoid Network Programmer, 2025 Edition
Y - Recursion The Hard Way GopherCon EU 2025
[2024] An Introduction to Functional Programming with Go [Y Combinator Remix]...
[2023] Putting the R! in R&D.pdf
Generics, Reflection, and Efficient Collections
The Relevance of Liveness - Biometrics and Data Integrity
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective
Go for the paranoid network programmer, 3rd edition
An introduction to functional programming with Go [redux]
An introduction to functional programming with go
Implementing virtual machines in go & c 2018 redux
Identity & trust in Monitored Spaces
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't ask, don't tell the virtues of privacy by design
Anonymity, identity, trust
Going Loopy - Adventures in Iteration with Google Go
Distributed Ledgers: Anonymity & Immutability at Scale
Hello Go
Go for the paranoid network programmer, 2nd edition
Ad

Recently uploaded (20)

PDF
MENA-ECEONOMIC-CONTEXT-VC MENA-ECEONOMIC
DOCX
Basics of Cloud Computing - Cloud Ecosystem
PPTX
MuleSoft-Compete-Deck for midddleware integrations
PDF
Data Virtualization in Action: Scaling APIs and Apps with FME
PDF
zbrain.ai-Scope Key Metrics Configuration and Best Practices.pdf
PDF
Electrocardiogram sequences data analytics and classification using unsupervi...
PDF
Connector Corner: Transform Unstructured Documents with Agentic Automation
PDF
Dell Pro Micro: Speed customer interactions, patient processing, and learning...
PDF
CXOs-Are-you-still-doing-manual-DevOps-in-the-age-of-AI.pdf
PDF
Planning-an-Audit-A-How-To-Guide-Checklist-WP.pdf
PDF
Advancing precision in air quality forecasting through machine learning integ...
PDF
Co-training pseudo-labeling for text classification with support vector machi...
PDF
The-2025-Engineering-Revolution-AI-Quality-and-DevOps-Convergence.pdf
PDF
Build Real-Time ML Apps with Python, Feast & NoSQL
PDF
4 layer Arch & Reference Arch of IoT.pdf
PDF
SaaS reusability assessment using machine learning techniques
PPTX
SGT Report The Beast Plan and Cyberphysical Systems of Control
PDF
CEH Module 2 Footprinting CEH V13, concepts
PDF
“The Future of Visual AI: Efficient Multimodal Intelligence,” a Keynote Prese...
PDF
IT-ITes Industry bjjbnkmkhkhknbmhkhmjhjkhj
MENA-ECEONOMIC-CONTEXT-VC MENA-ECEONOMIC
Basics of Cloud Computing - Cloud Ecosystem
MuleSoft-Compete-Deck for midddleware integrations
Data Virtualization in Action: Scaling APIs and Apps with FME
zbrain.ai-Scope Key Metrics Configuration and Best Practices.pdf
Electrocardiogram sequences data analytics and classification using unsupervi...
Connector Corner: Transform Unstructured Documents with Agentic Automation
Dell Pro Micro: Speed customer interactions, patient processing, and learning...
CXOs-Are-you-still-doing-manual-DevOps-in-the-age-of-AI.pdf
Planning-an-Audit-A-How-To-Guide-Checklist-WP.pdf
Advancing precision in air quality forecasting through machine learning integ...
Co-training pseudo-labeling for text classification with support vector machi...
The-2025-Engineering-Revolution-AI-Quality-and-DevOps-Convergence.pdf
Build Real-Time ML Apps with Python, Feast & NoSQL
4 layer Arch & Reference Arch of IoT.pdf
SaaS reusability assessment using machine learning techniques
SGT Report The Beast Plan and Cyberphysical Systems of Control
CEH Module 2 Footprinting CEH V13, concepts
“The Future of Visual AI: Efficient Multimodal Intelligence,” a Keynote Prese...
IT-ITes Industry bjjbnkmkhkhknbmhkhmjhjkhj

Never Say, Never Say Die! - the art of low-level Ruby and other Macabre Tales

  • 1. slideshare://feyeleanor the art of low-level ruby and other macabre tales Eleanor McHugh Never Say, "Never Say Die!"
  • 2. [2001 edition] My Dilemma • Ruby is a notoriously high level progr a mming l a ngu a ge • a nd it's the one I most enjoy using • but I a lso like to work on low-level things • so I use C • but do I re a lly need to?
  • 3. [2025 edition] My Dilemma • Ruby is a notoriously high level progr a mming l a ngu a ge • a nd it's the one I most enjoy using • but I a lso like to work on low-level things • so I use Go • but do I re a lly need to?
  • 4. Ruby 1.9 could get pretty freaky
  • 5. Semaphores with Kernel::syscall [Ruby 1.9] process 1 require ‘fcntl’ Open = 268 W a it = 271 Post = 273 Close = 269 s = sysc a ll Open, “/tmp/s”, Fcntl::O_CREAT, 1911 sysc a ll W a it, s puts “locked a t #{Time.now}” sleep 50 puts “posted a t #{Time.now}” sysc a ll Post, s sysc a ll Close, s produces: locked a t Thu M a y 28 01:03:23 +0100 2009 posted a t Thu M a y 28 01:04:13 +0100 2009 process 2 Open = 268 W a it = 271 TryW a it = 272 s = sysc a ll Open, “/tmp/s” begin t = Time.now sysc a ll TryW a it, s puts “locked a t #{t}” rescue Exception => e puts “busy a t #{t}” sysc a ll W a it, s puts “w a ited #{Time.now - t} seconds” end produces: busy a t Thu M a y 28 01:03:36 +0100 2009 w a ited 47.056508 seconds
  • 6. so what about Ruby 3.4?
  • 7. Semaphores with Kernel::syscall [Ruby 3.4] process 1 require ‘fcntl’ Open = 268 W a it = 271 Post = 273 Close = 269 s = sysc a ll Open, “/tmp/s”, Fcntl::O_CREAT, 1911 sysc a ll W a it, s puts “locked a t #{Time.now}” sleep 50 puts “posted a t #{Time.now}” sysc a ll Post, s sysc a ll Close, s produces: 01 a .rb:6:in '<m a in>': sysc a ll() function is unimplemented on this m a chine (NotImplementedError) from 01 a .rb:6:in '<m a in>' process 2 Open = 268 W a it = 271 TryW a it = 272 s = sysc a ll Open, “/tmp/s” begin t = Time.now sysc a ll TryW a it, s puts “locked a t #{t}” rescue Exception => e puts “busy a t #{t}” sysc a ll W a it, s puts “w a ited #{Time.now - t} seconds” end produces: 01b.rb:5:in '<m a in>': sysc a ll() function is unimplemented on this m a chine (NotImplementedError) from 01b.rb:5:in '<m a in>'
  • 8. Semaphores with Kernel::syscall [Ruby 3.4] process 1 require ‘fcntl’ Open = 268 W a it = 271 Post = 273 Close = 269 s = sysc a ll Open, “/tmp/s”, Fcntl::O_CREAT, 1911 sysc a ll W a it, s puts “locked a t #{Time.now}” sleep 50 puts “posted a t #{Time.now}” sysc a ll Post, s sysc a ll Close, s produces: 01 a .rb:6:in '<m a in>': sysc a ll() function is unimplemented on this m a chine (NotImplementedError) from 01 a .rb:6:in '<m a in>' process 2 Open = 268 W a it = 271 TryW a it = 272 Post = 273 s = sysc a ll Open, “/tmp/s” begin t = Time.now sysc a ll TryW a it, s puts “locked a t #{t}” rescue Exception => e puts “busy a t #{t}” sysc a ll W a it, s puts “w a ited #{Time.now - t} seconds” end produces: 01b.rb:5:in '<m a in>': sysc a ll() function is unimplemented on this m a chine (NotImplementedError) from 01b.rb:5:in '<m a in>' sysc a ll() function is unimplemented on this m a chine
  • 9. Not implemented on all platforms... linux 32-bit macOS 15.3 64-bit Windows 11 64-bit
  • 10. dynamic library loading with DL [Ruby 1.9] process 1 require ‘dl’ require ‘fcntl’ LIBC = DL::dlopen ‘libc.dylib’ open = LIBC[‘sem_open’, ‘ISII’] try_w a it = LIBC[‘sem_tryw a it’, ‘II’] w a it = LIBC[‘sem_w a it’, ‘II’] post = LIBC[‘sem_post’, ‘II’] close = LIBC[‘sem_close’, ‘II’] s = open.c a ll(“/tmp/s”, Fcntl::O_CREAT, 1911)[0] w a it.c a ll s puts “locked a t #{Time.now}” sleep 50 puts “posted a t #{Time.now}” post.c a ll s close.c a ll s => locked a t Thu M a y 28 01:03:23 +0100 2009 => posted a t Thu M a y 28 01:04:13 +0100 2009 process 2 require ‘dl’ require ‘fcntl’ LIBC = DL::dlopen ‘libc.dylib’ open = LIBC[‘sem_open’, ‘ISII’] try_w a it = LIBC[‘sem_tryw a it’, ‘II’] w a it = LIBC[‘sem_w a it’, ‘II’] post = LIBC[‘sem_post’, ‘II’] close = LIBC[‘sem_close’, ‘II’] s = open.c a ll(“/tmp/s”) t = Time.now if try_w a it.c a ll(s)[0] == 0 then puts “locked a t #{t}” else puts “busy a t #{t}” w a it.c a ll s puts “w a ited #{Time.now - t} seconds” end => busy a t Thu M a y 28 01:03:36 +0100 2009 => w a ited 47.056508 seconds
  • 11. FFI foreign functions with Fiddle [Ruby 3.4] require ‘ f iddle’ require ‘fcntl’ LIBC = Fiddle::dlopen 'libc++.dylib' Open = Fiddle::Function.new( LIBC['sem_open'], [Fiddle::TYPE_CONST_STRING, Fiddle::TYPE_INT, Fiddle::TYPE_INT, Fiddle::TYPE_UINT], Fiddle::TYPE_VOIDP) TryW a it = Fiddle::Function.new( LIBC['sem_tryw a it'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) W a it = Fiddle::Function.new( LIBC['sem_w a it'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) Post = Fiddle::Function.new( LIBC['sem_post'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) Close = Fiddle::Function.new( LIBC['sem_close'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) def report m, r = 0 puts "#{Time.now}: #{m}" if r != 0 e = Fiddle::l a st_error puts "terror = #{Errors[e]} [#{e}]" end end process 1 report "cre a ting sem a phore" s = Open.c a ll "/tmp/s", Fcntl::O_CREAT | Fcntl::O_RDWR, 777, 0 puts s.inspect report "sem a phore cre a ted" sleep 15 r = Post.c a ll s report "posted", r sleep 5 t = Time.now r = W a it.c a ll s report "w a ited #{Time.now - t} seconds", r r = Close.c a ll s report "sem a phore destroyed"
  • 12. FFI foreign functions with Fiddle [Ruby 3.4] require ‘ f iddle’ require ‘fcntl’ LIBC = Fiddle::dlopen 'libc++.dylib' Open = Fiddle::Function.new( LIBC['sem_open'], [Fiddle::TYPE_CONST_STRING, Fiddle::TYPE_INT, Fiddle::TYPE_INT, Fiddle::TYPE_UINT], Fiddle::TYPE_VOIDP) TryW a it = Fiddle::Function.new( LIBC['sem_tryw a it'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) W a it = Fiddle::Function.new( LIBC['sem_w a it'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) Post = Fiddle::Function.new( LIBC['sem_post'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) Close = Fiddle::Function.new( LIBC['sem_close'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) def report m, r = 0 puts "#{Time.now}: #{m}" if r != 0 e = Fiddle::l a st_error puts "terror = #{Errors[e]} [#{e}]" end end process 2 report "opening sem a phore" s = Open.c a ll "/tmp/s" puts s.inspect r = TryW a it.c a ll s report "locked" if r then report "busy", r t = Time.now r = W a it.c a ll s report "w a ited #{Time.now - t}s", r end sleep 10 report "posted", Post.c a ll(s)
  • 13. [Ruby 1.9] require ‘dl’ memory_bu ff er = DL::m a lloc 20 => #<DL::PtrD a t a :0x2d0870 ptr=0x820600 size=20 free=0x1b0257> memory_bu ff er[0] = “hello world!” => “hello world!000000000000000000000000" memory_bu ff er.free => #<DL::Symbol:0x40b760 func=0x1b0257 'void (free)(void *);'> memory_bu ff er.nil => nil malloc = fun
  • 14. [Ruby 1.9] string = “hello ruby” memory_bu ff er = string.to_ptr => #<DL::PtrD a t a :0x41be a 0 ptr=0x41be60 size=10 free=0x1b0257> memory_bu ff er[0] = “goodbye world” memory_bu ff er += 1 => #<DL::PtrD a t a :0x422000 ptr=0x41be61 size=9 free=0x0> puts memory_bu ff er, memory_bu ff er.to_str, string => “oodbye world” => “oodbye wo” => “hello ruby” memory_bu ff er -= 1 => (irb):51: [BUG] Segment a tion f a ult ...and frustration
  • 15. [Ruby 1.9] Sign a l.tr a p(:SEGV) { $stderr.puts "segf a ult triggered" } Process.kill :SEGV, 0 $stderr.puts "but I c a rry on a s usu a l" require 'dl' memory = DL::m a lloc 1 4096.times { |i| memory[0] = 42.chr * i } $stderr.puts "even genuine segf a ults don't ph a se me" should produce: segf a ult triggered but I c a rry on a s usu a l but we can fi x that?
  • 16. [Ruby 1.9] Sign a l.tr a p(:SEGV) { $stderr.puts "segf a ult triggered" } Process.kill :SEGV, 0 but we can fi x that? SIGSEGV in not a tr a pp a ble sign a l
  • 17. [Ruby 3.4] Sign a l.tr a p(:SEGV) { $stderr.puts "segf a ult triggered" } Process.kill :SEGV, 0 but we can fi x that? a nd it prob a bly never will be
  • 18. [Ruby 1.9] require 'dl' require ‘nevers a ydie’ memory = DL::m a lloc 1 4096.times do |i| begin puts "#{i} : #{(memory[1] = 42.chr * i).length}" rescue NeverS a yDie => e $stderr.puts "even genuine segf a ults don't ph a se me" bre a k end end produces: even genuine segf a ults don't ph a se me maybe with some tenderlove? wr a ps GNU libsigsegv a ctu a lly works
  • 19. [Ruby 3.4] https://github.com/tenderlove/neversaydie gem inst a ll nevers a ydie maybe with some tenderlove? nevers a ydie doesn't build uses CONFIG r a ther th a n RbCon f ig
  • 20. [Ruby 1.9] require 'dl' SIGSEGV = DL::dlopen('libsigsegv.dylib') inst a ll_h a ndler = SIGSEGV['sigsegv_inst a ll_h a ndler', 'IP'] deinst a ll_h a ndler = SIGSEGV['sigsegv_deinst a ll_h a ndler', '0'] le a ve_h a ndler = SIGSEGV['sigsegv_le a ve_h a ndler', 'IPPPP'] continu a tion = DL.c a llb a ck('IPPP') do | a ddress, b, c| r a ise RuntimeError, "segf a ult a t #{ a ddress}" end h a ndler = DL.c a llb a ck('IPI') do |f a ult_ a ddress, serious| le a ve_h a ndler.c a ll continu a tion, f a ult_ a ddress, nil, nil end inst a ll_h a ndler.c a ll h a ndler could this instead be done with DL?
  • 21. [Ruby 1.9] require 'dl' SIGSEGV = DL::dlopen('libsigsegv.dylib') inst a ll_h a ndler = SIGSEGV['sigsegv_inst a ll_h a ndler', 'IP'] deinst a ll_h a ndler = SIGSEGV['sigsegv_deinst a ll_h a ndler', '0'] le a ve_h a ndler = SIGSEGV['sigsegv_le a ve_h a ndler', 'IPPPP'] continu a tion = DL.c a llb a ck('IPPP') do | a ddress, b, c| r a ise RuntimeError, "segf a ult a t #{ a ddress}" end h a ndler = DL.c a llb a ck('IPI') do |f a ult_ a ddress, serious| le a ve_h a ndler.c a ll continu a tion, f a ult_ a ddress, nil, nil end inst a ll_h a ndler.c a ll h a ndler could this instead be done with DL? NO!!!! the registered h a ndler is never c a lled