Skip to content

Commit faadb1f

Browse files
committed
test: add a script that checks that we do not call unix_select from XAPI and xenopsd
This is somewhat of a hack, as it parses the disassembled binary of xapi and xenopsd, and might break with future compiler versions that invoke functions differently. There could also be false positives if a dependency calls Unix.select for just sleeping, i.e. with all 3 arguments as empty lists, but so far we don't have any. We still have the runtime test if that happens. If the commits are reordered this does find the 'Thread.wait_timed_read' call in 'Master_database_connection', and with the correct order of the commits it passes, offering some assurance that we don't actually call 'select' anymore, not even indirectly via one of our dependencies. Signed-off-by: Edwin Török <[email protected]>
1 parent b804b76 commit faadb1f

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

ocaml/tests/dune

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,41 @@
164164
)
165165

166166
(env (_ (env-vars (XAPI_TEST 1))))
167+
168+
; disassemble, but without sources
169+
; (source lookup doesn't work for all dependencies, and is very slow on a large binary)
170+
; To make debugging easier the disassembly is saved to a file instead of piping
171+
(rule
172+
(deps ../xapi/xapi_main.exe)
173+
(target xapi.disasm)
174+
(package xapi)
175+
(action
176+
(with-stdout-to %{target}
177+
(run objdump %{deps} --wide -d --no-show-raw-insn)
178+
)
179+
)
180+
)
181+
182+
(rule
183+
(deps ../xenopsd/xc/xenops_xc_main.exe)
184+
(target xenops_xc_main.disasm)
185+
(package xapi-xenopsd-xc)
186+
(action
187+
(with-stdout-to %{target}
188+
(run objdump %{deps} --wide -d --no-show-raw-insn)
189+
)
190+
)
191+
)
192+
193+
(rule
194+
(alias runtest)
195+
(package xapi)
196+
(deps (:script ./unix_select.gawk) (:disasm xapi.disasm))
197+
(action (run gawk -f ./%{script} %{disasm}))
198+
)
199+
(rule
200+
(alias runtest)
201+
(package xapi-xenopsd-xc)
202+
(deps (:script ./unix_select.gawk) (:disasm xenops_xc_main.disasm))
203+
(action (run gawk -f ./%{script} %{disasm}))
204+
)

ocaml/tests/unix_select.gawk

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
BEGIN { n = 0; }
2+
# A function definition and its address
3+
# Remember its address and update current symbol
4+
# 0000000000850330 <unix_select>:
5+
match($0, /^0*([0-9a-fA-F]+) <([^>]+)>/, symdef) {
6+
SYMBOL = symdef[2];
7+
ADDR = symdef[1];
8+
9+
SYMADDR[ADDR] = SYMBOL;
10+
11+
if (ADDR in LOADED) {
12+
for (idx in LOADED[ADDR]) {
13+
caller = LOADED[ADDR][idx]
14+
CALLS[symdef[2]][n++] = caller
15+
}
16+
}
17+
}
18+
19+
# Indirect calls (mostly used for C stubs)
20+
# mov $0x850330,%rax
21+
# call 872834 <caml_c_call>
22+
match($0, /mov.*0x([0-9a-fA-F]*),/, addr) {
23+
# this will have gaps, but the indexes will be unique
24+
LOADED[addr[1]][n++] = SYMBOL
25+
}
26+
27+
match($0, /call.*<([^>]+)>/, call) {
28+
CALLS[call[1]][n++] = SYMBOL
29+
}
30+
31+
END {
32+
SYM = "unix_select"
33+
had_calls = 0
34+
if (SYM in CALLS) {
35+
for (idx in CALLS[SYM]) {
36+
caller = CALLS[SYM][idx];
37+
print "--"
38+
if (caller ~ /caml(Thread|Unix__fun_).*/) {
39+
# direct calls from these functions to unix_select are expected
40+
print caller "[expected]"
41+
} else {
42+
print caller "[bad]"
43+
had_calls++
44+
}
45+
if (caller in CALLS) {
46+
for (idx2 in CALLS[caller]) {
47+
caller2 = CALLS[caller][idx2];
48+
if (caller2 ~ /caml(Thread).*/) {
49+
print caller2 "[expected]"
50+
} else {
51+
print caller2 "[bad]"
52+
had_calls++
53+
}
54+
if (caller2 in CALLS) {
55+
for (idx3 in CALLS[caller2]) {
56+
caller3 = CALLS[caller2][idx3];
57+
# but we don't expect anyone calling these functions from OCaml code,
58+
# reject that
59+
had_calls++
60+
print caller3 "[bad]"
61+
if (caller3 in CALLS) {
62+
for (idx4 in CALLS[caller3]) {
63+
caller4 = CALLS[caller3][idx4];
64+
print caller4 "[bad]"
65+
for (idx5 in CALLS[caller4]) {
66+
caller5 = CALLS[caller4][idx5];
67+
print caller5 "[bad]"
68+
}
69+
}
70+
}
71+
}
72+
}
73+
}
74+
}
75+
}
76+
}
77+
if (had_calls > 0) {
78+
exit 2
79+
}
80+
}

0 commit comments

Comments
 (0)