Skip to content

Commit 6603100

Browse files
committed
Add a CI for increase_default_stack_size.sh
This runs whenever the script is modified, or weekly to ensure the CI doesn't inadvertently decay (due to using the latest packages for a variety of shells). This runs with `sh` (presumably `dash`), `ksh`, `bash`, `dash` (explicitly), `zsh`, `ash` (Busybox), `hush` (Busybox), `mksh`, `yash`, and `brush`. While none of these guarantee this script is POSIX-compliant, as a fully and explicitly-only POSIX-compliant environment is not constructed, this does reasonably test the script itself to be POSIX-compliant. The tools called have been reviewed for being used to the POSIX standard (although not audited to that degree). The script itself is modified with the following changes for compliance with POSIX: 1) `hexdump` is replaced with `od` (`od` suggested by @PlasmaPower) 2) `printf \xFF` replaced with octal escapes, as `\x` is not part of POSIX 3) `head -c` is replaced with `cut`, as the `-c` option is not standardized under POSIX (despite it being present for `tail`). This was identified by @PlasmaPower. As we used `head -c-2` to truncate the last two characters of a string, we now use `wc -c` for a `strlen` to enable the necessary arithmetic to calculate what two bytes in from the end of the string is. This entire effort can be argued pointless, as we could simply run `monerod` on Debian. This script is useful, the journey down the rabbithole of POSIX compliance fascinating, and the methodology applicable to other potential futures though (whether running binaries on Alpine or testing other `sh` scripts for their portability). As part of this effort overall, our CI was extended with `shellcheck` for all `sh` scripts in-tree, including all of our existing `sh` scripts. That there is an actual, direct benefit past this specific effort.
1 parent f70fee6 commit 6603100

4 files changed

Lines changed: 110 additions & 8 deletions

File tree

.github/actions/build-dependencies/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ runs:
6262
docker system prune -a --volumes
6363
sudo apt remove -y *docker*
6464
# Install uidmap which will be required for the explicitly installed Docker
65-
sudo apt install uidmap
65+
sudo apt install -y uidmap
6666
if: runner.os == 'Linux'
6767

6868
- name: Update system dependencies

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ jobs:
208208
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
209209
- name: shellcheck
210210
run: |
211-
sudo apt install shellcheck
211+
sudo apt install -y shellcheck
212212
find . -iname "*.sh" | while read -r script; do
213213
shellcheck --enable=all --shell=sh --severity=info $script
214214
done

.github/workflows/stack_size.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: Check Update Default Stack Size
2+
3+
on:
4+
push:
5+
paths:
6+
- "orchestration/increase_default_stack_size.sh"
7+
pull_request:
8+
paths:
9+
- "orchestration/increase_default_stack_size.sh"
10+
workflow_dispatch:
11+
# Also run weekly to ensure this doesn't inadvertently decay
12+
schedule:
13+
- cron: "0 0 * * 1"
14+
15+
jobs:
16+
stack_size:
17+
strategy:
18+
matrix:
19+
os: [ubuntu-latest, ubuntu-24.04, ubuntu-22.04]
20+
runs-on: ${{ matrix.os }}
21+
22+
steps:
23+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
24+
25+
- name: Download Monero
26+
uses: ./.github/actions/monero
27+
28+
- name: Verify expected behavior
29+
shell: bash
30+
run: |
31+
cp /usr/bin/monerod monerod
32+
33+
STACK=$((8 * 1024 * 1024))
34+
35+
cp monerod monerod-chelf
36+
git clone https://github.com/Gottox/chelf
37+
cd chelf
38+
git checkout b2994186cea7b7d61a588fd06c1cc1ae75bcc21a
39+
make
40+
./chelf -s $STACK ../monerod-chelf
41+
cd ..
42+
43+
cp monerod monerod-muslstack
44+
GOBIN=$(pwd) go install github.com/yaegashi/muslstack@d19cc5866abce3ca59dfc1666df7cc97097d0933
45+
./muslstack -s $STACK ./monerod-muslstack
46+
47+
sudo apt update -y
48+
sudo apt install -y ksh bash dash zsh busybox mksh yash
49+
sudo ln -s $(which busybox) /usr/bin/ash
50+
sudo ln -s $(which busybox) /usr/bin/hush
51+
cargo install brush-shell
52+
for shell in sh ksh bash dash zsh ash hush mksh yash brush; do
53+
cp monerod monerod-idss-$shell
54+
ln -s $(which $shell) sh
55+
./sh ./orchestration/increase_default_stack_size.sh monerod-idss-$shell
56+
rm ./sh
57+
done
58+
59+
sha256() {
60+
sha256sum "$1" | cut -d' ' -f1
61+
}
62+
CHELF=$(sha256 monerod-chelf)
63+
find . -iname "monerod-*" | while read -r bin; do
64+
BIN=$(sha256 "$bin")
65+
if [ ! "$CHELF" = "$BIN" ]; then
66+
echo "Different artifact between monerod-chelf ($CHELF) and $bin ($BIN)"
67+
exit 1
68+
fi
69+
done
70+
71+
read_stack() {
72+
STACK_INFO=$(readelf "$1" -l | grep STACK -A1)
73+
MEMSZ=$(echo "$STACK_INFO" | tail -n1 | sed -E s/^[[:space:]]*//g | cut -f2 -d' ')
74+
printf "%i" $((MEMSZ))
75+
}
76+
INITIAL_STACK=$(read_stack monerod)
77+
if [ "$INITIAL_STACK" -ne "0" ]; then
78+
echo "Initial \`PT_GNU_STACK\` wasn't 0"
79+
exit 2
80+
fi
81+
82+
UPDATED_STACK=$(read_stack monerod-chelf)
83+
if [ "$UPDATED_STACK" -ne "$STACK" ]; then
84+
echo "Updated \`PT_GNU_STACK\` ($UPDATED_STACK) wasn't 8 MB ($STACK)"
85+
exit 3
86+
fi
87+
88+
# Only one byte should be different due to the bit pattern of 8 MB
89+
BYTES_DIFFERENT=$(cmp -l monerod monerod-chelf | wc -l || true)
90+
if [ "$BYTES_DIFFERENT" -ne 1 ]; then
91+
echo "More than one byte was different between the two binaries"
92+
exit 4
93+
fi

orchestration/increase_default_stack_size.sh

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,28 @@ hex() {
2626
read_bytes() {
2727
dd bs=1 skip="$1" count="$2" if="$ELF" 2> /dev/null | hex
2828
}
29+
hex_to_octal() {
30+
printf "ibase=16; obase=8; %s\n" "$1" | bc
31+
}
2932
write_bytes() {
3033
POS=$1
3134
BYTES=$2
3235
while [ ! "$BYTES" = "" ]; do
33-
NEXT=$(printf "%s" "$BYTES" | head -c2)
36+
NEXT=$(printf "%s" "$BYTES" | cut -c-2)
3437
# Advance to the third byte, as in, after the first two bytes
3538
BYTES=$(printf "%s" "$BYTES" | tail -c+3)
3639

40+
NEXT=$(hex_to_octal "$NEXT")
3741
# shellcheck disable=SC2059
38-
printf "\x$NEXT" | dd conv=notrunc bs=1 seek="$POS" of="$ELF" 2> /dev/null
42+
printf \\"$NEXT" | dd conv=notrunc bs=1 seek="$POS" of="$ELF" 2> /dev/null
3943
POS=$((POS + 1))
4044
done
4145
}
4246

4347
# Magic
4448
MAGIC=$(read_bytes 0 4)
45-
EXPECTED_MAGIC=$(printf "\x7ELF" | hex)
49+
# shellcheck disable=SC2059
50+
EXPECTED_MAGIC=$(printf \\"$(hex_to_octal 7F)"ELF | hex)
4651
if [ ! "$MAGIC" = "$EXPECTED_MAGIC" ]; then
4752
echo "Not ELF"
4853
exit 2
@@ -101,9 +106,13 @@ swap_native_endian() {
101106
return
102107
fi
103108

104-
while [ ! "$BYTES" = "" ]; do
109+
while :; do
105110
printf "%s" "$BYTES" | tail -c2
106-
BYTES=$(printf "%s" "$BYTES" | head -c-2)
111+
NEW_LENGTH=$(( $(printf "%s" "$BYTES" | wc -c) - 2 ))
112+
if [ "$NEW_LENGTH" -eq 0 ]; then
113+
break
114+
fi
115+
BYTES=$(printf "%s" "$BYTES" | cut -c-$NEW_LENGTH)
107116
done
108117
}
109118

@@ -144,7 +153,7 @@ while [ "$NEXT_PROGRAM_HEADER" -ne -1 ]; do
144153
NEXT_PROGRAM_HEADER=$(( NEXT_PROGRAM_HEADER - 1 ))
145154
PROGRAM_HEADER=$(read_program_header "$THIS_PROGRAM_HEADER")
146155

147-
HEADER_TYPE=$(printf "%s" "$PROGRAM_HEADER" | head -c8)
156+
HEADER_TYPE=$(printf "%s" "$PROGRAM_HEADER" | cut -c-8)
148157
HEADER_TYPE=$(swap_native_endian "$HEADER_TYPE")
149158
# `PT_GNU_STACK`
150159
# https://github.com/torvalds/linux/blob/c2f2b01b74be8b40a2173372bcd770723f87e7b2/include/uapi/linux/elf.h#L41

0 commit comments

Comments
 (0)