mirror of
https://github.com/wolfcw/libfaketime.git
synced 2026-05-19 09:46:11 +03:00
Compare commits
103 Commits
v0.9.9
...
pthread_co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46a0f84c1e | ||
|
|
985d666d73 | ||
|
|
9dcaf53fd7 | ||
|
|
02bc1fccae | ||
|
|
2c02fc08ef | ||
|
|
2d5126411b | ||
|
|
ee4f57d8a5 | ||
|
|
f09c98a89f | ||
|
|
527da8441b | ||
|
|
79defa361e | ||
|
|
6d7c42e2df | ||
|
|
a7e536bcca | ||
|
|
5466cd8a5f | ||
|
|
61490dc09a | ||
|
|
db47664840 | ||
|
|
bc24e278ff | ||
|
|
b0b9432ea4 | ||
|
|
84fc285923 | ||
|
|
806c05f49d | ||
|
|
fe6eeae423 | ||
|
|
f26242b655 | ||
|
|
e0ca33132d | ||
|
|
cbf1d729ed | ||
|
|
543f6b5040 | ||
|
|
aa9eb1006d | ||
|
|
14cf8d7ba8 | ||
|
|
f4ae29fb91 | ||
|
|
a9142e0e9a | ||
|
|
b7fff74716 | ||
|
|
e26859e5ca | ||
|
|
3155e0ee38 | ||
|
|
078a4e4060 | ||
|
|
9043941fa9 | ||
|
|
973111d78a | ||
|
|
4bab3179ce | ||
|
|
2090f5e548 | ||
|
|
f88c8d4221 | ||
|
|
9a73db074b | ||
|
|
932c138112 | ||
|
|
9e27b2ed8b | ||
|
|
c9f292ee39 | ||
|
|
d37421dbe7 | ||
|
|
89161a0cdf | ||
|
|
f87c2f8915 | ||
|
|
ce1d39c98f | ||
|
|
262d1d574f | ||
|
|
06d49adc12 | ||
|
|
1686664c97 | ||
|
|
5217bcd13d | ||
|
|
8ae4c9bc0e | ||
|
|
6733dc3a8d | ||
|
|
008d33fdf2 | ||
|
|
5a0071f952 | ||
|
|
51f1248593 | ||
|
|
e70b143733 | ||
|
|
e1073c8733 | ||
|
|
01b0b4bb56 | ||
|
|
5f5756ccd9 | ||
|
|
bca9f1bf90 | ||
|
|
d3f3ee38c6 | ||
|
|
a3f9410e51 | ||
|
|
a92d6ffe7c | ||
|
|
253774c8d8 | ||
|
|
986e6e1cdc | ||
|
|
0bfb72b627 | ||
|
|
5a1bd98979 | ||
|
|
7e62881c8f | ||
|
|
0e6b1b2460 | ||
|
|
1297568caf | ||
|
|
940502b3de | ||
|
|
26b4b395e9 | ||
|
|
0b0cc29d2e | ||
|
|
a5885f1479 | ||
|
|
0872c6c0c0 | ||
|
|
a51a38d0ae | ||
|
|
f47223ff12 | ||
|
|
7b1d0958b5 | ||
|
|
17522c5ba1 | ||
|
|
5e62eafcc2 | ||
|
|
01f6bc76c9 | ||
|
|
f329eee8c5 | ||
|
|
c89582fc1f | ||
|
|
9a38e5d775 | ||
|
|
7f4e5c378a | ||
|
|
9337bccfcb | ||
|
|
3668fd9b0f | ||
|
|
3a81c6becd | ||
|
|
3db9d20828 | ||
|
|
20e74b1b02 | ||
|
|
00d6edf90c | ||
|
|
811283e683 | ||
|
|
a8283c646d | ||
|
|
2ca0b719e3 | ||
|
|
f6ddc32695 | ||
|
|
8de66f799f | ||
|
|
63fe6f0be5 | ||
|
|
062abac575 | ||
|
|
004222585e | ||
|
|
9c59e24d33 | ||
|
|
46dc625642 | ||
|
|
8f2c856d8e | ||
|
|
b4a822cd6a | ||
|
|
54994ceb0d |
2
.github/workflows/make-test.yml
vendored
2
.github/workflows/make-test.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
- master
|
||||
- develop
|
||||
schedule:
|
||||
- cron: '30 9 * * *'
|
||||
- cron: '30 9 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -2,9 +2,15 @@
|
||||
*.so.1
|
||||
timetest
|
||||
test/getrandom_test
|
||||
test/lib*.so
|
||||
test/use_lib_*
|
||||
test/run_*
|
||||
test/repeat_random
|
||||
test/getentropy_test
|
||||
test/syscall_test
|
||||
test/variadic_promotion
|
||||
|
||||
src/libfaketime.dylib.1
|
||||
src/libfaketime.1.dylib
|
||||
src/core
|
||||
src/faketime
|
||||
|
||||
|
||||
@@ -16,6 +16,6 @@ script:
|
||||
- if [ "$TRAVIS_ARCH" = ppc64le ]; then
|
||||
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX -DFORCE_PTHREAD_NONVER" make;
|
||||
else
|
||||
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX" make;
|
||||
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX" make;
|
||||
fi
|
||||
- make test
|
||||
|
||||
1
Makefile
1
Makefile
@@ -2,6 +2,7 @@ INSTALL ?= install
|
||||
|
||||
UNAME=$(shell uname)
|
||||
SELECTOR:=$(shell if test "${UNAME}" = "Darwin" ; then echo "-f Makefile.OSX" ; fi)
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
all:
|
||||
$(MAKE) $(SELECTOR) -C src all
|
||||
|
||||
8
NEWS
8
NEWS
@@ -1,3 +1,11 @@
|
||||
Since 0.9.9:
|
||||
- improved macOS Monterey support through dyld interposing
|
||||
- changed interception hooks for stat() and similar functions,
|
||||
refactored to use a common handler (@sirainen)
|
||||
- added support for timespec_get, timerfd_{get,set} (@sliquister)
|
||||
- generic syscall() interception for selected syscalls (@dkg)
|
||||
- improved testing system (@dkg)
|
||||
|
||||
Since 0.9.8:
|
||||
- When compiled with the CFLAG FAKE_RANDOM set,
|
||||
libfaketime will intercept calls to getrandom()
|
||||
|
||||
4
README
4
README
@@ -1,5 +1,5 @@
|
||||
libfaketime, version 0.9.9 (February 2021)
|
||||
==========================================
|
||||
libfaketime, version 0.9.10 (February 2022)
|
||||
===========================================
|
||||
|
||||
|
||||
Content of this file:
|
||||
|
||||
@@ -6,7 +6,7 @@ all:
|
||||
|
||||
install:
|
||||
$(INSTALL) -Dm0644 faketime.1 "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
gzip -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
gzip -nf "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
|
||||
uninstall:
|
||||
rm -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1.gz"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH FAKETIME "1" "February 2021" "faketime 0.9.9" wolfcw
|
||||
.TH FAKETIME "1" "February 2022" "faketime 0.9.10" wolfcw
|
||||
.SH NAME
|
||||
faketime \- manipulate the system time for a given command
|
||||
.SH SYNOPSIS
|
||||
@@ -7,11 +7,11 @@ faketime \- manipulate the system time for a given command
|
||||
.SH DESCRIPTION
|
||||
.\" \fIfaketime\fR will trick the given program into seeing the specified timestamp as its starting date and time.
|
||||
.PP
|
||||
The given command will be tricked into believing that the current system time is the one specified in the timestamp. Filesystem timestamps will also be
|
||||
reported relative to this timestamp. The wall clock will continue to run from this date and time unless specified otherwise (see advanced options).
|
||||
Actually, faketime is a simple wrapper for libfaketime, which uses the LD_PRELOAD mechanism to load a small library which intercepts system calls to
|
||||
functions such as \fItime(2)\fR and \fIfstat(2)\fR. This wrapper exposes only a subset of libfaketime's functionality; please refer to the README file
|
||||
that came with faketime for more details and advanced options, or have a look at http://github.com/wolfcw/libfaketime
|
||||
The given command will be tricked into believing that the current system time is the one specified in the timestamp.
|
||||
Filesystem timestamps will also be reported relative to this timestamp.
|
||||
The wall clock will continue to run from this date and time unless specified otherwise (see advanced options).
|
||||
Actually, faketime is a simple wrapper for libfaketime, which uses the LD_PRELOAD mechanism to load a small library which intercepts system calls to functions such as \fItime(2)\fR and \fIfstat(2)\fR.
|
||||
This wrapper exposes only a subset of libfaketime's functionality; please refer to the README file that came with faketime for more details and advanced options, or have a look at https://github.com/wolfcw/libfaketime
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-\-help\fR
|
||||
@@ -23,11 +23,17 @@ show version information and quit.
|
||||
\fB\-m\fR
|
||||
use the multi-threading variant of libfaketime.
|
||||
.TP
|
||||
\fB\-p <PID>\fR
|
||||
pretend that the program's process ID is PID. (only available if built with FAKE_PID)
|
||||
.TP
|
||||
\fB\-f\fR
|
||||
use the advanced timestamp specification format.
|
||||
.TP
|
||||
\fB\--exclude-monotonic\fR
|
||||
Do not fake time when the program makes a call to clock_gettime with a CLOCK_MONOTONIC clock.
|
||||
.TP
|
||||
\fB\--date-prog <PATH>\fR
|
||||
Use a specific GNU-date compatible implementation of the helper used to transform "timestamp format" strings into programmatically usable dates, instead of a compile-time default guess for the generic target platform.
|
||||
|
||||
.SH EXAMPLES
|
||||
.nf
|
||||
@@ -41,41 +47,53 @@ In this single case all spawned processes will use the same global clock without
|
||||
(Please note that it depends on your locale settings whether . or , has to be used for fractional offsets)
|
||||
.fi
|
||||
.SH ADVANCED TIMESTAMP FORMAT
|
||||
The simple timestamp format used by default applies the \fB/bin/date -d\fR command to parse user-friendly specifications such as 'last friday'. When using
|
||||
the faketime option \fB\-f\fR, the timestamp specified on the command line is directly passed to libfaketime, which enables a couple of additional features
|
||||
such as speeding the clock up or slowing it down for the target program. It is strongly recommended that you have a look at the libfaketime documentation. Summary:
|
||||
The simple timestamp format used by default applies the \fB/bin/date -d\fR command to parse user-friendly specifications such as 'last friday'.
|
||||
When using the faketime option \fB\-f\fR, the timestamp specified on the command line is directly passed to libfaketime, which enables a couple of additional features such as speeding the clock up or slowing it down for the target program.
|
||||
It is strongly recommended that you have a look at the libfaketime documentation.
|
||||
Summary:
|
||||
.TP
|
||||
Freeze clock at absolute timestamp: \fB"YYYY-MM-DD hh:mm:ss"\fR
|
||||
If you want to specify an absolute point in time, exactly this format must be used. Please note that freezing the clock is usually not what you want and may break the application. Only use if you know what you're doing!
|
||||
If you want to specify an absolute point in time, exactly this format must be used.
|
||||
Please note that freezing the clock is usually not what you want and may break the application.
|
||||
Only use if you know what you're doing!
|
||||
.TP
|
||||
Relative time offset: \fB"[+/-]123[m/h/d/y]\fR, e.g. "+60m", "+2y"
|
||||
This is the most often used format and specifies the faked time relatively to the current real time. The first character of the format string \fBmust\fR be a + or a -. The numeric value by default represents seconds, but the modifiers m, h, d, and y can be used to specify minutes, hours, days, or years, respectively. For example, "-2y" means "two years ago". Fractional time offsets can be used, e.g. "+2,5y", which means "two and a half years in the future". Please note that the fraction delimiter depends on your locale settings, so if "+2,5y" does not work, you might want to try "+2.5y".
|
||||
Relative time offset: \fB"[+/-]123[m/h/d/y]"\fR, e.g., "+60m", "+2y"
|
||||
This is the most often used format and specifies the faked time relatively to the current real time.
|
||||
The first character of the format string \fBmust\fR be a + or a -.
|
||||
The numeric value by default represents seconds, but the modifiers m, h, d, and y can be used to specify minutes, hours, days, or years, respectively.
|
||||
For example, "-2y" means "two years ago". Fractional time offsets can be used, e.g., "+2,5y", which means "two and a half years in the future".
|
||||
Please note that the fraction delimiter depends on your locale settings, so if "+2,5y" does not work, you might want to try "+2.5y".
|
||||
.TP
|
||||
Start-at timestamps: \fB"@YYYY-MM-DD hh:mm:ss"\fR
|
||||
The wall clock will start counting at the given timestamp for the program. This can be used for specifying absolute timestamps without freezing the clock.
|
||||
The wall clock will start counting at the given timestamp for the program.
|
||||
This can be used for specifying absolute timestamps without freezing the clock.
|
||||
.SH ADVANCED USAGE
|
||||
When using relative time offsets or start-at timestamps (see ADVANCED TIMESTAMP FORMAT above and option \fB\-f\fR), the clock speed can be adjusted, i.e. time may run faster or slower for the executed program. For example, \fB"+5y x10"\fR will set the faked time 5 years into the future and make the time pass 10 times as fast (one real second equals 10 seconds measured by the program). Similarly, the flow of time can be slowed, e.g. using \fB"-7d x0,2"\fR, which will set the faked time 7 days in the past and set the clock speed to 20 percent, i.e. it takes five real world seconds for one second measured by the program. Again, depending on your locale, either "x2.0" or "x2,0" may be required regarding the delimiter. You can also make faketime to advance the reported time by a preset interval upon each time() call independently from the system's time using \fB"-7d i2,0"\fR, where
|
||||
\fB"i"\fR is followed by the increase interval in seconds.
|
||||
When using relative time offsets or start-at timestamps (see ADVANCED TIMESTAMP FORMAT above and option \fB\-f\fR), the clock speed can be adjusted, i.e., time may run faster or slower for the executed program.
|
||||
For example, \fB"+5y x10"\fR will set the faked time 5 years into the future and make the time pass 10 times as fast (one real second equals 10 seconds measured by the program).
|
||||
Similarly, the flow of time can be slowed, e.g., using \fB"-7d x0,2"\fR, which will set the faked time 7 days in the past and set the clock speed to 20 percent, i.e., it takes five real world seconds for one second measured by the program.
|
||||
Again, depending on your locale, either "x2.0" or "x2,0" may be required regarding the delimiter.
|
||||
You can also make faketime to advance the reported time by a preset interval upon each time() call independently from the system's time using \fB"-7d i2,0"\fR, where \fB"i"\fR is followed by the increase interval in seconds.
|
||||
.PP
|
||||
Faking times for multiple programs or even system-wide can be simplified by using ~/.faketimerc files and /etc/faketimerc. Please refer to the README that came with faketime for warnings and details.
|
||||
Faking times for multiple programs or even system-wide can be simplified by using ~/.faketimerc files and /etc/faketimerc.
|
||||
Please refer to the README that came with faketime for warnings and details.
|
||||
.PP
|
||||
Faking of filesystem timestamps may be disabled by setting the NO_FAKE_STAT environment variable to a non-empty value.
|
||||
.SH AUTHOR
|
||||
Please see the README and NEWS files for contributors.
|
||||
.SH BUGS
|
||||
Due to limitations of the LD_PRELOAD mechanism, faketime will not work with suidroot and statically linked programs.
|
||||
While timestamps and time offsets will work for child processes, speeding the clock up or slowing it down might not
|
||||
work for child processes spawned by the executed program as expected; a new instance of libfaketime is used for each
|
||||
child process, which means that the libfaketime start time, which is used in speed adjustments, will also be
|
||||
re-initialized. Some programs may dynamically load system libraries, such as librt, at run-time and therefore bypass libfaketime. You may report programs that do not work with libfaketime, but only if they are available as open source.
|
||||
While timestamps and time offsets will work for child processes, speeding the clock up or slowing it down might not work for child processes spawned by the executed program as expected;
|
||||
a new instance of libfaketime is used for each child process, which means that the libfaketime start time, which is used in speed adjustments, will also be re-initialized.
|
||||
Some programs may dynamically load system libraries, such as librt, at run-time and therefore bypass libfaketime.
|
||||
You may report programs that do not work with libfaketime, but only if they are available as open source.
|
||||
.SH "REPORTING BUGS"
|
||||
Please use https://github.com/wolfcw/libfaketime/issues
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2003-2021 by the libfaketime authors.
|
||||
.PP
|
||||
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You may redistribute copies of faketime under the
|
||||
terms of the GNU General Public License.
|
||||
There is NO warranty;
|
||||
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
You may redistribute copies of faketime under the terms of the GNU General Public License.
|
||||
.br
|
||||
For more information about these matters, see the file named COPYING.
|
||||
.SH "SEE ALSO"
|
||||
|
||||
74
src/Makefile
74
src/Makefile
@@ -1,30 +1,10 @@
|
||||
#
|
||||
# Notes:
|
||||
#
|
||||
# * Compilation Defines:
|
||||
# * Compilation Defines that are set by default:
|
||||
#
|
||||
# FAKE_STAT
|
||||
# - Enables time faking also for files' timestamps.
|
||||
#
|
||||
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
|
||||
# - Enables time faking for the utime* functions. If enabled via
|
||||
# FAKE_UTIME define instead of FAKE_FILE_TIMESTAMPS, the faking
|
||||
# defaults to off without FAKE_UTIME in the environment.
|
||||
#
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
#
|
||||
# PTHREAD_SINGLETHREADED_TIME
|
||||
# - Define this if you want to single-thread time() ... there ARE
|
||||
# possible caching side-effects in a multithreaded environment
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
#
|
||||
# FAKE_INTERNAL_CALLS
|
||||
# - Also intercept libc internal __functions, e.g. not just time(),
|
||||
# but also __time(). Enhances compatibility with applications
|
||||
# that make use of low-level system calls, such as Java Virtual
|
||||
# Machines.
|
||||
# - Enables time faking when reading files' timestamps.
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
@@ -35,12 +15,58 @@
|
||||
# FAKE_PTHREAD
|
||||
# - Intercept pthread_cond_timedwait
|
||||
#
|
||||
# FAKE_INTERNAL_CALLS
|
||||
# - Also intercept libc internal __functions, e.g. not just time(),
|
||||
# but also __time(). Enhances compatibility with applications
|
||||
# that make use of low-level system calls, such as Java Virtual
|
||||
# Machines.
|
||||
#
|
||||
# PTHREAD_SINGLETHREADED_TIME (only set in libfaketimeMT.so)
|
||||
# - Define this if you want to single-thread time() ... there ARE
|
||||
# possible caching side-effects in a multithreaded environment
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
#
|
||||
# * Compilation Defines that are unset by default:
|
||||
#
|
||||
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
|
||||
# - Enables time faking for the utime* functions. If enabled via
|
||||
# FAKE_FILE_TIMESTAMPS, the faking is opt-in at runtime using
|
||||
# with the FAKE_UTIME environment variable. If enabled via
|
||||
# FAKE_UTIME, the faking is opt-out at runtime.
|
||||
#
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
#
|
||||
# FAKE_SETTIME
|
||||
# - Intercept clock_settime(), settimeofday(), and adjtime()
|
||||
#
|
||||
# FAKE_RANDOM
|
||||
# - Intercept getrandom()
|
||||
#
|
||||
# FAKE_PID
|
||||
# - Intercept getpid()
|
||||
#
|
||||
# INTERCEPT_SYSCALL
|
||||
# - (On GNU/Linux only) intercept glibc's syscall() for known relevant syscalls.
|
||||
# If enabled, this currently only works to divert the getrandom syscall.
|
||||
#
|
||||
# - note that on unusual architectures, if INTERCEPT_SYSCALL is set, you may
|
||||
# need to explicitly define variadic_promotion_t (e.g. by putting
|
||||
# -Dvariadic_promotion_t=int into CFLAGS). See src/faketime_common.h for
|
||||
# more info.
|
||||
#
|
||||
# FAKE_STATELESS
|
||||
# - Remove support for any functionality that requires sharing state across
|
||||
# threads of a process, or different processes. This decreases the risk of
|
||||
# interference with a program's normal execution, at the cost of supporting
|
||||
# fewer ways of specifying the time.
|
||||
# Concretely, this currently:
|
||||
# - disables PTHREAD_SINGLETHREADED_TIME, which can cause deadlocks in
|
||||
# multithreaded programs that fork due to making clock_gettime not
|
||||
# async-signal-safe
|
||||
# - disables all shared-memory across processes
|
||||
#
|
||||
# FORCE_MONOTONIC_FIX
|
||||
# - If the test program hangs forever on
|
||||
# " pthread_cond_timedwait: CLOCK_MONOTONIC test
|
||||
@@ -54,6 +80,10 @@
|
||||
# ld automatically choose the correct library version to use for the
|
||||
# target binary. Use for Linux platforms with Multi-Arch support only!
|
||||
#
|
||||
# SILENT
|
||||
# - avoid that the faketime wrapper complains when running within a
|
||||
# libfaketime environment
|
||||
#
|
||||
# * Compilation addition: second libMT target added for building the pthread-
|
||||
# enabled library as a separate library
|
||||
#
|
||||
|
||||
@@ -3,11 +3,31 @@
|
||||
#
|
||||
# * Compilation Defines:
|
||||
#
|
||||
# MACOS_DYLD_INTERPOSE
|
||||
# - Use dlyd interposing instead of name-based function interception
|
||||
# (required since macOS Monterey)
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
#
|
||||
# FAKE_SETTIME
|
||||
# - Intercept clock_settime(), settimeofday(), and adjtime()
|
||||
#
|
||||
# FAKE_PID
|
||||
# - Enable faked values for getpid() calls through FAKETIME_FAKEPID
|
||||
#
|
||||
# FAKE_RANDOM
|
||||
# - Intercept getentropy(). Dangerous for production use.
|
||||
# See README about FAKE_RANDOM.
|
||||
#
|
||||
# FAKE_STAT
|
||||
# - Enables time faking also for files' timestamps.
|
||||
#
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
|
||||
# - Enables time faking for the utime* functions. If enabled via
|
||||
# FAKE_FILE_TIMESTAMPS, the faking is opt-in at runtime using
|
||||
# with the FAKE_UTIME environment variable. If enabled via
|
||||
# FAKE_UTIME, the faking is opt-out at runtime. Requires FAKE_STAT.
|
||||
#
|
||||
# PTHREAD
|
||||
# - Define this to enable multithreading support.
|
||||
@@ -18,9 +38,6 @@
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
#
|
||||
# * Compilation addition: second libMT target added for building the pthread-
|
||||
# enabled library as a separate library
|
||||
#
|
||||
@@ -38,8 +55,8 @@ INSTALL ?= install
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
CFLAGS += -DFAKE_SLEEP -DFAKE_INTERNAL_CALLS -DPREFIX='"'${PREFIX}'"' $(FAKETIME_COMPILE_CFLAGS)
|
||||
LIB_LDFLAGS += -dynamiclib -current_version 0.9.9 -compatibility_version 0.7
|
||||
CFLAGS += -DFAKE_SLEEP -DFAKE_INTERNAL_CALLS -DPREFIX='"'${PREFIX}'"' $(FAKETIME_COMPILE_CFLAGS) -DMACOS_DYLD_INTERPOSE -DFAKE_SETTIME
|
||||
LIB_LDFLAGS += -dynamiclib -current_version 0.9.10 -compatibility_version 0.7
|
||||
|
||||
SONAME = 1
|
||||
LIBS = libfaketime.${SONAME}.dylib
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libfaketime wrapper command
|
||||
*
|
||||
* This file is part of libfaketime, version 0.9.9
|
||||
* This file is part of libfaketime, version 0.9.10
|
||||
*
|
||||
* libfaketime is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License v2 as published by the
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
#include "faketime_common.h"
|
||||
|
||||
const char version[] = "0.9.9";
|
||||
const char version[] = "0.9.10";
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if (defined __APPLE__) || (defined __sun)
|
||||
static const char *date_cmd = "gdate";
|
||||
#else
|
||||
static const char *date_cmd = "date";
|
||||
@@ -75,6 +75,10 @@ void usage(const char *name)
|
||||
" -m : Use the multi-threaded version of libfaketime\n"
|
||||
" -f : Use the advanced timestamp specification format (see manpage)\n"
|
||||
" --exclude-monotonic : Prevent monotonic clock from drifting (not the raw monotonic one)\n"
|
||||
#ifdef FAKE_PID
|
||||
" -p PID : Pretend that the program's process ID is PID\n"
|
||||
#endif
|
||||
" --date-prog PROG : Use specified GNU-compatible implementation of 'date' program\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"%s 'last friday 5 pm' /bin/date\n"
|
||||
@@ -107,8 +111,16 @@ int main (int argc, char **argv)
|
||||
int curr_opt = 1;
|
||||
bool use_mt = false, use_direct = false;
|
||||
long offset;
|
||||
bool fake_pid = false;
|
||||
const char *pid_val;
|
||||
|
||||
while(curr_opt < argc)
|
||||
#ifndef SILENT
|
||||
if (getenv("FAKETIME") || getenv("FAKETIME_SHARED") || getenv("FAKETIME_FAKEPID") || getenv("FAKERANDOM_SEED")) {
|
||||
fprintf(stderr, "faketime: You appear to be running faketime within a libfaketime environment. Proceeding, but check for unexpected results...\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
while (curr_opt < argc)
|
||||
{
|
||||
if (0 == strcmp(argv[curr_opt], "-m"))
|
||||
{
|
||||
@@ -116,6 +128,16 @@ int main (int argc, char **argv)
|
||||
curr_opt++;
|
||||
continue;
|
||||
}
|
||||
if (0 == strcmp(argv[curr_opt], "-p"))
|
||||
{
|
||||
fake_pid = true;
|
||||
pid_val = argv[curr_opt + 1];
|
||||
curr_opt += 2;
|
||||
#ifndef FAKE_PID
|
||||
fprintf(stderr, "faketime: -p argument probably won't work (try rebuilding with -DFAKE_PID)\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if (0 == strcmp(argv[curr_opt], "-f"))
|
||||
{
|
||||
use_direct = true;
|
||||
@@ -128,6 +150,20 @@ int main (int argc, char **argv)
|
||||
curr_opt++;
|
||||
continue;
|
||||
}
|
||||
else if (0 == strcmp(argv[curr_opt], "--date-prog"))
|
||||
{
|
||||
curr_opt++;
|
||||
if (curr_opt > argc) {
|
||||
// At best this avoids a segfault reading beyond the argv[]
|
||||
// Realistically there would be other args (e.g. program to call)
|
||||
fprintf(stderr, "faketime: --date-prog requires a further argument\n");
|
||||
} else {
|
||||
date_cmd = argv[curr_opt];
|
||||
curr_opt++;
|
||||
//fprintf(stderr, "faketime: --date-prog assigned: %s\n", date_cmd);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if ((0 == strcmp(argv[curr_opt], "-v")) ||
|
||||
(0 == strcmp(argv[curr_opt], "--version")))
|
||||
{
|
||||
@@ -169,6 +205,7 @@ int main (int argc, char **argv)
|
||||
close(1); /* close normal stdout */
|
||||
(void) (dup(pfds[1]) + 1); /* make stdout same as pfds[1] */
|
||||
close(pfds[0]); /* we don't need this */
|
||||
// fprintf(stderr, "faketime: using --date-prog: %s\n", date_cmd);
|
||||
if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL))
|
||||
{
|
||||
perror("faketime: Running (g)date failed");
|
||||
@@ -198,6 +235,8 @@ int main (int argc, char **argv)
|
||||
/* simply pass format string along */
|
||||
setenv("FAKETIME", argv[curr_opt], true);
|
||||
}
|
||||
if (fake_pid)
|
||||
setenv("FAKETIME_FAKEPID", pid_val, true);
|
||||
int keepalive_fds[2];
|
||||
(void) (pipe(keepalive_fds) + 1);
|
||||
|
||||
@@ -345,6 +384,7 @@ int main (int argc, char **argv)
|
||||
if (0 == (child_pid = fork()))
|
||||
{
|
||||
close(keepalive_fds[0]); /* only parent needs to read this */
|
||||
// fprintf(stderr, "faketime: Executing: %s\n", argv[curr_opt]);
|
||||
if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt]))
|
||||
{
|
||||
perror("faketime: Running specified command failed");
|
||||
|
||||
@@ -45,7 +45,7 @@ struct ft_shared_s
|
||||
* When advancing time linearly with each time(), etc. call, the calls are
|
||||
* counted here */
|
||||
uint64_t ticks;
|
||||
/* Index of timstamp to be loaded from file */
|
||||
/* Index of timestamp to be loaded from file */
|
||||
uint64_t file_idx;
|
||||
/* System time Faketime started at */
|
||||
struct system_time_s start_time;
|
||||
@@ -58,4 +58,43 @@ struct ft_shared_s
|
||||
#include <mach/mach_port.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Variadic Argument Re-packing
|
||||
|
||||
Functions with variadic arguments typically have most arguments
|
||||
passed on the stack, but it varies across ABIs.
|
||||
|
||||
C specifies that variadic arguments that are smaller than some
|
||||
standard promotion size are promoted to "int or larger". If your
|
||||
platform's ABI only promotes to "int" and not "long" (and "int" and
|
||||
"long" differ on your platform), you should probably add
|
||||
-Dvariadic_promotion_t=int to CFLAGS.
|
||||
|
||||
Note that some ABIs do not put all the variadic arguments on the
|
||||
stack. For example, x86-64 puts float and double variadic
|
||||
arguments into floating point registers, according to
|
||||
https://www.uclibc.org/docs/psABI-x86_64.pdf
|
||||
|
||||
The only variadic function faketime cares about intercepting is
|
||||
syscall. But we don't believe that any syscalls expect float or
|
||||
double arguments, so we hope all the rest will be on the stack.
|
||||
tests/variadic/ attempts to confirm this if you are compiling
|
||||
with -DINTERCEPT_SYSCALL.
|
||||
|
||||
If libc were capable of exposing a variadic form of syscall, we
|
||||
could depend on that and drop this approach, which would be
|
||||
preferable: https://sourceware.org/bugzilla/show_bug.cgi?id=27508
|
||||
*/
|
||||
#ifndef variadic_promotion_t
|
||||
#define variadic_promotion_t long
|
||||
#endif
|
||||
|
||||
/*
|
||||
The Linux kernel appears to have baked-in 6 as the maximum number
|
||||
of arguments for a syscall beyond the syscall number itself.
|
||||
*/
|
||||
#ifndef syscall_max_args
|
||||
#define syscall_max_args 6
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
1010
src/libfaketime.c
1010
src/libfaketime.c
File diff suppressed because it is too large
Load Diff
@@ -9,4 +9,4 @@
|
||||
#define htole64(x) LE_64(x)
|
||||
#define le64toh(x) LE_64(x)
|
||||
|
||||
#endif /* SUN_OS_ENDIAN_H */
|
||||
#endif /* SUN_OS_ENDIAN_H */
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
do \
|
||||
{ \
|
||||
int64_t tmp_time; \
|
||||
tmp_time = (c) * (int64_t) ((tvp)->tv_sec * SEC_TO_##prefix##SEC + \
|
||||
tmp_time = (c) * (int64_t) ((int64_t) (tvp)->tv_sec * SEC_TO_##prefix##SEC + \
|
||||
(int64_t) (tvp)->tv_##prefix##sec); \
|
||||
(result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC; \
|
||||
(result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) / \
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
CC = gcc
|
||||
|
||||
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra $(FAKETIME_COMPILE_CFLAGS)
|
||||
LDFLAGS = -lrt -lpthread
|
||||
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra $(FAKETIME_COMPILE_CFLAGS)
|
||||
LDFLAGS += -lrt -lpthread
|
||||
|
||||
SRC = timetest.c
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: timetest test
|
||||
TEST_SNIPPETS = $(notdir $(basename $(wildcard snippets/*.c)))
|
||||
EXPECTATIONS= $(notdir $(basename $(wildcard snippets/*.variable)))
|
||||
|
||||
ALL_TESTS = timetest test
|
||||
|
||||
ifneq ($(filter -DINTERCEPT_SYSCALL,${CFLAGS}),)
|
||||
ALL_TESTS += confirm_variadic_promotion
|
||||
endif
|
||||
|
||||
all: $(ALL_TESTS)
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $<
|
||||
@@ -22,16 +31,48 @@ test: timetest functest
|
||||
functest:
|
||||
./testframe.sh functests
|
||||
|
||||
getrandom_test: getrandom_test.c
|
||||
%_test: %_test.c
|
||||
${CC} -o $@ ${CFLAGS} $<
|
||||
|
||||
randomtest: getrandom_test
|
||||
randomtest: repeat_random
|
||||
./randomtest.sh
|
||||
|
||||
# ensure our variadic argument unpacking/repacking works as expected
|
||||
confirm_variadic_promotion: variadic_promotion
|
||||
./variadic_promotion
|
||||
variadic_promotion: variadic/main.o variadic/outer.o variadic/inner.o
|
||||
${CC} -o $@ ${CFLAGS} $^
|
||||
variadic/%.o: variadic/%.c
|
||||
${CC} -c -o $@ ${CFLAGS} $<
|
||||
|
||||
# run snippet tests
|
||||
snippets: test_variable_data test_library_constructors
|
||||
|
||||
## test snippet behavior across env var setting over time:
|
||||
test_variable_data: test_variable_data.sh $(foreach f,${EXPECTATIONS},run_${f})
|
||||
./test_variable_data.sh ${EXPECTATIONS}
|
||||
|
||||
run_%: _run_test.c snippets/%.c
|
||||
sed s/SNIPPET_NAME/$*/g < _run_test.c | ${CC} -o $@ ${CFLAGS} -x c -
|
||||
|
||||
## test snippets in other library constructors:
|
||||
test_library_constructors: $(foreach f,${TEST_SNIPPETS},test_lib_${f})
|
||||
test_lib_%: test_constructors.sh use_lib_% lib%.so
|
||||
./test_constructors.sh $*
|
||||
|
||||
lib%.so: _libtest.c snippets/%.c
|
||||
sed s/SNIPPET_NAME/$*/g < _libtest.c | ${CC} -shared -o $@ -fpic ${CFLAGS} -x c -
|
||||
|
||||
use_lib_%: _use_lib_test.c snippets/%.c lib%.so
|
||||
sed s/SNIPPET_NAME/$*/g < _use_lib_test.c | ${CC} -L. -o $@ ${CFLAGS} -x c - -l$*
|
||||
|
||||
|
||||
## cleanup and metainformation
|
||||
|
||||
clean:
|
||||
@rm -f ${OBJ} timetest getrandom_test
|
||||
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o
|
||||
|
||||
distclean: clean
|
||||
@echo
|
||||
|
||||
.PHONY: all test clean distclean
|
||||
.PHONY: all test clean distclean randomtest snippets test_variable_data test_library_constructors
|
||||
|
||||
8
test/_libtest.c
Normal file
8
test/_libtest.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "snippets/include_headers.h"
|
||||
#define where "libSNIPPET_NAME"
|
||||
void SNIPPET_NAME_as_needed() {
|
||||
printf(" called SNIPPET_NAME_as_needed() \n");
|
||||
}
|
||||
static __attribute__((constructor)) void init_SNIPPET_NAME() {
|
||||
#include "snippets/SNIPPET_NAME.c"
|
||||
}
|
||||
5
test/_run_test.c
Normal file
5
test/_run_test.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "snippets/include_headers.h"
|
||||
#define where "run_SNIPPET_NAME"
|
||||
int main() {
|
||||
#include "snippets/SNIPPET_NAME.c"
|
||||
}
|
||||
7
test/_use_lib_test.c
Normal file
7
test/_use_lib_test.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "snippets/include_headers.h"
|
||||
extern void SNIPPET_NAME_as_needed();
|
||||
#define where "use_lib_SNIPPET_NAME"
|
||||
int main() {
|
||||
SNIPPET_NAME_as_needed();
|
||||
#include "snippets/SNIPPET_NAME.c"
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/random.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
char *buf = calloc(100, 1);
|
||||
size_t buflen = 100;
|
||||
unsigned flags = GRND_NONBLOCK;
|
||||
|
||||
fprintf(stdout, "Before getrandom:\n");
|
||||
for (size_t i=0; i < buflen; i++) { fprintf(stdout, "%hhu ", buf[i]); }
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
int result = getrandom(buf, buflen, flags);
|
||||
fprintf(stdout, "getrandom() result: %d\n", result);
|
||||
if (result == -1) perror("getrandom() unsuccessful");
|
||||
|
||||
|
||||
fprintf(stdout, "After getrandom:\n");
|
||||
for (size_t i=0; i < buflen; i++) { fprintf(stdout, "%hhu ", buf[i]); }
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
@@ -2,27 +2,17 @@
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
|
||||
set -e
|
||||
|
||||
error=0
|
||||
./getrandom_test > run0
|
||||
FAKERANDOM_SEED=0x12345678DEADBEEF LD_PRELOAD="$FTPL" ./getrandom_test > run1
|
||||
FAKERANDOM_SEED=0x12345678DEADBEEF LD_PRELOAD="$FTPL" ./getrandom_test > run2
|
||||
FAKERANDOM_SEED=0x0000000000000000 LD_PRELOAD="$FTPL" ./getrandom_test > run3
|
||||
|
||||
repeat3x5="$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 3 5)"
|
||||
repeat5x3="$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 5 3)"
|
||||
|
||||
if diff -u run0 run1 > /dev/null; then
|
||||
if [ "$repeat3x5" != "$repeat5x3" ]; then
|
||||
error=1
|
||||
printf >&2 'test run without a seed produced the same data as a run with a seed!\n'
|
||||
printf >&2 '5 calls of getrandom(3) got %s\n3 calls of getrandom(5) got %s\n' "$repeat3x5" "$repeat5x3"
|
||||
fi
|
||||
if ! diff -u run1 run2; then
|
||||
error=2
|
||||
printf >&2 'test runs with identical seeds differed!\n'
|
||||
fi
|
||||
if diff -u run2 run3 >/dev/null; then
|
||||
error=3
|
||||
printf >&2 'test runs with different seeds produced the same data!\n'
|
||||
fi
|
||||
|
||||
rm -f run0 run1 run2 run3
|
||||
|
||||
if [ 0 = $error ]; then
|
||||
printf 'getrandom interception test successful.\n'
|
||||
|
||||
40
test/repeat_random.c
Normal file
40
test/repeat_random.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/random.h>
|
||||
|
||||
void usage(const char* name) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s REPS SIZE\n\n"
|
||||
"Gather and print REPS blocks of SIZE bytes from getrandom()\n",
|
||||
name);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int reps, size;
|
||||
unsigned char *buf;
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
reps = atoi(argv[1]);
|
||||
size = atoi(argv[2]);
|
||||
buf = malloc(size);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "failure to allocate buffer of size %d\n", size);
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < reps; i++) {
|
||||
ssize_t resp = getrandom(buf, size, 0);
|
||||
if (resp != size) {
|
||||
fprintf(stderr, "tried to get %d bytes, got %zd\n", size, resp);
|
||||
free(buf);
|
||||
return 2;
|
||||
}
|
||||
for (int j = 0; j < size; j++) {
|
||||
printf("%02x", buf[j]);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
printf("\n");
|
||||
return 0;
|
||||
};
|
||||
72
test/snippets/README
Normal file
72
test/snippets/README
Normal file
@@ -0,0 +1,72 @@
|
||||
Testing Interception with Snippets
|
||||
==================================
|
||||
|
||||
Faketime intercepts some C library functions and system calls. We
|
||||
want to make it easier to apply certain generic tests across many
|
||||
different functions. We do that with snippets of C, which each can be
|
||||
applied in multiple testing frameworks.
|
||||
|
||||
Most snippets are just a minimalist invocation of a single function or
|
||||
syscall that is likely to be intercepted by libfaketime, though it's
|
||||
possible to test more complex snippets too.
|
||||
|
||||
Including a New Snippet
|
||||
-----------------------
|
||||
|
||||
To cover a new bit of intercepted functionality, supply a C snippet in
|
||||
this directory named `FOO.c` (the name FOO should conform to C
|
||||
function names -- letters, numbers, and underscores; if you're testing
|
||||
interception of a single function, the simplest thing is to name
|
||||
snippet file after the intercepted function name).
|
||||
|
||||
This file should contain a small bit of code that exercises the
|
||||
functionality in question. It should be self-contained, and it should
|
||||
produce some kind of description of what happened to stdout. The data
|
||||
sent to stdout should include the const char* "where" value (which is
|
||||
an indication of which test framework is using the snippet). Take a
|
||||
look at getpid.c for a simple example.
|
||||
|
||||
If the snippet needs additional #include headers, please add them
|
||||
in `include_headers.h`. These #includes will be used by every snippet,
|
||||
so try to keep it minimal.
|
||||
|
||||
Snippet Testing Frameworks
|
||||
--------------------------
|
||||
|
||||
We have the following frameworks that use the snippets:
|
||||
|
||||
### Variable Data
|
||||
|
||||
Most functionality intercepted by libfaketime will normally produce
|
||||
variant output when invoked multiple times across the span of a few
|
||||
seconds by different processes. But if `FAKETIME` (or an analogous
|
||||
variable like `FAKERANDOM_SEED`) is set, the output data should remain
|
||||
constant.
|
||||
|
||||
If this describes the functionality in a new snippet `FOO.c`, please
|
||||
also drop a single-line file `FOO.variable` in this directory, where
|
||||
the first word of the line is the variable that should hold the output
|
||||
constant, and the rest of the line is the value of that variable.
|
||||
|
||||
See the `test_variable_data` target in `test/Makefile` for how this is
|
||||
implemented.
|
||||
|
||||
### Library Constructors
|
||||
|
||||
Library constructor routines are run by ld.so before the main process
|
||||
is launched. If the LD_PRELOADed libfaketime is masking a symbol from
|
||||
libc, and another library has a constructor routine that invokes that
|
||||
symbol, it might get called before libfaketime has had a chance to
|
||||
initialize its followup pointers to the actual libc functionality.
|
||||
|
||||
This framework is applied automatically to all snippets.
|
||||
|
||||
See the `test_library_constructors` target in `test/Makefile` for how
|
||||
this is implemented.
|
||||
|
||||
Adding a New Framework
|
||||
----------------------
|
||||
|
||||
If you want to add a new framework that tests across all snippets,
|
||||
implement it in a few lines of `test/Makefile` and document it in the
|
||||
section above.
|
||||
8
test/snippets/clock_gettime.c
Normal file
8
test/snippets/clock_gettime.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec ts;
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
int ret = clock_gettime(ckid, &ts);
|
||||
if (ret == 0) {
|
||||
printf("[%s] clock_gettime(CLOCK_REALTIME[%d], &ts) -> {%lld, %ld}\n", where, ckid, (long long)ts.tv_sec, ts.tv_nsec);
|
||||
} else {
|
||||
printf("[%s] clock_gettime(CLOCK_REALTIME[%d], &ts) returned non-zero (%d), errno = %d (%s)\n", where, ckid, ret, errno, strerror(errno));
|
||||
}
|
||||
1
test/snippets/clock_gettime.variable
Normal file
1
test/snippets/clock_gettime.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
8
test/snippets/clock_gettime_heap.c
Normal file
8
test/snippets/clock_gettime_heap.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec *ts = malloc(sizeof(struct timespec));
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
int ret = clock_gettime(ckid, ts);
|
||||
if (ret == 0) {
|
||||
printf("[%s] clock_gettime_heap(CLOCK_REALTIME[%d], ts) -> {%lld, %ld}\n", where, ckid, (long long)ts->tv_sec, ts->tv_nsec);
|
||||
} else {
|
||||
printf("[%s] clock_gettime_heap(CLOCK_REALTIME[%d], ts) returned non-zero (%d), errno = %d (%s)\n", where, ckid, ret, errno, strerror(errno));
|
||||
}
|
||||
1
test/snippets/clock_gettime_heap.variable
Normal file
1
test/snippets/clock_gettime_heap.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
6
test/snippets/getentropy.c
Normal file
6
test/snippets/getentropy.c
Normal file
@@ -0,0 +1,6 @@
|
||||
unsigned int targ;
|
||||
if (getentropy(&targ, sizeof(targ)) == 0) {
|
||||
printf("[%s] getentropy() yielded 0x%08x\n", where, targ);
|
||||
} else {
|
||||
printf("[%s] getentropy() failed with %d (%s)\n", where, errno, strerror(errno));
|
||||
}
|
||||
1
test/snippets/getentropy.variable
Normal file
1
test/snippets/getentropy.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKERANDOM_SEED 0x0123456789ABCDEF
|
||||
2
test/snippets/getpid.c
Normal file
2
test/snippets/getpid.c
Normal file
@@ -0,0 +1,2 @@
|
||||
pid_t pid = getpid();
|
||||
printf("[%s] getpid() yielded %d\n", where, pid);
|
||||
1
test/snippets/getpid.variable
Normal file
1
test/snippets/getpid.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME_FAKEPID 1
|
||||
7
test/snippets/getrandom.c
Normal file
7
test/snippets/getrandom.c
Normal file
@@ -0,0 +1,7 @@
|
||||
unsigned int targ;
|
||||
ssize_t ret = getrandom(&targ, sizeof(targ), 0);
|
||||
if (ret == sizeof(targ)) {
|
||||
printf("[%s] getrandom() yielded 0x%08x\n", where, targ);
|
||||
} else {
|
||||
printf("[%s] getrandom() failed with only %zd\n", where, ret);
|
||||
}
|
||||
1
test/snippets/getrandom.variable
Normal file
1
test/snippets/getrandom.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKERANDOM_SEED 0xDEADBEEFDEADBEEF
|
||||
9
test/snippets/include_headers.h
Normal file
9
test/snippets/include_headers.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
2
test/snippets/syscall.c
Normal file
2
test/snippets/syscall.c
Normal file
@@ -0,0 +1,2 @@
|
||||
long uid = syscall(__NR_getuid);
|
||||
printf("[%s] syscall(__NR_getuid) -> %ld\n", where, uid);
|
||||
8
test/snippets/syscall_clock_gettime.c
Normal file
8
test/snippets/syscall_clock_gettime.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec ts;
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
long ret = syscall(__NR_clock_gettime, ckid, &ts);
|
||||
if (ret == 0)
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], &ts) -> {%lld, %ld}\n", where, ckid, (long long)ts.tv_sec, ts.tv_nsec);
|
||||
else
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], &ts) returned non-zero (%ld)\n", where, ckid, ret);
|
||||
|
||||
1
test/snippets/syscall_clock_gettime.variable
Normal file
1
test/snippets/syscall_clock_gettime.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-01-01 00:00:00
|
||||
8
test/snippets/syscall_clock_gettime_heap.c
Normal file
8
test/snippets/syscall_clock_gettime_heap.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec *ts = malloc(sizeof(struct timespec));
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
long ret = syscall(__NR_clock_gettime, ckid, ts);
|
||||
if (ret == 0)
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], ts) -> {%lld, %ld}\n", where, ckid, (long long)ts->tv_sec, ts->tv_nsec);
|
||||
else
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], ts) returned non-zero (%ld)\n", where, ckid, ret);
|
||||
|
||||
1
test/snippets/syscall_clock_gettime_heap.variable
Normal file
1
test/snippets/syscall_clock_gettime_heap.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
2
test/snippets/time.c
Normal file
2
test/snippets/time.c
Normal file
@@ -0,0 +1,2 @@
|
||||
time_t t = time(NULL);
|
||||
printf("[%s] time() yielded %zd\n", where, t);
|
||||
1
test/snippets/time.variable
Normal file
1
test/snippets/time.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
10
test/test_constructors.sh
Executable file
10
test/test_constructors.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
|
||||
function="$1"
|
||||
|
||||
printf 'Testing library init for %s (no LD_PRELOAD)\n' "$function"
|
||||
LD_LIBRARY_PATH=. "./use_lib_$function"
|
||||
printf 'Testing library init for %s (LD_PRELOAD)\n' "$function"
|
||||
LD_LIBRARY_PATH=. LD_PRELOAD="$FTPL" "./use_lib_$function"
|
||||
54
test/test_variable_data.sh
Executable file
54
test/test_variable_data.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
DELAY="${DELAY:-2}"
|
||||
|
||||
declare -A firstunset first second delayed delayedunset
|
||||
|
||||
err=0
|
||||
for func in "$@"; do
|
||||
if ! [ -x "./run_$func" ]; then
|
||||
printf >&2 '%s does not exist, failing\n' "./run_$func"
|
||||
exit 1
|
||||
fi
|
||||
read varname value < "snippets/$func.variable"
|
||||
unset $varname
|
||||
firstunset[$func]="$(env LD_PRELOAD="$FTPL" "./run_$func")"
|
||||
first[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
|
||||
second[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
|
||||
if [ "${first[$func]}" != "${second[$func]}" ]; then
|
||||
printf >&2 '[%s] Set %s="%s", but got two different outputs:\n - %s\n - %s\n' "$func" "$varname" "$value" "${first[$func]}" "${second[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
if [ "${first[$func]}" == "${firstunset[$func]}" ]; then
|
||||
printf >&2 '[%s] Same answer when %s="%s" and when unset:\n - set: %s\n - unset: %s\n' "$func" "$varname" "$value" "${first[$func]}" "${firstunset[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
printf "Sleeping %d seconds..." "$DELAY"
|
||||
sleep "$DELAY"
|
||||
printf 'done\n'
|
||||
|
||||
for func in "$@"; do
|
||||
read varname value < "snippets/$func.variable"
|
||||
unset $varname
|
||||
delayed[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
|
||||
delayedunset[$func]="$(LD_PRELOAD="$FTPL" "./run_$func")"
|
||||
if [ "${first[$func]}" != "${delayed[$func]}" ]; then
|
||||
printf >&2 '[%s] Vary across delay of %d seconds (%s="%s"):\n - before: %s\n - after: %s\n' "$func" "$DELAY" "$varname" "$value" "${first[$func]}" "${delayed[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
if [ "${firstunset[$func]}" == "${delayedunset[$func]}" ]; then
|
||||
printf >&2 '[%s] Same answer when unset across delay of %d seconds:\n - before: %s\n - after: %s\n' "$func" "$DELAY" "${firstunset[$func]}" "${delayedunset[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$err" -gt 0 ]; then
|
||||
printf >&2 'Got %d errors, failing\n' "$err"
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
@@ -83,6 +83,7 @@ void* pthread_test(void* args)
|
||||
if (rt != ETIMEDOUT)
|
||||
{
|
||||
printf("pthread_cond_timedwait failed\n");
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
@@ -105,6 +106,7 @@ void* pthread_test(void* args)
|
||||
if (rt != ETIMEDOUT)
|
||||
{
|
||||
printf("pthread_cond_timedwait failed\n");
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
|
||||
46
test/variadic/inner.c
Normal file
46
test/variadic/inner.c
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* round 0: c, s, wc, i, wi */
|
||||
long inner0(char *out, ...) {
|
||||
char c = 0;
|
||||
short s = 0;
|
||||
wchar_t wc = 0;
|
||||
int i = 0;
|
||||
wint_t wi = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, out);
|
||||
c = va_arg(ap, int);
|
||||
s = va_arg(ap, int);
|
||||
wc = va_arg(ap, typeof(wc));
|
||||
i = va_arg(ap, typeof(i));
|
||||
wi = va_arg(ap, typeof(wi));
|
||||
va_end(ap);
|
||||
|
||||
int ret = sprintf(out, "c: 0x%x s: 0x%x wc: 0x%lx i: 0x%x wi: 0x%x\n", c, s, (long)wc, i, wi);
|
||||
return ret;
|
||||
}
|
||||
/* round 1: l, ll, ptr, pd, sz */
|
||||
long inner1(char *out, ...) {
|
||||
long l = 0;
|
||||
long long ll = 0;
|
||||
void *ptr = NULL;
|
||||
ptrdiff_t pd = 0;
|
||||
size_t sz = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, out);
|
||||
l = va_arg(ap, typeof(l));
|
||||
ll = va_arg(ap, typeof(ll));
|
||||
ptr = va_arg(ap, typeof(ptr));
|
||||
pd = va_arg(ap, typeof(pd));
|
||||
sz = va_arg(ap, typeof(sz));
|
||||
va_end(ap);
|
||||
|
||||
int ret = sprintf(out, "l: 0x%lx ll: 0x%llx ptr: %p pd: 0x%tx sz: 0x%zx\n", l, ll, ptr, pd, sz);
|
||||
return ret;
|
||||
}
|
||||
70
test/variadic/main.c
Normal file
70
test/variadic/main.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <wchar.h>
|
||||
|
||||
extern long outer(long num, char *out, ...);
|
||||
extern long inner0(char *out, ...);
|
||||
extern long inner1(char *out, ...);
|
||||
|
||||
#define bufsize 2048
|
||||
|
||||
static int compare_buffers(int round,
|
||||
long ret_outer, long ret_inner,
|
||||
const char* outer, const char* inner) {
|
||||
int ret = 0;
|
||||
if (ret_outer != ret_inner) {
|
||||
printf("Round %d: return values differ (outer: %ld inner: %ld)\n", round, ret_outer, ret_inner);
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(outer, inner, bufsize)) {
|
||||
printf("Round %d strings differ:\n - outer: %s\n - inner: %s\n", round, outer, inner);
|
||||
ret++;
|
||||
}
|
||||
if (ret == 0)
|
||||
printf("Round %d success: %s\n", round, outer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main() {
|
||||
/* sizes of intrinsic types as reported by echo | cpp -dM | grep
|
||||
SIZEOF, pruned to avoid floating point types. Should work with
|
||||
both clang and gcc, not sure about other C preprocessors.
|
||||
|
||||
Note that we set bits in every high octet and every low octet to
|
||||
see that they end up in the right spot.
|
||||
*/
|
||||
char c = 0x03L;
|
||||
short s = (0x04L << ((__SIZEOF_SHORT__ - 1) * 8)) + 0xff;
|
||||
wchar_t wc = (0x05L << ((__SIZEOF_WCHAR_T__ - 1) * 8)) + 0xfe;
|
||||
int i = (0x06L << ((__SIZEOF_INT__ - 1) * 8)) + 0xfd;
|
||||
wint_t wi = (0x07L << ((__SIZEOF_WINT_T__ - 1) * 8)) + 0xfc;
|
||||
long l = (0x08L << ((__SIZEOF_LONG__ - 1) * 8) ) + 0xfb;
|
||||
long long ll = (0x09LL << ((__SIZEOF_LONG_LONG__ - 1) * 8)) + 0xfa;
|
||||
void *ptr = (void*)((0x0aL << ((__SIZEOF_POINTER__ - 1) * 8)) + 0xf9);
|
||||
ptrdiff_t pd = (0x0bL << ((__SIZEOF_PTRDIFF_T__ -1) * 8)) + 0xf9;
|
||||
size_t sz = (0x0cL << ((__SIZEOF_SIZE_T__ - 1) * 8)) + 0xf8;
|
||||
|
||||
char *buf[2];
|
||||
for (int j = 0; j < 2; j++)
|
||||
buf[j] = malloc(bufsize);
|
||||
|
||||
int ret[2];
|
||||
int errors = 0;
|
||||
|
||||
#define reset_buffers(n) for (int j = 0; j < 2; j++) memset(buf[j], n, bufsize)
|
||||
#define check_buffers(n) errors += compare_buffers(n, ret[0], ret[1], buf[0], buf[1])
|
||||
|
||||
reset_buffers(0);
|
||||
ret[0] = outer(0, buf[0], c, s, wc, i, wi);
|
||||
ret[1] = inner0(buf[1], c, s, wc, i, wi);
|
||||
check_buffers(0);
|
||||
|
||||
reset_buffers(1);
|
||||
ret[0] = outer(1, buf[0], l, ll, ptr, pd, sz);
|
||||
ret[1] = inner1(buf[1], l, ll, ptr, pd, sz);
|
||||
check_buffers(1);
|
||||
|
||||
return (int)errors;
|
||||
}
|
||||
21
test/variadic/outer.c
Normal file
21
test/variadic/outer.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include "../../src/faketime_common.h"
|
||||
|
||||
extern long inner0(char *out, ...);
|
||||
extern long inner1(char *out, ...);
|
||||
|
||||
long outer(long num, char *out, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, out);
|
||||
variadic_promotion_t a[syscall_max_args];
|
||||
for (int i = 0; i < syscall_max_args; i++)
|
||||
a[i] = va_arg(ap, variadic_promotion_t);
|
||||
va_end(ap);
|
||||
|
||||
if (num == 0)
|
||||
return inner0(out, a[0], a[1], a[2], a[3], a[4], a[5]);
|
||||
if (num == 1)
|
||||
return inner1(out, a[0], a[1], a[2], a[3], a[4], a[5]);
|
||||
else return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user