Add coverage for RHEL-45873
binutils: Avoid creating gaps between adjacent LOAD segments
This commit is contained in:
parent
54e002d31a
commit
7391c5eea6
5 changed files with 211 additions and 0 deletions
|
|
@ -0,0 +1,9 @@
|
|||
summary: Avoid creating gaps between adjacent LOAD segments
|
||||
|
||||
duration: 24h
|
||||
|
||||
require+:
|
||||
- rpm-build
|
||||
|
||||
link+:
|
||||
- verifies: https://issues.redhat.com/browse/RHEL-45873
|
||||
89
tests/bugs/Avoid-creating-gaps-between-adjacent-LOAD-segments/repro.sh
Executable file
89
tests/bugs/Avoid-creating-gaps-between-adjacent-LOAD-segments/repro.sh
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
ITER=${1:-10000}
|
||||
|
||||
echo "Testing with $(rpm -q binutils)..."
|
||||
|
||||
pagesz=$(getconf PAGESIZE)
|
||||
echo "Testing with a page size of $pagesz"
|
||||
|
||||
GLIBC_SCRIPTS="$(readlink -f "$(rpm --define="_topdir $TmpDir" --eval=%_builddir)/glibc-*/scripts")"
|
||||
|
||||
test() {
|
||||
y=$(($1 * 7))
|
||||
f=obj$y
|
||||
gcc -O2 -fpie -pie -DN=$y t.c -Wl,-z,relro,-z,now -o $f
|
||||
|
||||
PYTHONPATH="$GLIBC_SCRIPTS:$PYTHONPATH" python tst-load-segment-gaps.py $f >> verbose.log
|
||||
ret=$?
|
||||
|
||||
rm $f
|
||||
return $ret
|
||||
}
|
||||
|
||||
rm -f verbose.log
|
||||
|
||||
cat > t.c <<EOF
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *const array[] = {
|
||||
[N] = "value",
|
||||
};
|
||||
|
||||
#define BUF_SZ 2048
|
||||
|
||||
void pmap() {
|
||||
FILE *f;
|
||||
size_t bytes;
|
||||
char *buffer = malloc(BUF_SZ);
|
||||
if (buffer == NULL)
|
||||
err(EXIT_FAILURE, NULL);
|
||||
|
||||
f = fopen("/proc/self/maps", "r");
|
||||
if (f == NULL)
|
||||
err(EXIT_FAILURE, NULL);
|
||||
|
||||
while ((bytes = fread(buffer, 1, BUF_SZ, f)) > 0)
|
||||
fwrite(buffer, 1, bytes, stdout);
|
||||
|
||||
if (ferror(f))
|
||||
perror(NULL);
|
||||
|
||||
fclose(f);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
prctl(PR_SET_DUMPABLE, 0,0, 0);
|
||||
char **volatile p = (char **)array;
|
||||
pmap();
|
||||
__builtin_puts(p[N]);
|
||||
}
|
||||
EOF
|
||||
|
||||
errors=0
|
||||
|
||||
# Print a blank line that we will rewrite later.
|
||||
echo
|
||||
for x in $(seq $ITER) ; do
|
||||
p=$(($x * 100 / $ITER))
|
||||
echo -e '\e[1A\e[K Progress:' "$p% Errors: $errors"
|
||||
if ! test $x; then
|
||||
errors=$(($errors + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
rm t.c
|
||||
|
||||
if [[ "$errors" -eq 0 ]]; then
|
||||
echo "The test succeeded!"
|
||||
else
|
||||
percent=$(($errors * 100 / $ITER))
|
||||
echo "Error: tests had a $percent% failure rate" >&2
|
||||
exit 1
|
||||
fi
|
||||
28
tests/bugs/Avoid-creating-gaps-between-adjacent-LOAD-segments/test.sh
Executable file
28
tests/bugs/Avoid-creating-gaps-between-adjacent-LOAD-segments/test.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Include Beaker environment
|
||||
. /usr/share/beakerlib/beakerlib.sh || exit 1
|
||||
|
||||
. "$TMT_TREE/tests/lib.sh" || exit 1
|
||||
|
||||
rlJournalStart
|
||||
rlPhaseStartSetup
|
||||
buTestHeader
|
||||
buEnterTmpDir
|
||||
|
||||
buCopyReproducers "repro.sh tst-load-segment-gaps.py"
|
||||
|
||||
buPrepareSRPM "glibc"
|
||||
buConfigureSRPM "glibc"
|
||||
rlRun "tree $TmpDir"
|
||||
rlPhaseEnd
|
||||
|
||||
rlPhaseStartTest
|
||||
rlRun "./repro.sh"
|
||||
rlPhaseEnd
|
||||
|
||||
rlPhaseStartCleanup
|
||||
buExitTmpDir
|
||||
rlPhaseEnd
|
||||
rlJournalPrintText
|
||||
rlJournalEnd
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/python3
|
||||
# Verify that objects do not contain gaps in load segments.
|
||||
# Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
#
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# The GNU C Library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with the GNU C Library; if not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
|
||||
import argparse
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
# Make available glibc Python modules.
|
||||
sys.path.append(os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), os.path.pardir, 'scripts'))
|
||||
|
||||
import glibcelf
|
||||
|
||||
def rounddown(val, align):
|
||||
assert (align & (align - 1)) == 0, align
|
||||
return val & -align
|
||||
def roundup(val, align):
|
||||
assert (align & (align - 1)) == 0, align
|
||||
return (val + align - 1) & -align
|
||||
|
||||
errors = False
|
||||
|
||||
def process(path, img):
|
||||
global errors
|
||||
loads = [phdr for phdr in img.phdrs()
|
||||
if phdr.p_type == glibcelf.Pt.PT_LOAD]
|
||||
if not loads:
|
||||
# Nothing ot check.
|
||||
return
|
||||
alignments = [phdr.p_align for phdr in loads if phdr.p_align > 0]
|
||||
if alignments:
|
||||
align = min(alignments)
|
||||
else:
|
||||
print('error: cannot infer page size')
|
||||
errors = True
|
||||
align = 4096
|
||||
print('info: inferred page size:', align)
|
||||
current_address = None
|
||||
for idx, phdr in enumerate(loads):
|
||||
this_address = rounddown(phdr.p_vaddr, align)
|
||||
next_address = roundup(phdr.p_vaddr + phdr.p_memsz, align)
|
||||
print('info: LOAD segment {}: address 0x{:x}, size {},'
|
||||
' range [0x{:x},0x{:x})'
|
||||
.format(idx, phdr.p_vaddr, phdr.p_memsz,
|
||||
this_address, next_address))
|
||||
if current_address is not None:
|
||||
gap = this_address - current_address
|
||||
if gap != 0:
|
||||
errors = True
|
||||
print('error: gap between load segments: {} bytes'.format(gap))
|
||||
current_address = next_address
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
img = glibcelf.Image.readfile(path)
|
||||
process(path, img)
|
||||
|
||||
if errors:
|
||||
sys.exit(1)
|
||||
11
tests/lib.sh
11
tests/lib.sh
|
|
@ -116,6 +116,17 @@ function buPrepareSRPM () {
|
|||
}
|
||||
|
||||
|
||||
function buConfigureSRPM () {
|
||||
if [ -n "$BU_AS_TEST_USER" ]; then
|
||||
username="${1:-$BU_TEST_USER}"
|
||||
|
||||
rlRun "su - $username -c 'rpmbuild -bp --define=\"_topdir $TmpDir\" $SPECFILE'"
|
||||
else
|
||||
rlRun " rpmbuild -bp --define=\"_topdir $TmpDir\" $SPECFILE"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function buBuildSRPM () {
|
||||
if [ -n "$BU_AS_TEST_USER" ]; then
|
||||
username="${1:-$BU_TEST_USER}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue