Fix cross-arch shared memory struct layout and ftruncate/munmap sizes

Replace struct timespec (arch-dependent long/time_t) with fixed-width
int64_t pairs in ft_shared_s so that 32-bit and 64-bit processes
interpret the same shared memory layout identically.

Fix ftruncate calls that allocated sizeof(uint64_t) (8 bytes) instead
of sizeof(struct ft_shared_s) (64-80 bytes) for the shared memory
region. Fix munmap in ft_cleanup using the wrong size.

Add struct layout test and cross-process shared memory functional test.
This commit is contained in:
Andrij Abyzov
2026-01-26 13:31:55 +01:00
parent 13d47210d5
commit e21bf3017a
6 changed files with 174 additions and 25 deletions

View File

@@ -9,7 +9,7 @@ OBJ = ${SRC:.c=.o}
TEST_SNIPPETS = $(notdir $(basename $(wildcard snippets/*.c)))
EXPECTATIONS = $(notdir $(basename $(wildcard snippets/*.variable)))
ALL_TESTS = timetest test
ALL_TESTS = timetest test shm_layout_test
ifneq ($(filter -DINTERCEPT_SYSCALL,${CFLAGS}),)
ALL_TESTS += confirm_variadic_promotion
@@ -26,6 +26,9 @@ all: $(ALL_TESTS)
timetest: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
shm_layout_test: shm_layout_test.c ../src/faketime_common.h
${CC} -o $@ ${CFLAGS} $<
test: timetest functest libmallocintercept.so
@echo
@./test.sh
@@ -76,7 +79,7 @@ use_lib_%: _use_lib_test.c snippets/%.c lib%.so
## cleanup and metainformation
clean:
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o repeat_random libmallocintercept.so
@rm -f ${OBJ} timetest shm_layout_test getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o repeat_random libmallocintercept.so
distclean: clean
@echo

View File

@@ -0,0 +1,31 @@
# Verify that shared memory works end-to-end across processes.
# The faketime wrapper creates SHM with a known FAKETIME value,
# and the child process (via LD_PRELOAD) reads it and reports
# the faked time.
init()
{
typeset testsuite="$1"
PLATFORM=$(platform)
if [ -z "$PLATFORM" ]; then
echo "$testsuite: unknown platform! quitting"
return 1
fi
echo "# PLATFORM=$PLATFORM"
return 0
}
run()
{
init
run_testcase shm_year_check
}
shm_year_check()
{
typeset expected="2020"
typeset actual
actual=$(fakecmd "2020-06-15 12:00:00" date -u +%Y)
asserteq "$actual" "$expected" "child process should see faked year via SHM"
}

65
test/shm_layout_test.c Normal file
View File

@@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include "../src/faketime_common.h"
static int failures = 0;
static void check_offset(const char *field, size_t actual, size_t expected)
{
if (actual != expected)
{
fprintf(stderr, "FAIL: offsetof(ft_shared_s, %s) = %zu, expected %zu\n",
field, actual, expected);
failures++;
}
else
{
printf("OK: offsetof(ft_shared_s, %s) = %zu\n", field, actual);
}
}
static void check_size(const char *name, size_t actual, size_t expected)
{
if (actual != expected)
{
fprintf(stderr, "FAIL: sizeof(%s) = %zu, expected %zu\n",
name, actual, expected);
failures++;
}
else
{
printf("OK: sizeof(%s) = %zu\n", name, actual);
}
}
int main()
{
/* ft_shared_time_s must be exactly 16 bytes: two int64_t */
check_size("ft_shared_time_s", sizeof(struct ft_shared_time_s), 16);
/* Field offsets in ft_shared_s */
check_offset("ticks", offsetof(struct ft_shared_s, ticks), 0);
check_offset("file_idx", offsetof(struct ft_shared_s, file_idx), 8);
check_offset("start_time_real", offsetof(struct ft_shared_s, start_time_real), 16);
check_offset("start_time_mon", offsetof(struct ft_shared_s, start_time_mon), 32);
check_offset("start_time_mon_raw", offsetof(struct ft_shared_s, start_time_mon_raw), 48);
#ifdef CLOCK_BOOTTIME
check_offset("start_time_boot", offsetof(struct ft_shared_s, start_time_boot), 64);
check_size("ft_shared_s", sizeof(struct ft_shared_s), 80);
#else
check_size("ft_shared_s", sizeof(struct ft_shared_s), 64);
#endif
if (failures > 0)
{
fprintf(stderr, "%d layout check(s) failed\n", failures);
return EXIT_FAILURE;
}
printf("All layout checks passed\n");
return EXIT_SUCCESS;
}