mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-10 05:59:39 +08:00
Compare commits
165
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d6fdf9f05 | ||
|
|
6bbd88c251 | ||
|
|
821f0a9cb2 | ||
|
|
a79bc55e5b | ||
|
|
31615a5f47 | ||
|
|
6428a662cc | ||
|
|
a3ef8a0c3d | ||
|
|
70522b1c1d | ||
|
|
8ad5519ae1 | ||
|
|
23bc964c62 | ||
|
|
76e30dd44e | ||
|
|
071e2bdd85 | ||
|
|
25ed98a882 | ||
|
|
a3dd272e9c | ||
|
|
ae86a6bd48 | ||
|
|
a0ce680598 | ||
|
|
178292fe01 | ||
|
|
921b3e7ae3 | ||
|
|
6b4f9a4acc | ||
|
|
81d2a205a9 | ||
|
|
d5904daf76 | ||
|
|
d436d8b7ad | ||
|
|
1ad51a1840 | ||
|
|
84619864c6 | ||
|
|
ad65f574aa | ||
|
|
87a18fc33a | ||
|
|
de28bb3c61 | ||
|
|
fa93ff0640 | ||
|
|
bab2034153 | ||
|
|
12e572c150 | ||
|
|
e1d6be36f5 | ||
|
|
51bf3df138 | ||
|
|
3d00e826aa | ||
|
|
373f43fd0c | ||
|
|
8ebaa0fb1e | ||
|
|
d14cc230f6 | ||
|
|
375515bdf7 | ||
|
|
293a787c88 | ||
|
|
9d868841f8 | ||
|
|
6746407ed0 | ||
|
|
7341e72bc2 | ||
|
|
5661d967a5 | ||
|
|
83d111ee1f | ||
|
|
ed4899db39 | ||
|
|
9031e3fe26 | ||
|
|
447660cee5 | ||
|
|
2e776d7b31 | ||
|
|
889122cbfa | ||
|
|
fa4162af6f | ||
|
|
903f0b6942 | ||
|
|
3e33d93073 | ||
|
|
3d8ef60802 | ||
|
|
67b1fb515c | ||
|
|
1bf07898c9 | ||
|
|
79bf3c9774 | ||
|
|
d811d240c0 | ||
|
|
8113182a97 | ||
|
|
369b47aaf7 | ||
|
|
13e5c43287 | ||
|
|
61e8ae9b66 | ||
|
|
24c0d68815 | ||
|
|
80259cd098 | ||
|
|
704e18d66d | ||
|
|
ad34abcad5 | ||
|
|
236287f869 | ||
|
|
ade1fa24e3 | ||
|
|
afc53d52dc | ||
|
|
d59630f995 | ||
|
|
501f426fe0 | ||
|
|
94abcef26e | ||
|
|
520aaef712 | ||
|
|
1ba9ebfce3 | ||
|
|
dd591f8469 | ||
|
|
4748829f86 | ||
|
|
6ffe972db7 | ||
|
|
2900267d78 | ||
|
|
c8e3101337 | ||
|
|
8e94ffe0f8 | ||
|
|
bc33a4d53c | ||
|
|
a604ee4a54 | ||
|
|
618a86e09e | ||
|
|
6bd82f5fd0 | ||
|
|
7378e9c520 | ||
|
|
1c05b8f551 | ||
|
|
6f4527a7dd | ||
|
|
c56022269f | ||
|
|
42766b3db2 | ||
|
|
946ee0281a | ||
|
|
55e77b7d81 | ||
|
|
6b19792c9c | ||
|
|
9cd7745689 | ||
|
|
b3778c01b7 | ||
|
|
4f0ae74135 | ||
|
|
1ce16683d9 | ||
|
|
6b11f60c70 | ||
|
|
fb266e65cc | ||
|
|
da97c6b88e | ||
|
|
dd34bce38c | ||
|
|
949fbe7826 | ||
|
|
57700813eb | ||
|
|
75fa5fd7c3 | ||
|
|
d53f5cac50 | ||
|
|
74d9b0811e | ||
|
|
e1766196b6 | ||
|
|
b3be12767c | ||
|
|
761c0e6086 | ||
|
|
43598ef6e2 | ||
|
|
60c67613ea | ||
|
|
994e529a37 | ||
|
|
858069cb60 | ||
|
|
6359e79b4c | ||
|
|
dfa1f9fe0d | ||
|
|
83f793e6a6 | ||
|
|
85da102c52 | ||
|
|
143cea84a0 | ||
|
|
f0cd1cfbe3 | ||
|
|
dbbd748c5f | ||
|
|
8baeebad9a | ||
|
|
16a5765042 | ||
|
|
2f02abb81c | ||
|
|
799f4baa1d | ||
|
|
b90aefd4ac | ||
|
|
50f20fe506 | ||
|
|
4719e1851c | ||
|
|
761452f127 | ||
|
|
5a08bdb1e7 | ||
|
|
f4419b0d01 | ||
|
|
b325b5a60f | ||
|
|
37c90e1173 | ||
|
|
a4b3bbf71e | ||
|
|
919af705ee | ||
|
|
09abef31a5 | ||
|
|
09b81b2bab | ||
|
|
5f620768fb | ||
|
|
0c08d8e575 | ||
|
|
13f59c3ea6 | ||
|
|
54486d8bf8 | ||
|
|
f8a5de7385 | ||
|
|
d58efcaa0b | ||
|
|
8a7b3df72d | ||
|
|
11c0fd3ab3 | ||
|
|
6a1cfa6c0b | ||
|
|
d7c93b27ee | ||
|
|
f34079acb8 | ||
|
|
c930cf421e | ||
|
|
9859549f35 | ||
|
|
5216c16e80 | ||
|
|
f2923060f0 | ||
|
|
26fe8ad37a | ||
|
|
c70164e727 | ||
|
|
9adcf488e6 | ||
|
|
139e62dba9 | ||
|
|
d9e31526ba | ||
|
|
01efb543d5 | ||
|
|
c1a0df3bcb | ||
|
|
c347431fb5 | ||
|
|
fca2d6186a | ||
|
|
5397c399f9 | ||
|
|
a6aaabd036 | ||
|
|
b1299aab22 | ||
|
|
3c3f8dc307 | ||
|
|
5438639cff | ||
|
|
d74461fa34 | ||
|
|
9ca2648e2a | ||
|
|
be9a328c93 |
@@ -1,3 +1,382 @@
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24899]
|
||||
* sysdeps/gnu/bits/utmpx.h (struct utmpx): Add
|
||||
__attribute_nonstring__ to ut_line, ut_id, ut_user, ut_host.
|
||||
* sysdeps/unix/sysv/linux/s390/bits/utmpx.h (struct utmpx):
|
||||
Likewise.
|
||||
* sysdeps/gnu/bits/utmp.h (struct utmp): Add
|
||||
__attribute_nonstring__ to ut_id.
|
||||
* sysdeps/unix/sysv/linux/s390/bits/utmpx.h (struct utmp):
|
||||
Likewise.
|
||||
|
||||
2019-08-28 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24902]
|
||||
* login/Makefile (tests): Add tst-pututxline-lockfail.
|
||||
(tst-pututxline-lockfail): Link with -lpthread.
|
||||
* login/utmp_file.c (internal_getut_r): Remove buffer argument.
|
||||
(__libc_getutid_r): Adjust.
|
||||
(__libc_pututline): Likewise. Check for file_offset == -1.
|
||||
* login/tst-pututxline-lockfail.c: New file.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24880]
|
||||
* login/utmp_file.c (file_locking_failed): Use struct flock64.
|
||||
(file_locking_unlock): Likewise.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24879]
|
||||
login: Disarm timer after utmp lock acquisition.
|
||||
* login/utmp_file.c (struct file_locking): Remove.
|
||||
(try_file_lock): Adjust.
|
||||
(file_lock_restore): Remove function.
|
||||
(__libc_getutent_r): .
|
||||
(internal_getut_r): Likewise.
|
||||
(__libc_getutline_r): Likewise.
|
||||
(__libc_pututline): Likewise.
|
||||
(__libc_updwtmp): Likewise.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* login/utmp_file.c (__libc_updwtmp): Unlock the right file
|
||||
descriptor.
|
||||
* login/Makefile (tests): Add tst-updwtmpx.
|
||||
* login/tst-updwtmpx.c: New file.
|
||||
|
||||
2019-08-13 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* login/utmp_file.c (LOCK_FILE, LOCKING_FAILED, UNLOCK_FILE):
|
||||
Remove macros.
|
||||
(struct file_locking): New.
|
||||
(try_file_lock, file_unlock, file_lock_restore): New functions.
|
||||
(__libc_getutent_r): Use the new functions.
|
||||
(internal_getut_r): Likewise.
|
||||
(__libc_getutline_r): Likewise.
|
||||
(__libc_pututline): Likewise.
|
||||
(__libc_updwtmp): Likewise.
|
||||
|
||||
2019-08-13 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* login/getutid_r.c (__getutid_r): _HAVE_UT_ID and _HAVE_UT_TYPE
|
||||
are always true.
|
||||
* login/getutmp.c (getutmp): _HAVE_UT_TYPE, _HAVE_UT_PID,
|
||||
_HAVE_UT_ID, _HAVE_UT_HOST, _HAVE_UT_TV are always true.
|
||||
* login/getutmpx.c (getutmpx): Likewise.
|
||||
* login/login.c (login): _HAVE_UT_TYPE, _HAVE_UT_PID are always
|
||||
true.
|
||||
* login/logout.c (logout): _HAVE_UT_TYPE, _HAVE_UT_HOST,
|
||||
_HAVE_UT_TV are always true.
|
||||
* login/logwtmp.c (logwtmp): _HAVE_UT_PID, _HAVE_UT_TYPE,
|
||||
_HAVE_UT_HOST, _HAVE_UT_TV are always true.
|
||||
* login/tst-utmp.c: _HAVE_UT_TYPE, _HAVE_UT_TV are always true.
|
||||
* login/utmp_file.c (__libc_setutent): _HAVE_UT_TYPE, _HAVE_UT_ID
|
||||
are always true.
|
||||
(internal_getut_r): _HAVE_UT_TYPE is always true.
|
||||
(__libc_pututline): Likewise.
|
||||
* login/programs/utmpdump.c (print_entry): Assume that
|
||||
_HAVE_UT_TYPE, _HAVE_UT_PID, _HAVE_UT_ID, _HAVE_UT_HOST,
|
||||
_HAVE_UT_TV are always true.
|
||||
* sysdeps/generic/utmp-equal.h (__utmp_equal): _HAVE_UT_TYPE,
|
||||
_HAVE_UT_ID are always true.
|
||||
* sysdeps/gnu/bits/utmp.h: Move to ...
|
||||
* bits/utmp.h: ... here, replacing the old file.
|
||||
|
||||
2019-08-05 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #23518]
|
||||
* login/uptmp-private.h (struct ufuncs): Remove definition.
|
||||
(__libc_utmp_file_functions, __libc_utmp_unknown_functions)
|
||||
(__libc_utmp_jump_table): Remove declarations.
|
||||
(__libc_setutent, __libc_getutent_r, __libc_getutid_r)
|
||||
(__libc_getutline_r, __libc_pututline, __libc_endutent)
|
||||
(__libc_updwtmp): Declare.
|
||||
* login/getutent_r.c (__libc_utmp_unknown_functions)
|
||||
(__libc_utmp_jump_table, setutent_unknown, getutent_r_unknown)
|
||||
(getutid_r_unknown, getutline_r_unknown, pututline_unknown)
|
||||
(endutent_unknown): Remove definitions.
|
||||
(__setutent): Call __libc_setutent.
|
||||
(__getutent_r): Call __libc_getutent_r.
|
||||
(__pututline): Call __libc_pututline.
|
||||
(__endutent): Call __libc_endutent.
|
||||
* login/getutid_r.c (__getutid_r): Call __libc_getutid_r.
|
||||
* login/getutline_r.c (__getutline_r): Call __libc_getutline_r.
|
||||
* login/updwtmp.c (__updwtmp): Call __libc_updwtmp.
|
||||
* login/utmp_file.c (__libc_utmp_file_functions): Remove definition
|
||||
(__libc_setutent): Rename from stetutent_file. Drop static.
|
||||
(maybe_setutent): New function.
|
||||
(__libc_getutent_r): Rename from getutent_r_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_getutid_r): Rename from getutid_r_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_getutline_r): Rename from getutline_r_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_pututline): Rename from pututline_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_endutent): Rename from endutent_file. Drop static. Check
|
||||
for initialization.
|
||||
(__libc_updwtmp): Rename from updwtmp_file. Drop static.
|
||||
* login/utmpname.c (__utmpname): Call __libc_endutent.
|
||||
* sysdeps/unix/getlogin_r (__getlogin_r): Call __libc_setutent,
|
||||
__libc_getutlien_r, __libc_endutent.
|
||||
* manual/users.texi (Who Logged In, Manipulating the Database):
|
||||
Adjust.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* malloc/Makefile (tests): Only add tst-mxfast for
|
||||
$(have-tunables).
|
||||
* malloc/tst-mxfast.c: Fix copyright year.
|
||||
(do_test): Fix GNU style issues. Use TEST_COMPARE instead of
|
||||
assert for checks.
|
||||
|
||||
2019-08-09 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* elf/dl-tunables.list: Add glibc.malloc.mxfast.
|
||||
* manual/tunables.texi: Document it.
|
||||
* malloc/malloc.c (do_set_mxfast): New.
|
||||
(__libc_mallopt): Call it.
|
||||
* malloc/arena.c: Add mxfast tunable.
|
||||
* malloc/tst-mxfast.c: New.
|
||||
* malloc/Makefile: Add it.
|
||||
|
||||
2019-08-08 Niklas Hambüchen <mail@nh2.me>
|
||||
Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
[BZ #24026]
|
||||
* malloc/malloc.c (__malloc_info): Account for top chunk.
|
||||
|
||||
2019-11-01 Dragan Mladjenovic <dmladjenovic@wavecomp.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/mips/Makefile
|
||||
(test-xfail-check-execstack):
|
||||
Move under mips-has-gnustack != yes.
|
||||
(CFLAGS-.o*, ASFLAGS-.o*): New rules.
|
||||
Apply -Wa,-execstack if mips-force-execstack == yes.
|
||||
* sysdeps/unix/sysv/linux/mips/configure: Regenerated.
|
||||
* sysdeps/unix/sysv/linux/mips/configure.ac
|
||||
(mips-force-execstack): New var.
|
||||
Set to yes for hard-float builds with minimum_kernel < 4.8.0
|
||||
or minimum_kernel not set at all.
|
||||
(mips-has-gnustack): New var.
|
||||
Use value of libc_cv_as_noexecstack
|
||||
if mips-force-execstack != yes, otherwise set to no.
|
||||
|
||||
2019-10-08 Gabriel F. T. Gomes <gabrielftg@linux.ibm.com>
|
||||
|
||||
* Makefile: Fix locale dependency for a couple of tests.
|
||||
($(objpfx)tst-strftime2.out): New rule.
|
||||
($(objpfx)tst-strftime3.out): Likewise.
|
||||
|
||||
2019-09-20 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/riscv/vfork.S: Do not include
|
||||
<linux/sched.h>.
|
||||
(CLONE_VM): New macro.
|
||||
(CLONE_VFORK): Likewise.
|
||||
|
||||
2019-09-14 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
[BZ #24986]
|
||||
* sysdeps/unix/alpha/getegid.S: Move to ...
|
||||
* sysdeps/unix/sysv/linux/alpha/getegid.S: ... here.
|
||||
* sysdeps/unix/alpha/geteuid.S: Move to ...
|
||||
* sysdeps/unix/sysv/linux/alpha/geteuid.S: ... here.
|
||||
* sysdeps/unix/alpha/getppid.S: Move to ...
|
||||
* sysdeps/unix/sysv/linux/alpha/getppid.S: ... here
|
||||
|
||||
2019-09-08 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
* sysdeps/hppa/fpu/libm-test-ulps: Update.
|
||||
|
||||
2019-09-03 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
* sysdeps/alpha/fpu/libm-test-ulps: Regenerated using GCC 9.2.
|
||||
|
||||
2019-08-28 Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
|
||||
[BZ #24682]
|
||||
* NEWS: Mention this bug fixed.
|
||||
* localedata/locales/bo_CN (first_weekday): Add, set to 2 (Monday).
|
||||
* localedata/locales/ug_CN (first_weekday): Likewise.
|
||||
* localedata/locales/zh_CN (first_weekday): Likewise.
|
||||
|
||||
2019-08-01 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24867]
|
||||
* malloc/malloc.c (__malloc_info): Remove unwanted leading
|
||||
whitespace.
|
||||
|
||||
2019-10-02 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_private.h:
|
||||
(__TEST_AND_BEGIN_NON_STOP): New.
|
||||
(__TEST_AND_END_NON_STOP): New.
|
||||
(libc_feholdexcept_setround_ppc): Use __TEST_AND_BEGIN_NON_STOP.
|
||||
(__libc_femergeenv_ppc): Use __TEST_AND_BEGIN_NON_STOP and
|
||||
__TEST_AND_END_NON_STOP.
|
||||
(libc_feholdsetround_noex_ppc_ctx): Use __TEST_AND_END_NON_STOP.
|
||||
|
||||
2019-09-27 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (fesetenv_mode): Rename to
|
||||
fesetenv_control.
|
||||
* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Accommodate
|
||||
rename of fesetenv_mode to fegetenv_control.
|
||||
* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise.
|
||||
* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Likewise.
|
||||
* sysdeps/powerpc/fpu/fenv_private.h (__libc_femergeenv_ppc): Likewise.
|
||||
(libc_feholdsetround_noex_ppc_ctx): Likewise.
|
||||
|
||||
2019-09-27 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_private.h
|
||||
(libc_feholdsetround_noex_ppc_ctx): Call fesetenv_mode instead
|
||||
of fesetenv_register.
|
||||
|
||||
2019-09-27 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_status): Rename to
|
||||
fegetenv_control.
|
||||
* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Accommodate
|
||||
rename of fegetenv_status to fegetenv_control.
|
||||
* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise.
|
||||
* sysdeps/powerpc/fpu/fegetexcept.c (__fegetexcept): Likewise.
|
||||
* sysdeps/powerpc/fpu/fegetmode.c (fegetmode): Likewise.
|
||||
* sysdeps/powerpc/fpu/fesetenv.c (__fesetenv): Likewise.
|
||||
* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Likewise.
|
||||
|
||||
2019-09-27 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (__fesetround_inline): Use
|
||||
'mffscrn' instruction on POWER9.
|
||||
(__fesetround_inline_nocheck): Likewise.
|
||||
|
||||
2019-09-27 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (FPSCR_EXCEPTIONS_MASK): New.
|
||||
* sysdeps/powerpc/fpu/fenv_private.h (__libc_femergeenv_ppc): Optimize
|
||||
to write FPSCR control only, if exceptions have not changed.
|
||||
|
||||
2019-09-27 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h:
|
||||
(__TEST_AND_ENTER_NON_STOP): New.
|
||||
(__TEST_AND_EXIT_NON_STOP): New.
|
||||
* sysdeps/powerpc/fpu/fenv_private.h
|
||||
(_FPU_ALL_TRAPS): Delete, replace with FPSCR_ENABLES_MASK.
|
||||
(_FPU_MASK_RN): Delete.
|
||||
(_FPU_MASK_NOT_RN_NI): Delete.
|
||||
(_FPU_MASK_TRAPS_RN): Delete, replace with ~FPSCR_CONTROL_MASK.
|
||||
(_FPU_MASK_FRAC_INEX_RET_CC): Delete, replace with ~FPSCR_STATUS_MASK.
|
||||
(__libc_feholdbits_ppc): Delete, move code into
|
||||
libc_feholdexcept_setround_ppc.
|
||||
(libc_feholdexcept_ppc): Delete.
|
||||
(libc_fesetround_ppc): Delete.
|
||||
(libc_fetestexcept_ppc): Delete.
|
||||
(libc_feholdsetround_ppc): Delete.
|
||||
(__libc_femergeenv_ppc): Use __TEST_AND_ENTER/EXIT_NON_STOP.
|
||||
(libc_feholdsetround_noex_ppc_ctx): Likewise.
|
||||
(libc_feupdateenv_test_ppc): Use FPSCR defines.
|
||||
* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Use
|
||||
__TEST_AND_ENTER_NON_STOP.
|
||||
* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Likewise.
|
||||
* sysdeps/powerpc/fpu/feholdexcpt.c (__feholdexcept): Likewise.
|
||||
* sysdeps/powerpc/fpu/fesetenv.c (__fesetenv): Likewise.
|
||||
* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Likewise.
|
||||
* sysdeps/powerpc/fpu/feupdateenv.c (__feupdateenv): Likewise.
|
||||
(_FPU_MASK_ALL): Delete.
|
||||
|
||||
2019-09-19 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_and_set_rn): New.
|
||||
(__fe_mffscrn): New.
|
||||
* sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx):
|
||||
Do not clear enable bits, remove obsolete code, use
|
||||
fegetenv_and_set_rn.
|
||||
(libc_feresetround_ppc): Remove obsolete code, use
|
||||
fegetenv_and_set_rn.
|
||||
|
||||
2019-08-28 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_status_ISA300): Delete.
|
||||
(fegetenv_status): Generate 'mffsl' unconditionally.
|
||||
|
||||
2019-08-28 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fesetenv.c (__fesetenv): Utilize lightweight
|
||||
FPSCR read.
|
||||
(_FPU_MASK_ALL): Delete.
|
||||
|
||||
2019-08-28 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx):
|
||||
Utilize lightweight FPSCR read if possible, set fewer FPSCR bits
|
||||
if possible.
|
||||
(libc_feresetround_ppc): Replace call to __libc_femergeenv_ppc
|
||||
with simpler required steps, set fewer FPSCR bits if possible.
|
||||
|
||||
2019-08-28 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (fesetenv_mode): New.
|
||||
(FPSCR_FPRF_MASK): New. (FPSCR_STATUS_MASK): New.
|
||||
* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Use lighter-
|
||||
weight access to FPSCR; remove unnecessary second FPSCR read and
|
||||
validate.
|
||||
* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Likewise.
|
||||
* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Use lighter-weight
|
||||
access to FPSCR; Use macros in fenv_libc.h in favor of local.
|
||||
|
||||
2019-08-28 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h: Define FPSCR bitmasks.
|
||||
(fenv_reg_to_exceptions): Replace bitwise operations with mask-shift.
|
||||
(fenv_exceptions_to_reg): New.
|
||||
* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Replace bitwise
|
||||
operation with call to fenv_exceptions_to_reg().
|
||||
* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise.
|
||||
|
||||
2019-09-20 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/riscv/vfork.S: Do not include
|
||||
<linux/sched.h>.
|
||||
(CLONE_VM): New macro.
|
||||
(CLONE_VFORK): Likewise.
|
||||
|
||||
2019-09-14 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
[BZ #24986]
|
||||
* sysdeps/unix/alpha/getegid.S: Move to ...
|
||||
* sysdeps/unix/sysv/linux/alpha/getegid.S: ... here.
|
||||
* sysdeps/unix/alpha/geteuid.S: Move to ...
|
||||
* sysdeps/unix/sysv/linux/alpha/geteuid.S: ... here.
|
||||
* sysdeps/unix/alpha/getppid.S: Move to ...
|
||||
* sysdeps/unix/sysv/linux/alpha/getppid.S: ... here
|
||||
|
||||
2019-09-08 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
* sysdeps/hppa/fpu/libm-test-ulps: Update.
|
||||
|
||||
2019-09-03 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
* sysdeps/alpha/fpu/libm-test-ulps: Regenerated using GCC 9.2.
|
||||
|
||||
2019-08-28 Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
|
||||
[BZ #24682]
|
||||
* NEWS: Mention this bug fixed.
|
||||
* localedata/locales/bo_CN (first_weekday): Add, set to 2 (Monday).
|
||||
* localedata/locales/ug_CN (first_weekday): Likewise.
|
||||
* localedata/locales/zh_CN (first_weekday): Likewise.
|
||||
|
||||
2019-08-01 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24867]
|
||||
* malloc/malloc.c (__malloc_info): Remove unwanted leading
|
||||
whitespace.
|
||||
|
||||
2019-08-01 Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
* version.h (RELEASE): Set to "stable".
|
||||
|
||||
@@ -4,6 +4,81 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.30.1
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2019-19126: ld.so failed to ignore the LD_PREFER_MAP_32BIT_EXEC
|
||||
environment variable during program execution after a security
|
||||
transition, allowing local attackers to restrict the possible mapping
|
||||
addresses for loaded libraries and thus bypass ASLR for a setuid
|
||||
program. Reported by Marcin Kościelnicki.
|
||||
|
||||
CVE-2020-10029: Trigonometric functions on x86 targets suffered from stack
|
||||
corruption when they were passed a pseudo-zero argument. Reported by Guido
|
||||
Vranken / ForAllSecure Mayhem.
|
||||
|
||||
CVE-2020-1751: A defect in the PowerPC backtrace function could cause an
|
||||
out-of-bounds write when executed in a signal frame context.
|
||||
|
||||
CVE-2020-1752: A use-after-free vulnerability in the glob function when
|
||||
expanding ~user has been fixed.
|
||||
|
||||
CVE-2020-27618: An infinite loop has been fixed in the iconv program when
|
||||
invoked with input containing redundant shift sequences in the IBM1364,
|
||||
IBM1371, IBM1388, IBM1390, or IBM1399 character sets.
|
||||
|
||||
CVE-2020-29562: An assertion failure has been fixed in the iconv function
|
||||
when invoked with UCS4 input containing an invalid character.
|
||||
|
||||
CVE-2021-3326: An assertion failure during conversion from the
|
||||
ISO-20220-JP-3 character set using the iconv function has been fixed.
|
||||
This assertion was triggered by certain valid inputs in which the
|
||||
converted output contains a combined sequence of two wide characters
|
||||
crossing a buffer boundary. Reported by Tavis Ormandy.
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT
|
||||
[20543] Please move from .gnu.linkonce to comdat
|
||||
[23296] Data race in setting function descriptor during lazy binding
|
||||
[23518] login: Remove utmp backend jump tables
|
||||
[24682] localedata: zh_CN first weekday should be Monday per GB/T
|
||||
7408-2005
|
||||
[24867] malloc: Remove unwanted leading whitespace in malloc_info
|
||||
[24879] login: Disarm timer after utmp lock acquisition
|
||||
[24880] login: Use struct flock64 in utmp
|
||||
[24882] login: Acquire write lock early in pututline
|
||||
[24986] alpha: new getegid, geteuid and getppid syscalls used
|
||||
unconditionally
|
||||
[24899] login: Add nonstring attributes to struct utmp, struct utmpx
|
||||
[24902] login: pututxline could fail to overwrite existing entries
|
||||
[25066] FAIL: nptl/tst-tls1 on hppa
|
||||
[25189] Don't use a custom wrapper macro around __has_include
|
||||
[25203] libio: Disable vtable validation for pre-2.1 interposed handles
|
||||
[25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs
|
||||
[25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection
|
||||
[25232] No const correctness for strchr et al. for Clang++
|
||||
[25401] Remove incorrect alloc_size attribute from pvalloc
|
||||
[25487] sinl() stack corruption from crafted input (CVE-2020-10029)
|
||||
[25523] MIPS/Linux inline syscall template is miscompiled
|
||||
[25635] arm: Wrong sysdep order selection for soft-fp
|
||||
[25715] system() returns wrong errors when posix_spawn fails
|
||||
[25810] x32: Incorrect syscall entries with pointer, off_t and size_t
|
||||
[25896] Incorrect prctl
|
||||
[25902] Bad LOADARGS_N
|
||||
[25933] Off by one error in __strncmp_avx2
|
||||
[25966] Incorrect access of __x86_shared_non_temporal_threshold for x32
|
||||
[25976] nss_compat: internal_end*ent may clobber errno, hiding ERANGE
|
||||
[27130] "rep movsb" performance issue
|
||||
[27177] GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on doesn't work
|
||||
[27457] vzeroupper use in AVX2 multiarch string functions cause HTM aborts
|
||||
[27974] Overflow bug in some implementation of wcsnlen, wmemchr, and wcsncat
|
||||
[28755] overflow bug in wcsncmp_avx2 and wcsncmp_evex
|
||||
[28896] strncmp-avx2-rtm and wcsncmp-avx2-rtm fallback on non-rtm
|
||||
variants when avoiding overflow
|
||||
|
||||
|
||||
Version 2.30
|
||||
|
||||
|
||||
+91
-13
@@ -1,4 +1,4 @@
|
||||
/* The `struct utmp' type, describing entries in the utmp file. Generic/BSDish
|
||||
/* The `struct utmp' type, describing entries in the utmp file.
|
||||
Copyright (C) 1993-2019 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
@@ -21,29 +21,107 @@
|
||||
#endif
|
||||
|
||||
#include <paths.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <bits/wordsize.h>
|
||||
|
||||
|
||||
#define UT_NAMESIZE 8
|
||||
#define UT_LINESIZE 8
|
||||
#define UT_HOSTSIZE 16
|
||||
#define UT_LINESIZE 32
|
||||
#define UT_NAMESIZE 32
|
||||
#define UT_HOSTSIZE 256
|
||||
|
||||
|
||||
/* The structure describing an entry in the database of
|
||||
previous logins. */
|
||||
struct lastlog
|
||||
{
|
||||
time_t ll_time;
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ll_time;
|
||||
#else
|
||||
__time_t ll_time;
|
||||
#endif
|
||||
char ll_line[UT_LINESIZE];
|
||||
char ll_host[UT_HOSTSIZE];
|
||||
};
|
||||
|
||||
struct utmp
|
||||
|
||||
/* The structure describing the status of a terminated process. This
|
||||
type is used in `struct utmp' below. */
|
||||
struct exit_status
|
||||
{
|
||||
char ut_line[UT_LINESIZE];
|
||||
char ut_user[UT_NAMESIZE];
|
||||
#define ut_name ut_user
|
||||
char ut_host[UT_HOSTSIZE];
|
||||
long int ut_time;
|
||||
short int e_termination; /* Process termination status. */
|
||||
short int e_exit; /* Process exit status. */
|
||||
};
|
||||
|
||||
|
||||
#define _HAVE_UT_HOST 1 /* We have the ut_host field. */
|
||||
/* The structure describing an entry in the user accounting database. */
|
||||
struct utmp
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]
|
||||
__attribute_nonstring__; /* Inittab ID. */
|
||||
char ut_user[UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
/* The ut_session and ut_tv fields must be the same size when compiled
|
||||
32- and 64-bit. This allows data files and shared memory to be
|
||||
shared between 32- and 64-bit applications. */
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ut_session; /* Session ID, used for windowing. */
|
||||
struct
|
||||
{
|
||||
int32_t tv_sec; /* Seconds. */
|
||||
int32_t tv_usec; /* Microseconds. */
|
||||
} ut_tv; /* Time entry was made. */
|
||||
#else
|
||||
long int ut_session; /* Session ID, used for windowing. */
|
||||
struct timeval ut_tv; /* Time entry was made. */
|
||||
#endif
|
||||
|
||||
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
|
||||
char __glibc_reserved[20]; /* Reserved for future use. */
|
||||
};
|
||||
|
||||
/* Backwards compatibility hacks. */
|
||||
#define ut_name ut_user
|
||||
#ifndef _NO_UT_TIME
|
||||
/* We have a problem here: `ut_time' is also used otherwise. Define
|
||||
_NO_UT_TIME if the compiler complains. */
|
||||
# define ut_time ut_tv.tv_sec
|
||||
#endif
|
||||
#define ut_xtime ut_tv.tv_sec
|
||||
#define ut_addr ut_addr_v6[0]
|
||||
|
||||
|
||||
/* Values for the `ut_type' field of a `struct utmp'. */
|
||||
#define EMPTY 0 /* No valid user accounting information. */
|
||||
|
||||
#define RUN_LVL 1 /* The system's runlevel. */
|
||||
#define BOOT_TIME 2 /* Time of system boot. */
|
||||
#define NEW_TIME 3 /* Time after system clock changed. */
|
||||
#define OLD_TIME 4 /* Time when system clock changed. */
|
||||
|
||||
#define INIT_PROCESS 5 /* Process spawned by the init process. */
|
||||
#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */
|
||||
#define USER_PROCESS 7 /* Normal process. */
|
||||
#define DEAD_PROCESS 8 /* Terminated process. */
|
||||
|
||||
#define ACCOUNTING 9
|
||||
|
||||
/* Old Linux name for the EMPTY type. */
|
||||
#define UT_UNKNOWN EMPTY
|
||||
|
||||
|
||||
/* Tell the user that we have a modern system with UT_HOST, UT_PID,
|
||||
UT_TYPE, UT_ID and UT_TV fields. */
|
||||
#define _HAVE_UT_TYPE 1
|
||||
#define _HAVE_UT_PID 1
|
||||
#define _HAVE_UT_ID 1
|
||||
#define _HAVE_UT_TV 1
|
||||
#define _HAVE_UT_HOST 1
|
||||
|
||||
@@ -3777,11 +3777,32 @@ else
|
||||
fi
|
||||
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
#ifndef __CET__
|
||||
#error no CET compiler support
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
libc_cv_compiler_default_cet=yes
|
||||
else
|
||||
libc_cv_compiler_default_cet=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
|
||||
# Check whether --enable-cet was given.
|
||||
if test "${enable_cet+set}" = set; then :
|
||||
enableval=$enable_cet; enable_cet=$enableval
|
||||
else
|
||||
enable_cet=no
|
||||
enable_cet=$libc_cv_compiler_default_cet
|
||||
fi
|
||||
|
||||
|
||||
@@ -4014,7 +4035,7 @@ if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
|
||||
-o conftest conftest.S 1>&5 2>&5; then
|
||||
# Do a link to see if the backend supports IFUNC relocs.
|
||||
$READELF -r conftest 1>&5
|
||||
LC_ALL=C $READELF -r conftest | grep 'no relocations' >/dev/null || {
|
||||
LC_ALL=C $READELF -Wr conftest | grep -q 'IRELATIVE\|R_SPARC_JMP_IREL' && {
|
||||
libc_cv_ld_gnu_indirect_function=yes
|
||||
}
|
||||
fi
|
||||
|
||||
+9
-2
@@ -472,11 +472,18 @@ AC_ARG_ENABLE([mathvec],
|
||||
[build_mathvec=$enableval],
|
||||
[build_mathvec=notset])
|
||||
|
||||
AC_TRY_COMPILE([], [
|
||||
#ifndef __CET__
|
||||
# error no CET compiler support
|
||||
#endif],
|
||||
[libc_cv_compiler_default_cet=yes],
|
||||
[libc_cv_compiler_default_cet=no])
|
||||
|
||||
AC_ARG_ENABLE([cet],
|
||||
AC_HELP_STRING([--enable-cet],
|
||||
[enable Intel Control-flow Enforcement Technology (CET), x86 only]),
|
||||
[enable_cet=$enableval],
|
||||
[enable_cet=no])
|
||||
[enable_cet=$libc_cv_compiler_default_cet])
|
||||
|
||||
# We keep the original values in `$config_*' and never modify them, so we
|
||||
# can write them unchanged into config.make. Everything else uses
|
||||
@@ -641,7 +648,7 @@ if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
|
||||
-o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
|
||||
# Do a link to see if the backend supports IFUNC relocs.
|
||||
$READELF -r conftest 1>&AS_MESSAGE_LOG_FD
|
||||
LC_ALL=C $READELF -r conftest | grep 'no relocations' >/dev/null || {
|
||||
LC_ALL=C $READELF -Wr conftest | grep -q 'IRELATIVE\|R_SPARC_JMP_IREL' && {
|
||||
libc_cv_ld_gnu_indirect_function=yes
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -89,6 +89,18 @@ handle_signal (int signum)
|
||||
}
|
||||
/* Symbol names are not available for static functions, so we do not
|
||||
check do_test. */
|
||||
|
||||
/* Check that backtrace does not return more than what fits in the array
|
||||
(bug 25423). */
|
||||
for (int j = 0; j < NUM_FUNCTIONS; j++)
|
||||
{
|
||||
n = backtrace (addresses, j);
|
||||
if (n > j)
|
||||
{
|
||||
FAIL ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NO_INLINE int
|
||||
|
||||
+2
-2
@@ -1302,6 +1302,8 @@ CFLAGS-ifuncmain7pie.c += $(pie-ccflag)
|
||||
CFLAGS-ifuncmain9pie.c += $(pie-ccflag)
|
||||
CFLAGS-tst-ifunc-textrel.c += $(pic-ccflag)
|
||||
|
||||
LDFLAGS-ifuncmain6pie = -Wl,-z,lazy
|
||||
|
||||
$(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so
|
||||
$(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o
|
||||
$(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so
|
||||
@@ -1512,8 +1514,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
|
||||
|
||||
tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
|
||||
LD_HWCAP_MASK=0x1
|
||||
tst-env-setuid-tunables-ENV = \
|
||||
GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
|
||||
|
||||
$(objpfx)tst-debug1: $(libdl)
|
||||
$(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
|
||||
|
||||
+26
-30
@@ -178,6 +178,7 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
return;
|
||||
|
||||
char *p = tunestr;
|
||||
size_t off = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -191,7 +192,11 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
/* If we reach the end of the string before getting a valid name-value
|
||||
pair, bail out. */
|
||||
if (p[len] == '\0')
|
||||
return;
|
||||
{
|
||||
if (__libc_enable_secure)
|
||||
tunestr[off] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
/* We did not find a valid name-value pair before encountering the
|
||||
colon. */
|
||||
@@ -217,35 +222,28 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
|
||||
if (tunable_is_name (cur->name, name))
|
||||
{
|
||||
/* If we are in a secure context (AT_SECURE) then ignore the tunable
|
||||
unless it is explicitly marked as secure. Tunable values take
|
||||
precendence over their envvar aliases. */
|
||||
/* If we are in a secure context (AT_SECURE) then ignore the
|
||||
tunable unless it is explicitly marked as secure. Tunable
|
||||
values take precedence over their envvar aliases. We write
|
||||
the tunables that are not SXID_ERASE back to TUNESTR, thus
|
||||
dropping all SXID_ERASE tunables and any invalid or
|
||||
unrecognized tunables. */
|
||||
if (__libc_enable_secure)
|
||||
{
|
||||
if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
|
||||
if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
|
||||
{
|
||||
if (p[len] == '\0')
|
||||
{
|
||||
/* Last tunable in the valstring. Null-terminate and
|
||||
return. */
|
||||
*name = '\0';
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove the current tunable from the string. We do
|
||||
this by overwriting the string starting from NAME
|
||||
(which is where the current tunable begins) with
|
||||
the remainder of the string. We then have P point
|
||||
to NAME so that we continue in the correct
|
||||
position in the valstring. */
|
||||
char *q = &p[len + 1];
|
||||
p = name;
|
||||
while (*q != '\0')
|
||||
*name++ = *q++;
|
||||
name[0] = '\0';
|
||||
len = 0;
|
||||
}
|
||||
if (off > 0)
|
||||
tunestr[off++] = ':';
|
||||
|
||||
const char *n = cur->name;
|
||||
|
||||
while (*n != '\0')
|
||||
tunestr[off++] = *n++;
|
||||
|
||||
tunestr[off++] = '=';
|
||||
|
||||
for (size_t j = 0; j < len; j++)
|
||||
tunestr[off++] = value[j];
|
||||
}
|
||||
|
||||
if (cur->security_level != TUNABLE_SECLEVEL_NONE)
|
||||
@@ -258,9 +256,7 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
}
|
||||
}
|
||||
|
||||
if (p[len] == '\0')
|
||||
return;
|
||||
else
|
||||
if (p[len] != '\0')
|
||||
p += len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,11 @@ glibc {
|
||||
tcache_unsorted_limit {
|
||||
type: SIZE_T
|
||||
}
|
||||
mxfast {
|
||||
type: SIZE_T
|
||||
minval: 0
|
||||
security_level: SXID_IGNORE
|
||||
}
|
||||
}
|
||||
cpu {
|
||||
hwcap_mask {
|
||||
|
||||
@@ -142,10 +142,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
assert (info[DT_FLAGS] == NULL
|
||||
|| (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
|
||||
#endif
|
||||
#if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP
|
||||
assert (info[DT_RUNPATH] == NULL);
|
||||
assert (info[DT_RPATH] == NULL);
|
||||
#else
|
||||
#if ! defined RTLD_BOOTSTRAP && ! defined STATIC_PIE_BOOTSTRAP
|
||||
if (info[DT_FLAGS] != NULL)
|
||||
{
|
||||
/* Flags are used. Translate to the old form where available.
|
||||
|
||||
+3
-11
@@ -9,7 +9,6 @@
|
||||
#include "ifunc-sel.h"
|
||||
|
||||
typedef int (*foo_p) (void);
|
||||
extern foo_p foo_ptr;
|
||||
|
||||
static int
|
||||
one (void)
|
||||
@@ -28,20 +27,17 @@ foo_ifunc (void)
|
||||
}
|
||||
|
||||
extern int foo (void);
|
||||
extern foo_p get_foo (void);
|
||||
extern int call_foo (void);
|
||||
extern foo_p get_foo_p (void);
|
||||
|
||||
foo_p my_foo_ptr = foo;
|
||||
foo_p foo_ptr = foo;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
foo_p p;
|
||||
|
||||
p = get_foo ();
|
||||
if (p != foo)
|
||||
abort ();
|
||||
if ((*p) () != -30)
|
||||
if (call_foo () != -30)
|
||||
abort ();
|
||||
|
||||
p = get_foo_p ();
|
||||
@@ -52,12 +48,8 @@ main (void)
|
||||
|
||||
if (foo_ptr != foo)
|
||||
abort ();
|
||||
if (my_foo_ptr != foo)
|
||||
abort ();
|
||||
if ((*foo_ptr) () != -30)
|
||||
abort ();
|
||||
if ((*my_foo_ptr) () != -30)
|
||||
abort ();
|
||||
if (foo () != -30)
|
||||
abort ();
|
||||
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ extern int foo (void);
|
||||
|
||||
typedef int (*foo_p) (void);
|
||||
|
||||
foo_p foo_ptr = foo;
|
||||
extern foo_p foo_ptr;
|
||||
|
||||
foo_p
|
||||
get_foo_p (void)
|
||||
@@ -12,8 +12,8 @@ get_foo_p (void)
|
||||
return foo_ptr;
|
||||
}
|
||||
|
||||
foo_p
|
||||
get_foo (void)
|
||||
int
|
||||
call_foo (void)
|
||||
{
|
||||
return foo;
|
||||
return foo ();
|
||||
}
|
||||
|
||||
@@ -25,35 +25,76 @@
|
||||
#include "config.h"
|
||||
#undef _LIBC
|
||||
|
||||
#define test_parent test_parent_tunables
|
||||
#define test_child test_child_tunables
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <intprops.h>
|
||||
#include <array_length.h>
|
||||
|
||||
static int test_child_tunables (void);
|
||||
static int test_parent_tunables (void);
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
|
||||
#include "tst-env-setuid.c"
|
||||
const char *teststrings[] =
|
||||
{
|
||||
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
|
||||
"glibc.malloc.perturb=0x800",
|
||||
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
|
||||
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
|
||||
":glibc.malloc.garbage=2:glibc.malloc.check=1",
|
||||
"glibc.malloc.check=1:glibc.malloc.check=2",
|
||||
"not_valid.malloc.check=2",
|
||||
"glibc.not_valid.check=2",
|
||||
};
|
||||
|
||||
#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
|
||||
#define PARENT_VALSTRING_VALUE \
|
||||
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
|
||||
const char *resultstrings[] =
|
||||
{
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.perturb=0x800",
|
||||
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
};
|
||||
|
||||
static int
|
||||
test_child_tunables (void)
|
||||
test_child (int off)
|
||||
{
|
||||
const char *val = getenv ("GLIBC_TUNABLES");
|
||||
|
||||
#if HAVE_TUNABLES
|
||||
if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
|
||||
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
|
||||
return 0;
|
||||
|
||||
if (val != NULL)
|
||||
printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
|
||||
printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
if (val != NULL)
|
||||
{
|
||||
printf ("GLIBC_TUNABLES not cleared\n");
|
||||
printf ("[%d] GLIBC_TUNABLES not cleared\n", off);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -61,15 +102,48 @@ test_child_tunables (void)
|
||||
}
|
||||
|
||||
static int
|
||||
test_parent_tunables (void)
|
||||
do_test (int argc, char **argv)
|
||||
{
|
||||
const char *val = getenv ("GLIBC_TUNABLES");
|
||||
/* Setgid child process. */
|
||||
if (argc == 2)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
|
||||
if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
|
||||
return 0;
|
||||
int ret = test_child (atoi (argv[1]));
|
||||
|
||||
if (val != NULL)
|
||||
printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
|
||||
if (ret != 0)
|
||||
exit (1);
|
||||
|
||||
return 1;
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Spawn tests. */
|
||||
for (int i = 0; i < array_length (teststrings); i++)
|
||||
{
|
||||
char buf[INT_BUFSIZE_BOUND (int)];
|
||||
|
||||
printf ("Spawned test for %s (%d)\n", teststrings[i], i);
|
||||
snprintf (buf, sizeof (buf), "%d\n", i);
|
||||
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
|
||||
exit (1);
|
||||
|
||||
int status = support_capture_subprogram_self_sgid (buf);
|
||||
|
||||
/* Bail out early if unsupported. */
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
ret |= status;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION_ARGV do_test
|
||||
#include <support/test-driver.c>
|
||||
|
||||
+14
-183
@@ -29,173 +29,12 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
|
||||
static char SETGID_CHILD[] = "setgid-child";
|
||||
#define CHILD_STATUS 42
|
||||
|
||||
/* Return a GID which is not our current GID, but is present in the
|
||||
supplementary group list. */
|
||||
static gid_t
|
||||
choose_gid (void)
|
||||
{
|
||||
const int count = 64;
|
||||
gid_t groups[count];
|
||||
int ret = getgroups (count, groups);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("getgroups: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
gid_t current = getgid ();
|
||||
for (int i = 0; i < ret; ++i)
|
||||
{
|
||||
if (groups[i] != current)
|
||||
return groups[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */
|
||||
static pid_t
|
||||
do_execve (char **args)
|
||||
{
|
||||
pid_t kid = vfork ();
|
||||
|
||||
if (kid < 0)
|
||||
{
|
||||
printf ("vfork: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kid == 0)
|
||||
{
|
||||
/* Child process. */
|
||||
execve (args[0], args, environ);
|
||||
_exit (-errno);
|
||||
}
|
||||
|
||||
if (kid < 0)
|
||||
return 1;
|
||||
|
||||
int status;
|
||||
|
||||
if (waitpid (kid, &status, 0) < 0)
|
||||
{
|
||||
printf ("waitpid: %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
|
||||
{
|
||||
printf ("Unexpected exit status %d from child process\n",
|
||||
WEXITSTATUS (status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copies the executable into a restricted directory, so that we can
|
||||
safely make it SGID with the TARGET group ID. Then runs the
|
||||
executable. */
|
||||
static int
|
||||
run_executable_sgid (gid_t target)
|
||||
{
|
||||
char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
|
||||
test_dir, (intmax_t) getpid ());
|
||||
char *execname = xasprintf ("%s/bin", dirname);
|
||||
int infd = -1;
|
||||
int outfd = -1;
|
||||
int ret = 0;
|
||||
if (mkdir (dirname, 0700) < 0)
|
||||
{
|
||||
printf ("mkdir: %m\n");
|
||||
goto err;
|
||||
}
|
||||
infd = open ("/proc/self/exe", O_RDONLY);
|
||||
if (infd < 0)
|
||||
{
|
||||
printf ("open (/proc/self/exe): %m\n");
|
||||
goto err;
|
||||
}
|
||||
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
|
||||
if (outfd < 0)
|
||||
{
|
||||
printf ("open (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
char buf[4096];
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rdcount = read (infd, buf, sizeof (buf));
|
||||
if (rdcount < 0)
|
||||
{
|
||||
printf ("read: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (rdcount == 0)
|
||||
break;
|
||||
char *p = buf;
|
||||
char *end = buf + rdcount;
|
||||
while (p != end)
|
||||
{
|
||||
ssize_t wrcount = write (outfd, buf, end - p);
|
||||
if (wrcount == 0)
|
||||
errno = ENOSPC;
|
||||
if (wrcount <= 0)
|
||||
{
|
||||
printf ("write: %m\n");
|
||||
goto err;
|
||||
}
|
||||
p += wrcount;
|
||||
}
|
||||
}
|
||||
if (fchown (outfd, getuid (), target) < 0)
|
||||
{
|
||||
printf ("fchown (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (fchmod (outfd, 02750) < 0)
|
||||
{
|
||||
printf ("fchmod (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (close (outfd) < 0)
|
||||
{
|
||||
printf ("close (outfd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (close (infd) < 0)
|
||||
{
|
||||
printf ("close (infd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
char *args[] = {execname, SETGID_CHILD, NULL};
|
||||
|
||||
ret = do_execve (args);
|
||||
|
||||
err:
|
||||
if (outfd >= 0)
|
||||
close (outfd);
|
||||
if (infd >= 0)
|
||||
close (infd);
|
||||
if (execname)
|
||||
{
|
||||
unlink (execname);
|
||||
free (execname);
|
||||
}
|
||||
if (dirname)
|
||||
{
|
||||
rmdir (dirname);
|
||||
free (dirname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef test_child
|
||||
static int
|
||||
@@ -256,40 +95,32 @@ do_test (int argc, char **argv)
|
||||
if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
{
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
exit (EXIT_UNSUPPORTED);
|
||||
}
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
|
||||
int ret = test_child ();
|
||||
|
||||
if (ret != 0)
|
||||
exit (1);
|
||||
|
||||
exit (CHILD_STATUS);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test_parent () != 0)
|
||||
exit (1);
|
||||
|
||||
/* Try running a setgid program. */
|
||||
gid_t target = choose_gid ();
|
||||
if (target == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Could not find a suitable GID for user %jd, skipping test\n",
|
||||
(intmax_t) getuid ());
|
||||
exit (0);
|
||||
}
|
||||
int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
|
||||
|
||||
return run_executable_sgid (target);
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (!WIFEXITED (status))
|
||||
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Something went wrong and our argv was corrupted. */
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION_ARGV do_test
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ CFLAGS-linereader.c += -DNO_TRANSLITERATION
|
||||
CFLAGS-simple-hash.c += -I../locale
|
||||
|
||||
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \
|
||||
tst-iconv7 tst-iconv-mt
|
||||
tst-iconv7 tst-iconv8 tst-iconv-mt
|
||||
|
||||
others = iconv_prog iconvconfig
|
||||
install-others-programs = $(inst_bindir)/iconv
|
||||
|
||||
+4
-12
@@ -239,11 +239,9 @@ ucs4_internal_loop (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
uint32_t inval;
|
||||
|
||||
@@ -307,11 +305,9 @@ ucs4_internal_loop_unaligned (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
if (__glibc_unlikely (inptr[0] > 0x80))
|
||||
{
|
||||
@@ -613,11 +609,9 @@ ucs4le_internal_loop (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
uint32_t inval;
|
||||
|
||||
@@ -684,11 +678,9 @@ ucs4le_internal_loop_unaligned (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
if (__glibc_unlikely (inptr[3] > 0x80))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Test iconv behavior on UCS4 conversions with //IGNORE.
|
||||
Copyright (C) 2020 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Derived from BZ #26923 */
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
iconv_t cd = iconv_open ("UTF-8//IGNORE", "ISO-10646/UCS4/");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
/*
|
||||
* Convert sequence beginning with an irreversible character into buffer that
|
||||
* is too small.
|
||||
*/
|
||||
char input[12] = "\xe1\x80\xa1" "AAAAAAAAA";
|
||||
char *inptr = input;
|
||||
size_t insize = sizeof (input);
|
||||
char output[6];
|
||||
char *outptr = output;
|
||||
size_t outsize = sizeof (output);
|
||||
|
||||
TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == -1);
|
||||
TEST_VERIFY (errno == E2BIG);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,284 @@
|
||||
#!/bin/bash
|
||||
# Test for some known iconv(1) hangs from bug 19519, and miscellaneous
|
||||
# iconv(1) program error conditions.
|
||||
# Copyright (C) 2020 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/>.
|
||||
|
||||
codir=$1
|
||||
test_wrapper_env="$2"
|
||||
run_program_env="$3"
|
||||
|
||||
# We have to have some directories in the library path.
|
||||
LIBPATH=$codir:$codir/iconvdata
|
||||
|
||||
# How the start the iconv(1) program. $from is not defined/expanded yet.
|
||||
ICONV='
|
||||
$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so
|
||||
$codir/iconv/iconv_prog
|
||||
'
|
||||
ICONV="$test_wrapper_env $run_program_env $ICONV"
|
||||
|
||||
# List of known hangs;
|
||||
# Gathered by running an exhaustive 2 byte input search against glibc-2.28
|
||||
hangarray=(
|
||||
"\x00\x23;-c;ANSI_X3.110;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa1;-c;ARMSCII-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa1;-c;ASMO_449;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;BIG5;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;BIG5HKSCS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;BRF;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;BS_4730;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1250;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;CP1251;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1252;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1253;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1254;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1255;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1257;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;CP1258;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;CP932;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;CSA_Z243.4-1985-1;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;CSA_Z243.4-1985-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;DEC-MCS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;DIN_66003;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;DS_2089;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-AT-DE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-AT-DE-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-CA-FR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-DK-NO;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-DK-NO-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-ES;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-ES-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-ES-S;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-FI-SE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-FI-SE-A;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-FR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-IS-FRISS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-IT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-PT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-UK;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;EBCDIC-US;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ES;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ES2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-CN;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-JISX0213;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-JP;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-JP-MS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-KR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;EUC-TW;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GB18030;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GB_1988-80;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GBK;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GOST_19768-74;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GREEK7;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GREEK7-OLD;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;GREEK-CCITT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-GREEK8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-ROMAN8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-ROMAN9;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-THAI8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;HP-TURKISH8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM038;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM1004;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xff;-c;IBM1008;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM1046;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x51;-c;IBM1132;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa0;-c;IBM1133;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xce;-c;IBM1137;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x0f;-c;IBM1364;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1364;UTF-8"
|
||||
"\x00\x0f;-c;IBM1371;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1371;UTF-8"
|
||||
"\x00\x0f;-c;IBM1388;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1388;UTF-8"
|
||||
"\x00\x0f;-c;IBM1390;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1390;UTF-8"
|
||||
"\x00\x0f;-c;IBM1399;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1399;UTF-8"
|
||||
"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM281;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x57;-c;IBM290;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x45;-c;IBM420;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x68;-c;IBM423;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x70;-c;IBM424;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x53;-c;IBM4517;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x53;-c;IBM4899;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa5;-c;IBM4909;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdc;-c;IBM4971;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM803;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x91;-c;IBM851;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x9b;-c;IBM856;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xd5;-c;IBM857;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM864;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x94;-c;IBM868;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x94;-c;IBM869;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM874;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x6a;-c;IBM875;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM880;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM891;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM903;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;IBM904;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM905;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM9066;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x48;-c;IBM918;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x57;-c;IBM930;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM932;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM933;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM935;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM937;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM939;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IBM943;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;INIS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;INIS-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;INIS-CYRILLIC;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xec;-c;ISIRI-3342;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xec;-c;ISO_10367-BOX;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-CN;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-CN-EXT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-JP;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-JP-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-JP-3;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-2022-KR;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_2033;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_5427;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_5427-EXT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO_5428;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa4;-c;ISO_6937;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa0;-c;ISO_6937-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-11;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xa5;-c;ISO-8859-3;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-6;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-7;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;ISO-8859-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;ISO-IR-197;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;ISO-IR-209;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;IT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JIS_C6220-1969-RO;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JIS_C6229-1984-B;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JOHAB;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;JUS_I.B1.002;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;KOI-8;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x88;-c;KOI8-T;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;KSC5636;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;LATIN-GREEK;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;LATIN-GREEK-1;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xf6;-c;MAC-IS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;MSZ_7795.3;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NATS-DANO;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NATS-SEFI;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NC_NC00-10;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NF_Z_62-010;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NF_Z_62-010_1973;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NS_4551-1;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;NS_4551-2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;PT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;PT2;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;RK1048;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;SEN_850200_B;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x98;-c;SEN_850200_C;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;Shift_JISX0213;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x80;-c;SJIS;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x23;-c;T.61-8BIT;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;TIS-620;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;TSCII;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;UHC;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xd8;-c;UNICODE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdc;-c;UTF-16;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xdc\x00;-c;UTF-16BE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdc;-c;UTF-16LE;UTF-8//TRANSLIT//IGNORE"
|
||||
"\xff\xff;-c;UTF-7;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE"
|
||||
)
|
||||
|
||||
# List of option combinations that *should* lead to an error
|
||||
errorarray=(
|
||||
# Converting from/to invalid character sets should cause error
|
||||
"\x00\x00;;INVALID;INVALID"
|
||||
"\x00\x00;;INVALID;UTF-8"
|
||||
"\x00\x00;;UTF-8;INVALID"
|
||||
)
|
||||
|
||||
# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
|
||||
execute_test ()
|
||||
{
|
||||
eval PROG=\"$ICONV\"
|
||||
echo -en "$twobyte" \
|
||||
| timeout -k 4 3 $PROG $c -f $from -t "$to" &>/dev/null
|
||||
ret=$?
|
||||
}
|
||||
|
||||
check_hangtest_result ()
|
||||
{
|
||||
if [ "$ret" -eq "124" ] || [ "$ret" -eq "137" ]; then # timeout/hang
|
||||
result="HANG"
|
||||
else
|
||||
if [ "$ret" -eq "139" ]; then # segfault
|
||||
result="SEGFAULT"
|
||||
else
|
||||
if [ "$ret" -gt "127" ]; then # unexpected error
|
||||
result="UNEXPECTED"
|
||||
else
|
||||
result="OK"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -n "$result: from: \"$from\", to: \"$to\","
|
||||
echo " input \"$twobyte\", flags \"$c\""
|
||||
|
||||
if [ "$result" != "OK" ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for hangcommand in "${hangarray[@]}"; do
|
||||
twobyte="$(echo "$hangcommand" | cut -d";" -f 1)"
|
||||
c="$(echo "$hangcommand" | cut -d";" -f 2)"
|
||||
from="$(echo "$hangcommand" | cut -d";" -f 3)"
|
||||
to="$(echo "$hangcommand" | cut -d";" -f 4)"
|
||||
execute_test
|
||||
check_hangtest_result
|
||||
done
|
||||
|
||||
check_errtest_result ()
|
||||
{
|
||||
if [ "$ret" -eq "1" ]; then # we errored out as expected
|
||||
result="PASS"
|
||||
else
|
||||
result="FAIL"
|
||||
fi
|
||||
echo -n "$result: from: \"$from\", to: \"$to\","
|
||||
echo " input \"$twobyte\", flags \"$c\", return code $ret"
|
||||
|
||||
if [ "$result" != "PASS" ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for errorcommand in "${errorarray[@]}"; do
|
||||
twobyte="$(echo "$errorcommand" | cut -d";" -f 1)"
|
||||
c="$(echo "$errorcommand" | cut -d";" -f 2)"
|
||||
from="$(echo "$errorcommand" | cut -d";" -f 3)"
|
||||
to="$(echo "$errorcommand" | cut -d";" -f 4)"
|
||||
execute_test
|
||||
check_errtest_result
|
||||
done
|
||||
+3
-1
@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules))
|
||||
ifeq (yes,$(build-shared))
|
||||
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
|
||||
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
|
||||
bug-iconv10 bug-iconv11 bug-iconv12
|
||||
bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv14
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += bug-iconv3
|
||||
endif
|
||||
@@ -316,6 +316,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
|
||||
$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so)) \
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256).
|
||||
Copyright (C) 2021 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/>. */
|
||||
|
||||
#include <iconv.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <support/check.h>
|
||||
|
||||
/* Use an escape sequence to return to the initial state. */
|
||||
static void
|
||||
with_escape_sequence (void)
|
||||
{
|
||||
iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
|
||||
TEST_VERIFY_EXIT (c != (iconv_t) -1);
|
||||
|
||||
char in[] = "\e$(O+D\e(B";
|
||||
char *inbuf = in;
|
||||
size_t inleft = strlen (in);
|
||||
char out[3]; /* Space for one output character. */
|
||||
char *outbuf;
|
||||
size_t outleft;
|
||||
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
TEST_COMPARE (inleft, 3);
|
||||
TEST_COMPARE (inbuf - in, strlen (in) - 3);
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xc3);
|
||||
TEST_COMPARE (out[1] & 0xff, 0xa6);
|
||||
|
||||
/* Return to the initial shift state, producing the pending
|
||||
character. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (inleft, 0);
|
||||
TEST_COMPARE (inbuf - in, strlen (in));
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
/* Nothing should be flushed the second time. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (outleft, sizeof (out));
|
||||
TEST_COMPARE (outbuf - out, 0);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
TEST_COMPARE (iconv_close (c), 0);
|
||||
}
|
||||
|
||||
/* Use an explicit flush to return to the initial state. */
|
||||
static void
|
||||
with_flush (void)
|
||||
{
|
||||
iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
|
||||
TEST_VERIFY_EXIT (c != (iconv_t) -1);
|
||||
|
||||
char in[] = "\e$(O+D";
|
||||
char *inbuf = in;
|
||||
size_t inleft = strlen (in);
|
||||
char out[3]; /* Space for one output character. */
|
||||
char *outbuf;
|
||||
size_t outleft;
|
||||
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
TEST_COMPARE (inleft, 0);
|
||||
TEST_COMPARE (inbuf - in, strlen (in));
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xc3);
|
||||
TEST_COMPARE (out[1] & 0xff, 0xa6);
|
||||
|
||||
/* Flush the pending character. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
/* Nothing should be flushed the second time. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (outleft, sizeof (out));
|
||||
TEST_COMPARE (outbuf - out, 0);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
TEST_COMPARE (iconv_close (c), 0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
with_escape_sequence ();
|
||||
with_flush ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+2
-12
@@ -158,24 +158,14 @@ enum
|
||||
\
|
||||
if (__builtin_expect (ch, 0) == SO) \
|
||||
{ \
|
||||
/* Shift OUT, change to DBCS converter. */ \
|
||||
if (curcs == db) \
|
||||
{ \
|
||||
result = __GCONV_ILLEGAL_INPUT; \
|
||||
break; \
|
||||
} \
|
||||
/* Shift OUT, change to DBCS converter (redundant escape okay). */ \
|
||||
curcs = db; \
|
||||
++inptr; \
|
||||
continue; \
|
||||
} \
|
||||
if (__builtin_expect (ch, 0) == SI) \
|
||||
{ \
|
||||
/* Shift IN, change to SBCS converter. */ \
|
||||
if (curcs == sb) \
|
||||
{ \
|
||||
result = __GCONV_ILLEGAL_INPUT; \
|
||||
break; \
|
||||
} \
|
||||
/* Shift IN, change to SBCS converter (redundant escape okay). */ \
|
||||
curcs = sb; \
|
||||
++inptr; \
|
||||
continue; \
|
||||
|
||||
+48
-19
@@ -67,23 +67,34 @@ enum
|
||||
CURRENT_SEL_MASK = 7 << 3
|
||||
};
|
||||
|
||||
/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
|
||||
also contains the last two bytes to be output, shifted by 6 bits, and a
|
||||
one-bit indicator whether they must be preceded by the shift sequence,
|
||||
in bit 22. */
|
||||
/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the
|
||||
state also contains the last two bytes to be output, shifted by 6
|
||||
bits, and a one-bit indicator whether they must be preceded by the
|
||||
shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4
|
||||
conversion, COUNT may also contain a non-zero pending wide
|
||||
character, shifted by six bits. This happens for certain inputs in
|
||||
JISX0213_1_2004_set and JISX0213_2_set if the second wide character
|
||||
in a combining sequence cannot be written because the buffer is
|
||||
full. */
|
||||
|
||||
/* Since this is a stateful encoding we have to provide code which resets
|
||||
the output state to the initial state. This has to be done during the
|
||||
flushing. */
|
||||
#define EMIT_SHIFT_TO_INIT \
|
||||
if ((data->__statep->__count & ~7) != ASCII_set) \
|
||||
if (data->__statep->__count != ASCII_set) \
|
||||
{ \
|
||||
if (FROM_DIRECTION) \
|
||||
{ \
|
||||
/* It's easy, we don't have to emit anything, we just reset the \
|
||||
state for the input. */ \
|
||||
data->__statep->__count &= 7; \
|
||||
data->__statep->__count |= ASCII_set; \
|
||||
if (__glibc_likely (outbuf + 4 <= outend)) \
|
||||
{ \
|
||||
/* Write out the last character. */ \
|
||||
*((uint32_t *) outbuf) = data->__statep->__count >> 6; \
|
||||
outbuf += sizeof (uint32_t); \
|
||||
data->__statep->__count = ASCII_set; \
|
||||
} \
|
||||
else \
|
||||
/* We don't have enough room in the output buffer. */ \
|
||||
status = __GCONV_FULL_OUTPUT; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
@@ -151,7 +162,21 @@ enum
|
||||
#define LOOPFCT FROM_LOOP
|
||||
#define BODY \
|
||||
{ \
|
||||
uint32_t ch = *inptr; \
|
||||
uint32_t ch; \
|
||||
\
|
||||
/* Output any pending character. */ \
|
||||
ch = set >> 6; \
|
||||
if (__glibc_unlikely (ch != 0)) \
|
||||
{ \
|
||||
put32 (outptr, ch); \
|
||||
outptr += 4; \
|
||||
/* Remove the pending character, but preserve state bits. */ \
|
||||
set &= (1 << 6) - 1; \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
/* Otherwise read the next input byte. */ \
|
||||
ch = *inptr; \
|
||||
\
|
||||
/* Recognize escape sequences. */ \
|
||||
if (__glibc_unlikely (ch == ESC)) \
|
||||
@@ -297,21 +322,25 @@ enum
|
||||
uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \
|
||||
uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \
|
||||
\
|
||||
inptr += 2; \
|
||||
\
|
||||
put32 (outptr, u1); \
|
||||
outptr += 4; \
|
||||
\
|
||||
/* See whether we have room for two characters. */ \
|
||||
if (outptr + 8 <= outend) \
|
||||
if (outptr + 4 <= outend) \
|
||||
{ \
|
||||
inptr += 2; \
|
||||
put32 (outptr, u1); \
|
||||
outptr += 4; \
|
||||
put32 (outptr, u2); \
|
||||
outptr += 4; \
|
||||
continue; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
result = __GCONV_FULL_OUTPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
/* Otherwise store only the first character now, and \
|
||||
put the second one into the queue. */ \
|
||||
set |= u2 << 6; \
|
||||
/* Tell the caller why we terminate the loop. */ \
|
||||
result = __GCONV_FULL_OUTPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
inptr += 2; \
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# ifndef _ISOMAC
|
||||
|
||||
extern int __prctl (int __option, ...);
|
||||
libc_hidden_proto (__prctl)
|
||||
|
||||
# endif /* !_ISOMAC */
|
||||
#endif
|
||||
|
||||
@@ -83,6 +83,11 @@ _IO_check_libio (void)
|
||||
= stderr->_vtable_offset =
|
||||
((int) sizeof (struct _IO_FILE)
|
||||
- (int) sizeof (struct _IO_FILE_complete));
|
||||
|
||||
if (_IO_stdin_.vtable != &_IO_old_file_jumps
|
||||
|| _IO_stdout_.vtable != &_IO_old_file_jumps
|
||||
|| _IO_stderr_.vtable != &_IO_old_file_jumps)
|
||||
IO_set_accept_foreign_vtables (&_IO_vtable_check);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ t_fmt_ampm "<U0F46><U0F74><U0F0B><U0F5A><U0F7C><U0F51>/
|
||||
<U0025><U0070>"
|
||||
|
||||
week 7;19971130;1
|
||||
first_weekday 2
|
||||
END LC_TIME
|
||||
|
||||
LC_MESSAGES
|
||||
|
||||
@@ -165,6 +165,7 @@ am_pm "";""
|
||||
date_fmt "%a<U060C> %d-%m-%Y<U060C> %T"
|
||||
|
||||
week 7;19971130;1
|
||||
first_weekday 2
|
||||
END LC_TIME
|
||||
|
||||
LC_MESSAGES
|
||||
|
||||
@@ -139,6 +139,7 @@ t_fmt_ampm "%p %I<U65F6>%M<U5206>%S<U79D2>"
|
||||
|
||||
date_fmt "%Y<U5E74> %m<U6708> %d<U65E5> %A %H:%M:%S %Z"
|
||||
week 7;19971130;1
|
||||
first_weekday 2
|
||||
END LC_TIME
|
||||
|
||||
LC_MESSAGES
|
||||
|
||||
+5
-1
@@ -43,7 +43,8 @@ endif
|
||||
subdir-dirs = programs
|
||||
vpath %.c programs
|
||||
|
||||
tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin
|
||||
tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
|
||||
tst-pututxline-lockfail tst-pututxline-cache
|
||||
|
||||
# Build the -lutil library with these extra functions.
|
||||
extra-libs := libutil
|
||||
@@ -71,3 +72,6 @@ endif
|
||||
$(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force)
|
||||
$(make-target-directory)
|
||||
-$(INSTALL_PROGRAM) -m 4755 -o root $< $@
|
||||
|
||||
$(objpfx)tst-pututxline-lockfail: $(shared-thread-library)
|
||||
$(objpfx)tst-pututxline-cache: $(shared-thread-library)
|
||||
|
||||
+4
-104
@@ -23,115 +23,16 @@
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
|
||||
/* Functions defined here. */
|
||||
static int setutent_unknown (void);
|
||||
static int getutent_r_unknown (struct utmp *buffer, struct utmp **result);
|
||||
static int getutid_r_unknown (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static int getutline_r_unknown (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static struct utmp *pututline_unknown (const struct utmp *data);
|
||||
static void endutent_unknown (void);
|
||||
|
||||
/* Initial Jump table. */
|
||||
const struct utfuncs __libc_utmp_unknown_functions =
|
||||
{
|
||||
setutent_unknown,
|
||||
getutent_r_unknown,
|
||||
getutid_r_unknown,
|
||||
getutline_r_unknown,
|
||||
pututline_unknown,
|
||||
endutent_unknown,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Currently selected backend. */
|
||||
const struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
|
||||
/* We need to protect the opening of the file. */
|
||||
__libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
|
||||
|
||||
|
||||
static int
|
||||
setutent_unknown (void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = (*__libc_utmp_file_functions.setutent) ();
|
||||
if (result)
|
||||
__libc_utmp_jump_table = &__libc_utmp_file_functions;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutent_r_unknown (struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->getutent_r) (buffer, result);
|
||||
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutid_r_unknown (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
|
||||
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutline_r_unknown (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
|
||||
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct utmp *
|
||||
pututline_unknown (const struct utmp *data)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->pututline) (data);
|
||||
|
||||
/* Not available. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
endutent_unknown (void)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__setutent (void)
|
||||
{
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
(*__libc_utmp_jump_table->setutent) ();
|
||||
__libc_setutent ();
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
}
|
||||
@@ -145,7 +46,7 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result);
|
||||
retval = __libc_getutent_r (buffer, result);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
@@ -162,7 +63,7 @@ __pututline (const struct utmp *data)
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
buffer = (*__libc_utmp_jump_table->pututline) (data);
|
||||
buffer = __libc_pututline (data);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
@@ -177,8 +78,7 @@ __endutent (void)
|
||||
{
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
__libc_endutent ();
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
}
|
||||
|
||||
+1
-6
@@ -32,7 +32,6 @@ __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
|
||||
int
|
||||
__getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
#if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0)
|
||||
int retval;
|
||||
|
||||
/* Test whether ID has any of the legal types. */
|
||||
@@ -49,15 +48,11 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
|
||||
retval = __libc_getutid_r (id, buffer, result);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
return retval;
|
||||
#else /* !_HAVE_UT_ID && !_HAVE_UT_TYPE */
|
||||
__set_errno (ENOSYS);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
libc_hidden_def (__getutid_r)
|
||||
weak_alias (__getutid_r, getutid_r)
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
|
||||
retval = __libc_getutline_r (line, buffer, result);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
|
||||
@@ -23,23 +23,11 @@
|
||||
void
|
||||
getutmp (const struct utmpx *utmpx, struct utmp *utmp)
|
||||
{
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
utmp->ut_type = utmpx->ut_type;
|
||||
#endif
|
||||
#if _HAVE_UT_PID - 0
|
||||
utmp->ut_pid = utmpx->ut_pid;
|
||||
#endif
|
||||
memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
|
||||
memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
|
||||
#if _HAVE_UT_ID - 0
|
||||
memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
|
||||
#endif
|
||||
#if _HAVE_UT_HOST - 0
|
||||
memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
|
||||
#endif
|
||||
#if _HAVE_UT_TV - 0
|
||||
utmp->ut_tv = utmpx->ut_tv;
|
||||
#else
|
||||
utmp->ut_time = utmpx->ut_time;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -24,24 +24,11 @@ void
|
||||
getutmpx (const struct utmp *utmp, struct utmpx *utmpx)
|
||||
{
|
||||
memset (utmpx, 0, sizeof (struct utmpx));
|
||||
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
utmpx->ut_type = utmp->ut_type;
|
||||
#endif
|
||||
#if _HAVE_UT_PID - 0
|
||||
utmpx->ut_pid = utmp->ut_pid;
|
||||
#endif
|
||||
memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line));
|
||||
memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user));
|
||||
#if _HAVE_UT_ID - 0
|
||||
memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id));
|
||||
#endif
|
||||
#if _HAVE_UT_HOST - 0
|
||||
memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host));
|
||||
#endif
|
||||
#if _HAVE_UT_TV - 0
|
||||
utmpx->ut_tv = utmp->ut_tv;
|
||||
#else
|
||||
utmpx->ut_time = utmp->ut_time;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -91,12 +91,8 @@ login (const struct utmp *ut)
|
||||
struct utmp copy = *ut;
|
||||
|
||||
/* Fill in those fields we supply. */
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
copy.ut_type = USER_PROCESS;
|
||||
#endif
|
||||
#if _HAVE_UT_PID - 0
|
||||
copy.ut_pid = getpid ();
|
||||
#endif
|
||||
|
||||
/* Seek tty. */
|
||||
found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty));
|
||||
|
||||
@@ -36,9 +36,7 @@ logout (const char *line)
|
||||
setutent ();
|
||||
|
||||
/* Fill in search information. */
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
tmp.ut_type = USER_PROCESS;
|
||||
#endif
|
||||
strncpy (tmp.ut_line, line, sizeof tmp.ut_line);
|
||||
|
||||
/* Read the record. */
|
||||
@@ -46,20 +44,12 @@ logout (const char *line)
|
||||
{
|
||||
/* Clear information about who & from where. */
|
||||
memset (ut->ut_name, '\0', sizeof ut->ut_name);
|
||||
#if _HAVE_UT_HOST - 0
|
||||
memset (ut->ut_host, '\0', sizeof ut->ut_host);
|
||||
#endif
|
||||
#if _HAVE_UT_TV - 0
|
||||
struct timeval tv;
|
||||
__gettimeofday (&tv, NULL);
|
||||
ut->ut_tv.tv_sec = tv.tv_sec;
|
||||
ut->ut_tv.tv_usec = tv.tv_usec;
|
||||
#else
|
||||
ut->ut_time = time (NULL);
|
||||
#endif
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
ut->ut_type = DEAD_PROCESS;
|
||||
#endif
|
||||
|
||||
if (pututline (ut) != NULL)
|
||||
result = 1;
|
||||
|
||||
@@ -30,26 +30,16 @@ logwtmp (const char *line, const char *name, const char *host)
|
||||
|
||||
/* Set information in new entry. */
|
||||
memset (&ut, 0, sizeof (ut));
|
||||
#if _HAVE_UT_PID - 0
|
||||
ut.ut_pid = getpid ();
|
||||
#endif
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS;
|
||||
#endif
|
||||
strncpy (ut.ut_line, line, sizeof ut.ut_line);
|
||||
strncpy (ut.ut_name, name, sizeof ut.ut_name);
|
||||
#if _HAVE_UT_HOST - 0
|
||||
strncpy (ut.ut_host, host, sizeof ut.ut_host);
|
||||
#endif
|
||||
|
||||
#if _HAVE_UT_TV - 0
|
||||
struct timeval tv;
|
||||
__gettimeofday (&tv, NULL);
|
||||
ut.ut_tv.tv_sec = tv.tv_sec;
|
||||
ut.ut_tv.tv_usec = tv.tv_usec;
|
||||
#else
|
||||
ut.ut_time = time (NULL);
|
||||
#endif
|
||||
|
||||
updwtmp (_PATH_WTMP, &ut);
|
||||
}
|
||||
|
||||
@@ -37,47 +37,11 @@ print_entry (struct utmp *up)
|
||||
temp_tv.tv_sec = up->ut_tv.tv_sec;
|
||||
temp_tv.tv_usec = up->ut_tv.tv_usec;
|
||||
|
||||
(printf) (
|
||||
/* The format string. */
|
||||
#if _HAVE_UT_TYPE
|
||||
"[%d] "
|
||||
#endif
|
||||
#if _HAVE_UT_PID
|
||||
"[%05d] "
|
||||
#endif
|
||||
#if _HAVE_UT_ID
|
||||
"[%-4.4s] "
|
||||
#endif
|
||||
"[%-8.8s] [%-12.12s]"
|
||||
#if _HAVE_UT_HOST
|
||||
" [%-16.16s]"
|
||||
#endif
|
||||
" [%-15.15s]"
|
||||
#if _HAVE_UT_TV
|
||||
" [%ld]"
|
||||
#endif
|
||||
"\n"
|
||||
/* The arguments. */
|
||||
#if _HAVE_UT_TYPE
|
||||
, up->ut_type
|
||||
#endif
|
||||
#if _HAVE_UT_PID
|
||||
, up->ut_pid
|
||||
#endif
|
||||
#if _HAVE_UT_ID
|
||||
, up->ut_id
|
||||
#endif
|
||||
, up->ut_user, up->ut_line
|
||||
#if _HAVE_UT_HOST
|
||||
, up->ut_host
|
||||
#endif
|
||||
#if _HAVE_UT_TV
|
||||
, 4 + ctime (&temp_tv.tv_sec)
|
||||
, (long int) temp_tv.tv_usec
|
||||
#else
|
||||
, 4 + ctime (&up->ut_time)
|
||||
#endif
|
||||
);
|
||||
printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-16.16s] [%-15.15s]"
|
||||
" [%ld]\n",
|
||||
up->ut_type, up->ut_pid, up->ut_id, up->ut_user, up->ut_line,
|
||||
up->ut_host, 4 + ctime (&temp_tv.tv_sec),
|
||||
(long int) temp_tv.tv_usec);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/* Test case for cache invalidation after concurrent write (bug 24882).
|
||||
Copyright (C) 2019 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; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This test writes an entry to the utmpx file, reads it (so that it
|
||||
is cached) in process1, and overwrites the same entry in process2
|
||||
with something that does not match the search criteria. At this
|
||||
point, the cache of the first process is stale, and when process1
|
||||
attempts to write a new record which would have gone to the same
|
||||
place (as indicated by the cache), it needs to realize that it has
|
||||
to pick a different slot because the old slot is now used for
|
||||
something else. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/xthread.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <utmp.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
/* Set to the path of the utmp file. */
|
||||
static char *utmp_file;
|
||||
|
||||
/* Used to synchronize the subprocesses. The barrier itself is
|
||||
allocated in shared memory. */
|
||||
static pthread_barrier_t *barrier;
|
||||
|
||||
/* setutxent with error checking. */
|
||||
static void
|
||||
xsetutxent (void)
|
||||
{
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
}
|
||||
|
||||
/* getutxent with error checking. */
|
||||
static struct utmpx *
|
||||
xgetutxent (void)
|
||||
{
|
||||
errno = 0;
|
||||
struct utmpx *result = getutxent ();
|
||||
if (result == NULL)
|
||||
FAIL_EXIT1 ("getutxent: %m");
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
put_entry (const char *id, pid_t pid, const char *user, const char *line)
|
||||
{
|
||||
struct utmpx ut =
|
||||
{
|
||||
.ut_type = LOGIN_PROCESS,
|
||||
.ut_pid = pid,
|
||||
.ut_host = "localhost",
|
||||
};
|
||||
strcpy (ut.ut_id, id);
|
||||
strncpy (ut.ut_user, user, sizeof (ut.ut_user));
|
||||
strncpy (ut.ut_line, line, sizeof (ut.ut_line));
|
||||
TEST_VERIFY (pututxline (&ut) != NULL);
|
||||
}
|
||||
|
||||
/* Use two cooperating subprocesses to avoid issues related to
|
||||
unlock-on-close semantics of POSIX advisory locks. */
|
||||
|
||||
static __attribute__ ((noreturn)) void
|
||||
process1 (void)
|
||||
{
|
||||
TEST_COMPARE (utmpname (utmp_file), 0);
|
||||
|
||||
/* Create an entry. */
|
||||
xsetutxent ();
|
||||
put_entry ("1", 101, "root", "process1");
|
||||
|
||||
/* Retrieve the entry. This will fill the internal cache. */
|
||||
{
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
struct utmpx ut =
|
||||
{
|
||||
.ut_type = LOGIN_PROCESS,
|
||||
.ut_line = "process1",
|
||||
};
|
||||
struct utmpx *result = getutxline (&ut);
|
||||
if (result == NULL)
|
||||
FAIL_EXIT1 ("getutxline (\"process1\"): %m");
|
||||
TEST_COMPARE (result->ut_pid, 101);
|
||||
}
|
||||
|
||||
/* Signal the other process to overwrite the entry. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Wait for the other process to complete the write operation. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Add another entry. Note: This time, there is no setutxent call. */
|
||||
put_entry ("1", 103, "root", "process1");
|
||||
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
process2 (void *closure)
|
||||
{
|
||||
/* Wait for the first process to write its entry. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Truncate the file. The glibc interface does not support
|
||||
re-purposing records, but an external expiration mechanism may
|
||||
trigger this. */
|
||||
TEST_COMPARE (truncate64 (utmp_file, 0), 0);
|
||||
|
||||
/* Write the replacement entry. */
|
||||
TEST_COMPARE (utmpname (utmp_file), 0);
|
||||
xsetutxent ();
|
||||
put_entry ("2", 102, "user", "process2");
|
||||
|
||||
/* Signal the other process that the entry has been replaced. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
xclose (create_temp_file ("tst-tumpx-cache-write-", &utmp_file));
|
||||
{
|
||||
pthread_barrierattr_t attr;
|
||||
xpthread_barrierattr_init (&attr);
|
||||
xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS);
|
||||
barrier = support_shared_allocate (sizeof (*barrier));
|
||||
xpthread_barrier_init (barrier, &attr, 2);
|
||||
}
|
||||
|
||||
/* Run both subprocesses in parallel. */
|
||||
{
|
||||
pid_t pid1 = xfork ();
|
||||
if (pid1 == 0)
|
||||
process1 ();
|
||||
support_isolate_in_subprocess (process2, NULL);
|
||||
int status;
|
||||
xwaitpid (pid1, &status, 0);
|
||||
TEST_COMPARE (status, 0);
|
||||
}
|
||||
|
||||
/* Check that the utmpx database contains the expected records. */
|
||||
{
|
||||
TEST_COMPARE (utmpname (utmp_file), 0);
|
||||
xsetutxent ();
|
||||
|
||||
struct utmpx *ut = xgetutxent ();
|
||||
TEST_COMPARE_STRING (ut->ut_id, "2");
|
||||
TEST_COMPARE (ut->ut_pid, 102);
|
||||
TEST_COMPARE_STRING (ut->ut_user, "user");
|
||||
TEST_COMPARE_STRING (ut->ut_line, "process2");
|
||||
|
||||
ut = xgetutxent ();
|
||||
TEST_COMPARE_STRING (ut->ut_id, "1");
|
||||
TEST_COMPARE (ut->ut_pid, 103);
|
||||
TEST_COMPARE_STRING (ut->ut_user, "root");
|
||||
TEST_COMPARE_STRING (ut->ut_line, "process1");
|
||||
|
||||
if (getutxent () != NULL)
|
||||
FAIL_EXIT1 ("additional utmpx entry");
|
||||
}
|
||||
|
||||
xpthread_barrier_destroy (barrier);
|
||||
support_shared_free (barrier);
|
||||
free (utmp_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,176 @@
|
||||
/* Test the lock upgrade path in tst-pututxline.
|
||||
Copyright (C) 2019 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; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* pututxline upgrades the read lock on the file to a write lock.
|
||||
This test verifies that if the lock upgrade fails, the utmp
|
||||
subsystem remains in a consistent state, so that pututxline can be
|
||||
called again. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/xthread.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
/* Path to the temporary utmp file. */
|
||||
static char *path;
|
||||
|
||||
/* Used to synchronize the subprocesses. The barrier itself is
|
||||
allocated in shared memory. */
|
||||
static pthread_barrier_t *barrier;
|
||||
|
||||
/* Use pututxline to write an entry for PID. */
|
||||
static struct utmpx *
|
||||
write_entry (pid_t pid)
|
||||
{
|
||||
struct utmpx ut =
|
||||
{
|
||||
.ut_type = LOGIN_PROCESS,
|
||||
.ut_id = "1",
|
||||
.ut_user = "root",
|
||||
.ut_pid = pid,
|
||||
.ut_line = "entry",
|
||||
.ut_host = "localhost",
|
||||
};
|
||||
return pututxline (&ut);
|
||||
}
|
||||
|
||||
/* Create the initial entry in a subprocess, so that the utmp
|
||||
subsystem in the original process is not disturbed. */
|
||||
static void
|
||||
subprocess_create_entry (void *closure)
|
||||
{
|
||||
TEST_COMPARE (utmpname (path), 0);
|
||||
TEST_VERIFY (write_entry (101) != NULL);
|
||||
}
|
||||
|
||||
/* Acquire an advisory read lock on PATH. */
|
||||
__attribute__ ((noreturn)) static void
|
||||
subprocess_lock_file (void)
|
||||
{
|
||||
int fd = xopen (path, O_RDONLY, 0);
|
||||
|
||||
struct flock64 fl =
|
||||
{
|
||||
.l_type = F_RDLCK,
|
||||
fl.l_whence = SEEK_SET,
|
||||
};
|
||||
TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0);
|
||||
|
||||
/* Signal to the main process that the lock has been acquired. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Wait for the unlock request from the main process. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Implicitly unlock the file. */
|
||||
xclose (fd);
|
||||
|
||||
/* Overwrite the existing entry. */
|
||||
TEST_COMPARE (utmpname (path), 0);
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
TEST_VERIFY (write_entry (102) != NULL);
|
||||
errno = 0;
|
||||
endutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
xclose (create_temp_file ("tst-pututxline-lockfail-", &path));
|
||||
|
||||
{
|
||||
pthread_barrierattr_t attr;
|
||||
xpthread_barrierattr_init (&attr);
|
||||
xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS);
|
||||
barrier = support_shared_allocate (sizeof (*barrier));
|
||||
xpthread_barrier_init (barrier, &attr, 2);
|
||||
xpthread_barrierattr_destroy (&attr);
|
||||
}
|
||||
|
||||
/* Write the initial entry. */
|
||||
support_isolate_in_subprocess (subprocess_create_entry, NULL);
|
||||
|
||||
pid_t locker_pid = xfork ();
|
||||
if (locker_pid == 0)
|
||||
subprocess_lock_file ();
|
||||
|
||||
/* Wait for the file locking to complete. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Try to add another entry. This attempt will fail, with EINTR or
|
||||
EAGAIN. */
|
||||
TEST_COMPARE (utmpname (path), 0);
|
||||
TEST_VERIFY (write_entry (102) == NULL);
|
||||
if (errno != EINTR)
|
||||
TEST_COMPARE (errno, EAGAIN);
|
||||
|
||||
/* Signal the subprocess to overwrite the entry. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Wait for write and unlock to complete. */
|
||||
{
|
||||
int status;
|
||||
xwaitpid (locker_pid, &status, 0);
|
||||
TEST_COMPARE (status, 0);
|
||||
}
|
||||
|
||||
/* The file is no longer locked, so this operation will succeed. */
|
||||
TEST_VERIFY (write_entry (103) != NULL);
|
||||
errno = 0;
|
||||
endutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
|
||||
/* Check that there is just one entry with the expected contents.
|
||||
If pututxline becomes desynchronized internally, the entry is not
|
||||
overwritten (bug 24902). */
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
struct utmpx *ut = getutxent ();
|
||||
TEST_VERIFY_EXIT (ut != NULL);
|
||||
TEST_COMPARE (ut->ut_type, LOGIN_PROCESS);
|
||||
TEST_COMPARE_STRING (ut->ut_id, "1");
|
||||
TEST_COMPARE_STRING (ut->ut_user, "root");
|
||||
TEST_COMPARE (ut->ut_pid, 103);
|
||||
TEST_COMPARE_STRING (ut->ut_line, "entry");
|
||||
TEST_COMPARE_STRING (ut->ut_host, "localhost");
|
||||
TEST_VERIFY (getutxent () == NULL);
|
||||
errno = 0;
|
||||
endutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
|
||||
xpthread_barrier_destroy (barrier);
|
||||
support_shared_free (barrier);
|
||||
free (path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Basic test coverage for updwtmpx.
|
||||
Copyright (C) 2019 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; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This program runs a series of tests. Each one calls updwtmpx
|
||||
twice, to write two records, optionally with misalignment in the
|
||||
file, and reads back the results. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/descriptors.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <unistd.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Two entries filled with an arbitrary bit pattern. */
|
||||
struct utmpx entries[2];
|
||||
unsigned char pad;
|
||||
{
|
||||
unsigned char *p = (unsigned char *) &entries[0];
|
||||
for (size_t i = 0; i < sizeof (entries); ++i)
|
||||
{
|
||||
p[i] = i;
|
||||
}
|
||||
/* Make sure that the first and second entry and the padding are
|
||||
different. */
|
||||
p[sizeof (struct utmpx)] = p[0] + 1;
|
||||
pad = p[0] + 2;
|
||||
}
|
||||
|
||||
char *path;
|
||||
int fd = create_temp_file ("tst-updwtmpx-", &path);
|
||||
|
||||
/* Used to check that updwtmpx does not leave an open file
|
||||
descriptor around. */
|
||||
struct support_descriptors *descriptors = support_descriptors_list ();
|
||||
|
||||
/* updwtmpx is expected to remove misalignment. Optionally insert
|
||||
one byte of misalignment at the start and in the middle (after
|
||||
the first entry). */
|
||||
for (int misaligned_start = 0; misaligned_start < 2; ++misaligned_start)
|
||||
for (int misaligned_middle = 0; misaligned_middle < 2; ++misaligned_middle)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: misaligned_start=%d misaligned_middle=%d\n",
|
||||
misaligned_start, misaligned_middle);
|
||||
|
||||
xftruncate (fd, 0);
|
||||
TEST_COMPARE (pwrite64 (fd, &pad, misaligned_start, 0),
|
||||
misaligned_start);
|
||||
|
||||
/* Write first entry and check it. */
|
||||
errno = 0;
|
||||
updwtmpx (path, &entries[0]);
|
||||
TEST_COMPARE (errno, 0);
|
||||
support_descriptors_check (descriptors);
|
||||
TEST_COMPARE (xlseek (fd, 0, SEEK_END), sizeof (struct utmpx));
|
||||
struct utmpx buffer;
|
||||
TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0),
|
||||
sizeof (buffer));
|
||||
TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]),
|
||||
&buffer, sizeof (buffer));
|
||||
|
||||
/* Middle mis-alignmet. */
|
||||
TEST_COMPARE (pwrite64 (fd, &pad, misaligned_middle,
|
||||
sizeof (struct utmpx)), misaligned_middle);
|
||||
|
||||
/* Write second entry and check both entries. */
|
||||
errno = 0;
|
||||
updwtmpx (path, &entries[1]);
|
||||
TEST_COMPARE (errno, 0);
|
||||
support_descriptors_check (descriptors);
|
||||
TEST_COMPARE (xlseek (fd, 0, SEEK_END), 2 * sizeof (struct utmpx));
|
||||
TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0),
|
||||
sizeof (buffer));
|
||||
TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]),
|
||||
&buffer, sizeof (buffer));
|
||||
TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), sizeof (buffer)),
|
||||
sizeof (buffer));
|
||||
TEST_COMPARE_BLOB (&entries[1], sizeof (entries[1]),
|
||||
&buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
support_descriptors_free (descriptors);
|
||||
free (path);
|
||||
xclose (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -39,8 +39,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#if defined UTMPX || _HAVE_UT_TYPE
|
||||
|
||||
/* Prototype for our test function. */
|
||||
static int do_test (int argc, char *argv[]);
|
||||
|
||||
@@ -75,11 +73,7 @@ do_prepare (int argc, char *argv[])
|
||||
|
||||
struct utmp entry[] =
|
||||
{
|
||||
#if defined UTMPX || _HAVE_UT_TV
|
||||
#define UT(a) .ut_tv = { .tv_sec = (a)}
|
||||
#else
|
||||
#define UT(a) .ut_time = (a)
|
||||
#endif
|
||||
|
||||
{ .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
|
||||
{ .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
|
||||
@@ -167,11 +161,7 @@ simulate_login (const char *line, const char *user)
|
||||
entry[n].ut_pid = (entry_pid += 27);
|
||||
entry[n].ut_type = USER_PROCESS;
|
||||
strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
|
||||
#if defined UTMPX || _HAVE_UT_TV - 0
|
||||
entry[n].ut_tv.tv_sec = (entry_time += 1000);
|
||||
#else
|
||||
entry[n].ut_time = (entry_time += 1000);
|
||||
#endif
|
||||
setutent ();
|
||||
|
||||
if (pututline (&entry[n]) == NULL)
|
||||
@@ -201,11 +191,7 @@ simulate_logout (const char *line)
|
||||
{
|
||||
entry[n].ut_type = DEAD_PROCESS;
|
||||
strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
|
||||
#if defined UTMPX || _HAVE_UT_TV - 0
|
||||
entry[n].ut_tv.tv_sec = (entry_time += 1000);
|
||||
#else
|
||||
entry[n].ut_time = (entry_time += 1000);
|
||||
#endif
|
||||
setutent ();
|
||||
|
||||
if (pututline (&entry[n]) == NULL)
|
||||
@@ -390,14 +376,3 @@ do_test (int argc, char *argv[])
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* No field 'ut_type' in struct utmp. */
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ __updwtmp (const char *wtmp_file, const struct utmp *utmp)
|
||||
{
|
||||
const char *file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file);
|
||||
|
||||
(*__libc_utmp_file_functions.updwtmp) (file_name, utmp);
|
||||
__libc_updwtmp (file_name, utmp);
|
||||
}
|
||||
libc_hidden_def (__updwtmp)
|
||||
weak_alias (__updwtmp, updwtmp)
|
||||
|
||||
+11
-18
@@ -24,24 +24,17 @@
|
||||
#include <utmp.h>
|
||||
#include <libc-lock.h>
|
||||
|
||||
/* The structure describing the functions in a backend. */
|
||||
struct utfuncs
|
||||
{
|
||||
int (*setutent) (void);
|
||||
int (*getutent_r) (struct utmp *, struct utmp **);
|
||||
int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **);
|
||||
int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **);
|
||||
struct utmp *(*pututline) (const struct utmp *);
|
||||
void (*endutent) (void);
|
||||
int (*updwtmp) (const char *, const struct utmp *);
|
||||
};
|
||||
|
||||
/* The tables from the services. */
|
||||
extern const struct utfuncs __libc_utmp_file_functions attribute_hidden;
|
||||
extern const struct utfuncs __libc_utmp_unknown_functions attribute_hidden;
|
||||
|
||||
/* Currently selected backend. */
|
||||
extern const struct utfuncs *__libc_utmp_jump_table attribute_hidden;
|
||||
/* These functions check for initialization, but not perform any
|
||||
locking. */
|
||||
int __libc_setutent (void) attribute_hidden;
|
||||
int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
|
||||
int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
|
||||
attribute_hidden;
|
||||
int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
|
||||
attribute_hidden;
|
||||
struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
|
||||
void __libc_endutent (void) attribute_hidden;
|
||||
int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
|
||||
|
||||
/* Current file name. */
|
||||
extern const char *__libc_utmp_file_name attribute_hidden;
|
||||
|
||||
+252
-269
@@ -43,6 +43,25 @@ static off64_t file_offset;
|
||||
/* Cache for the last read entry. */
|
||||
static struct utmp last_entry;
|
||||
|
||||
/* Returns true if *ENTRY matches last_entry, based on
|
||||
data->ut_type. */
|
||||
static bool
|
||||
matches_last_entry (const struct utmp *data)
|
||||
{
|
||||
if (file_offset <= 0)
|
||||
/* Nothing has been read. last_entry is stale and cannot match. */
|
||||
return false;
|
||||
|
||||
if (data->ut_type == RUN_LVL
|
||||
|| data->ut_type == BOOT_TIME
|
||||
|| data->ut_type == OLD_TIME
|
||||
|| data->ut_type == NEW_TIME)
|
||||
/* For some entry types, only a type match is required. */
|
||||
return data->ut_type == last_entry.ut_type;
|
||||
else
|
||||
/* For the process-related entries, a full match is needed. */
|
||||
return __utmp_equal (&last_entry, data);
|
||||
}
|
||||
|
||||
/* Locking timeout. */
|
||||
#ifndef TIMEOUT
|
||||
@@ -52,90 +71,70 @@ static struct utmp last_entry;
|
||||
/* Do-nothing handler for locking timeout. */
|
||||
static void timeout_handler (int signum) {};
|
||||
|
||||
/* LOCK_FILE(fd, type) failure_statement
|
||||
attempts to get a lock on the utmp file referenced by FD. If it fails,
|
||||
the failure_statement is executed, otherwise it is skipped.
|
||||
LOCKING_FAILED()
|
||||
jumps into the UNLOCK_FILE macro and ensures cleanup of LOCK_FILE.
|
||||
UNLOCK_FILE(fd)
|
||||
unlocks the utmp file referenced by FD and performs the cleanup of
|
||||
LOCK_FILE.
|
||||
*/
|
||||
#define LOCK_FILE(fd, type) \
|
||||
{ \
|
||||
struct flock fl; \
|
||||
struct sigaction action, old_action; \
|
||||
unsigned int old_timeout; \
|
||||
\
|
||||
/* Cancel any existing alarm. */ \
|
||||
old_timeout = alarm (0); \
|
||||
\
|
||||
/* Establish signal handler. */ \
|
||||
action.sa_handler = timeout_handler; \
|
||||
__sigemptyset (&action.sa_mask); \
|
||||
action.sa_flags = 0; \
|
||||
__sigaction (SIGALRM, &action, &old_action); \
|
||||
\
|
||||
alarm (TIMEOUT); \
|
||||
\
|
||||
/* Try to get the lock. */ \
|
||||
memset (&fl, '\0', sizeof (struct flock)); \
|
||||
fl.l_type = (type); \
|
||||
fl.l_whence = SEEK_SET; \
|
||||
if (__fcntl64_nocancel ((fd), F_SETLKW, &fl) < 0)
|
||||
|
||||
#define LOCKING_FAILED() \
|
||||
goto unalarm_return
|
||||
/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
|
||||
operation failed and recovery needs to be performed.
|
||||
|
||||
#define UNLOCK_FILE(fd) \
|
||||
/* Unlock the file. */ \
|
||||
fl.l_type = F_UNLCK; \
|
||||
__fcntl64_nocancel ((fd), F_SETLKW, &fl); \
|
||||
\
|
||||
unalarm_return: \
|
||||
/* Reset the signal handler and alarm. We must reset the alarm \
|
||||
before resetting the handler so our alarm does not generate a \
|
||||
spurious SIGALRM seen by the user. However, we cannot just set \
|
||||
the user's old alarm before restoring the handler, because then \
|
||||
it's possible our handler could catch the user alarm's SIGARLM \
|
||||
and then the user would never see the signal he expected. */ \
|
||||
alarm (0); \
|
||||
__sigaction (SIGALRM, &old_action, NULL); \
|
||||
if (old_timeout != 0) \
|
||||
alarm (old_timeout); \
|
||||
} while (0)
|
||||
file_unlock (FD) removes the lock (which must have been
|
||||
successfully acquired). */
|
||||
|
||||
|
||||
/* Functions defined here. */
|
||||
static int setutent_file (void);
|
||||
static int getutent_r_file (struct utmp *buffer, struct utmp **result);
|
||||
static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static struct utmp *pututline_file (const struct utmp *data);
|
||||
static void endutent_file (void);
|
||||
static int updwtmp_file (const char *file, const struct utmp *utmp);
|
||||
|
||||
/* Jump table for file functions. */
|
||||
const struct utfuncs __libc_utmp_file_functions =
|
||||
static bool
|
||||
try_file_lock (int fd, int type)
|
||||
{
|
||||
setutent_file,
|
||||
getutent_r_file,
|
||||
getutid_r_file,
|
||||
getutline_r_file,
|
||||
pututline_file,
|
||||
endutent_file,
|
||||
updwtmp_file
|
||||
};
|
||||
/* Cancel any existing alarm. */
|
||||
int old_timeout = alarm (0);
|
||||
|
||||
/* Establish signal handler. */
|
||||
struct sigaction old_action;
|
||||
struct sigaction action;
|
||||
action.sa_handler = timeout_handler;
|
||||
__sigemptyset (&action.sa_mask);
|
||||
action.sa_flags = 0;
|
||||
__sigaction (SIGALRM, &action, &old_action);
|
||||
|
||||
alarm (TIMEOUT);
|
||||
|
||||
/* Try to get the lock. */
|
||||
struct flock64 fl =
|
||||
{
|
||||
.l_type = type,
|
||||
.l_whence = SEEK_SET,
|
||||
};
|
||||
|
||||
bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
|
||||
int saved_errno = errno;
|
||||
|
||||
/* Reset the signal handler and alarm. We must reset the alarm
|
||||
before resetting the handler so our alarm does not generate a
|
||||
spurious SIGALRM seen by the user. However, we cannot just set
|
||||
the user's old alarm before restoring the handler, because then
|
||||
it's possible our handler could catch the user alarm's SIGARLM and
|
||||
then the user would never see the signal he expected. */
|
||||
alarm (0);
|
||||
__sigaction (SIGALRM, &old_action, NULL);
|
||||
if (old_timeout != 0)
|
||||
alarm (old_timeout);
|
||||
|
||||
__set_errno (saved_errno);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
file_unlock (int fd)
|
||||
{
|
||||
struct flock64 fl =
|
||||
{
|
||||
.l_type = F_UNLCK,
|
||||
};
|
||||
__fcntl64_nocancel (fd, F_SETLKW, &fl);
|
||||
}
|
||||
|
||||
#ifndef TRANSFORM_UTMP_FILE_NAME
|
||||
# define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
|
||||
#endif
|
||||
|
||||
static int
|
||||
setutent_file (void)
|
||||
int
|
||||
__libc_setutent (void)
|
||||
{
|
||||
if (file_fd < 0)
|
||||
{
|
||||
@@ -153,56 +152,68 @@ setutent_file (void)
|
||||
__lseek64 (file_fd, 0, SEEK_SET);
|
||||
file_offset = 0;
|
||||
|
||||
/* Make sure the entry won't match. */
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
last_entry.ut_type = -1;
|
||||
#else
|
||||
last_entry.ut_line[0] = '\177';
|
||||
# if _HAVE_UT_ID - 0
|
||||
last_entry.ut_id[0] = '\0';
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutent_r_file (struct utmp *buffer, struct utmp **result)
|
||||
/* Preform initialization if necessary. */
|
||||
static bool
|
||||
maybe_setutent (void)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
return file_fd >= 0 || __libc_setutent ();
|
||||
}
|
||||
|
||||
assert (file_fd >= 0);
|
||||
/* Reads the entry at file_offset, storing it in last_entry and
|
||||
updating file_offset on success. Returns -1 for a read error, 0
|
||||
for EOF, and 1 for a successful read. last_entry and file_offset
|
||||
are only updated on a successful and complete read. */
|
||||
static ssize_t
|
||||
read_last_entry (void)
|
||||
{
|
||||
struct utmp buffer;
|
||||
ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
|
||||
file_offset);
|
||||
if (nbytes < 0)
|
||||
return -1;
|
||||
else if (nbytes != sizeof (buffer))
|
||||
/* Assume EOF. */
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
last_entry = buffer;
|
||||
file_offset += sizeof (buffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_offset == -1l)
|
||||
int
|
||||
__libc_getutent_r (struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
if (!maybe_setutent ())
|
||||
{
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_RDLCK)
|
||||
if (try_file_lock (file_fd, F_RDLCK))
|
||||
return -1;
|
||||
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
file_unlock (file_fd);
|
||||
|
||||
if (nbytes <= 0) /* Read error or EOF. */
|
||||
{
|
||||
nbytes = 0;
|
||||
LOCKING_FAILED ();
|
||||
}
|
||||
|
||||
/* Read the next entry. */
|
||||
nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
|
||||
|
||||
UNLOCK_FILE (file_fd);
|
||||
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
if (nbytes != 0)
|
||||
file_offset = -1l;
|
||||
if (nbytes == 0)
|
||||
/* errno should be unchanged to indicate success. A premature
|
||||
EOF is treated like an EOF (missing complete record at the
|
||||
end). */
|
||||
__set_errno (saved_errno);
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update position pointer. */
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
memcpy (buffer, &last_entry, sizeof (struct utmp));
|
||||
*result = buffer;
|
||||
|
||||
@@ -210,82 +221,55 @@ getutent_r_file (struct utmp *buffer, struct utmp **result)
|
||||
}
|
||||
|
||||
|
||||
/* Search for *ID, updating last_entry and file_offset. Return 0 on
|
||||
success and -1 on failure. Does not perform locking; for that see
|
||||
internal_getut_r below. */
|
||||
static int
|
||||
internal_getut_r (const struct utmp *id, struct utmp *buffer,
|
||||
bool *lock_failed)
|
||||
internal_getut_nolock (const struct utmp *id)
|
||||
{
|
||||
int result = -1;
|
||||
while (1)
|
||||
{
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
if (nbytes < 0)
|
||||
return -1;
|
||||
if (nbytes == 0)
|
||||
{
|
||||
/* End of file reached. */
|
||||
__set_errno (ESRCH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_RDLCK)
|
||||
if (matches_last_entry (id))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search for *ID, updating last_entry and file_offset. Return 0 on
|
||||
success and -1 on failure. If the locking operation failed, write
|
||||
true to *LOCK_FAILED. */
|
||||
static int
|
||||
internal_getut_r (const struct utmp *id, bool *lock_failed)
|
||||
{
|
||||
if (try_file_lock (file_fd, F_RDLCK))
|
||||
{
|
||||
*lock_failed = true;
|
||||
LOCKING_FAILED ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
|
||||
|| id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
|
||||
{
|
||||
/* Search for next entry with type RUN_LVL, BOOT_TIME,
|
||||
OLD_TIME, or NEW_TIME. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
{
|
||||
__set_errno (ESRCH);
|
||||
file_offset = -1l;
|
||||
goto unlock_return;
|
||||
}
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
if (id->ut_type == buffer->ut_type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* _HAVE_UT_TYPE */
|
||||
{
|
||||
/* Search for the next entry with the specified ID and with type
|
||||
INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
{
|
||||
__set_errno (ESRCH);
|
||||
file_offset = -1l;
|
||||
goto unlock_return;
|
||||
}
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
if (__utmp_equal (buffer, id))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (file_fd);
|
||||
|
||||
int result = internal_getut_nolock (id);
|
||||
file_unlock (file_fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* For implementing this function we don't use the getutent_r function
|
||||
because we can avoid the reposition on every new entry this way. */
|
||||
static int
|
||||
getutid_r_file (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
int
|
||||
__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
assert (file_fd >= 0);
|
||||
|
||||
if (file_offset == -1l)
|
||||
if (!maybe_setutent ())
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
@@ -294,7 +278,7 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer,
|
||||
/* We don't have to distinguish whether we can lock the file or
|
||||
whether there is no entry. */
|
||||
bool lock_failed = false;
|
||||
if (internal_getut_r (id, &last_entry, &lock_failed) < 0)
|
||||
if (internal_getut_r (id, &lock_failed) < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
@@ -306,69 +290,65 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* For implementing this function we don't use the getutent_r function
|
||||
because we can avoid the reposition on every new entry this way. */
|
||||
static int
|
||||
getutline_r_file (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
int
|
||||
__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
assert (file_fd >= 0);
|
||||
|
||||
if (file_offset == -1l)
|
||||
if (!maybe_setutent ())
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_RDLCK)
|
||||
if (try_file_lock (file_fd, F_RDLCK))
|
||||
{
|
||||
*result = NULL;
|
||||
LOCKING_FAILED ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
if (nbytes < 0)
|
||||
{
|
||||
__set_errno (ESRCH);
|
||||
file_offset = -1l;
|
||||
file_unlock (file_fd);
|
||||
*result = NULL;
|
||||
goto unlock_return;
|
||||
return -1;
|
||||
}
|
||||
if (nbytes == 0)
|
||||
{
|
||||
/* End of file reached. */
|
||||
file_unlock (file_fd);
|
||||
__set_errno (ESRCH);
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
/* Stop if we found a user or login entry. */
|
||||
if (
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(last_entry.ut_type == USER_PROCESS
|
||||
if ((last_entry.ut_type == USER_PROCESS
|
||||
|| last_entry.ut_type == LOGIN_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
!strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
|
||||
&& (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
|
||||
== 0))
|
||||
break;
|
||||
}
|
||||
|
||||
file_unlock (file_fd);
|
||||
memcpy (buffer, &last_entry, sizeof (struct utmp));
|
||||
*result = buffer;
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (file_fd);
|
||||
|
||||
return ((*result == NULL) ? -1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct utmp *
|
||||
pututline_file (const struct utmp *data)
|
||||
struct utmp *
|
||||
__libc_pututline (const struct utmp *data)
|
||||
{
|
||||
struct utmp buffer;
|
||||
struct utmp *pbuf;
|
||||
int found;
|
||||
if (!maybe_setutent ())
|
||||
return NULL;
|
||||
|
||||
assert (file_fd >= 0);
|
||||
struct utmp *pbuf;
|
||||
|
||||
if (! file_writable)
|
||||
{
|
||||
@@ -380,8 +360,7 @@ pututline_file (const struct utmp *data)
|
||||
if (new_fd == -1)
|
||||
return NULL;
|
||||
|
||||
if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1
|
||||
|| __dup2 (new_fd, file_fd) < 0)
|
||||
if (__dup2 (new_fd, file_fd) < 0)
|
||||
{
|
||||
__close_nocancel_nostatus (new_fd);
|
||||
return NULL;
|
||||
@@ -390,95 +369,96 @@ pututline_file (const struct utmp *data)
|
||||
file_writable = true;
|
||||
}
|
||||
|
||||
/* Find the correct place to insert the data. */
|
||||
if (file_offset > 0
|
||||
&& (
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(last_entry.ut_type == data->ut_type
|
||||
&& (last_entry.ut_type == RUN_LVL
|
||||
|| last_entry.ut_type == BOOT_TIME
|
||||
|| last_entry.ut_type == OLD_TIME
|
||||
|| last_entry.ut_type == NEW_TIME))
|
||||
||
|
||||
#endif
|
||||
__utmp_equal (&last_entry, data)))
|
||||
found = 1;
|
||||
else
|
||||
{
|
||||
bool lock_failed = false;
|
||||
found = internal_getut_r (data, &buffer, &lock_failed);
|
||||
/* Exclude other writers before validating the cache. */
|
||||
if (try_file_lock (file_fd, F_WRLCK))
|
||||
return NULL;
|
||||
|
||||
if (__builtin_expect (lock_failed, false))
|
||||
/* Find the correct place to insert the data. */
|
||||
bool found = false;
|
||||
if (matches_last_entry (data))
|
||||
{
|
||||
/* Read back the entry under the write lock. */
|
||||
file_offset -= sizeof (last_entry);
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
if (nbytes < 0)
|
||||
{
|
||||
__set_errno (EAGAIN);
|
||||
file_unlock (file_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nbytes == 0)
|
||||
/* End of file reached. */
|
||||
found = false;
|
||||
else
|
||||
found = matches_last_entry (data);
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_WRLCK)
|
||||
{
|
||||
pbuf = NULL;
|
||||
LOCKING_FAILED ();
|
||||
}
|
||||
if (!found)
|
||||
/* Search forward for the entry. */
|
||||
found = internal_getut_nolock (data) >= 0;
|
||||
|
||||
if (found < 0)
|
||||
off64_t write_offset;
|
||||
if (!found)
|
||||
{
|
||||
/* We append the next entry. */
|
||||
file_offset = __lseek64 (file_fd, 0, SEEK_END);
|
||||
if (file_offset % sizeof (struct utmp) != 0)
|
||||
{
|
||||
file_offset -= file_offset % sizeof (struct utmp);
|
||||
__ftruncate64 (file_fd, file_offset);
|
||||
write_offset = __lseek64 (file_fd, 0, SEEK_END);
|
||||
|
||||
if (__lseek64 (file_fd, 0, SEEK_END) < 0)
|
||||
{
|
||||
pbuf = NULL;
|
||||
goto unlock_return;
|
||||
}
|
||||
}
|
||||
/* Round down to the next multiple of the entry size. This
|
||||
ensures any partially-written record is overwritten by the
|
||||
new record. */
|
||||
write_offset = (write_offset / sizeof (struct utmp)
|
||||
* sizeof (struct utmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We replace the just read entry. */
|
||||
file_offset -= sizeof (struct utmp);
|
||||
__lseek64 (file_fd, file_offset, SEEK_SET);
|
||||
}
|
||||
/* Overwrite last_entry. */
|
||||
write_offset = file_offset - sizeof (struct utmp);
|
||||
|
||||
/* Write the new data. */
|
||||
if (__write_nocancel (file_fd, data, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
ssize_t nbytes;
|
||||
if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
|
||||
|| (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
|
||||
{
|
||||
/* There is no need to recover the file position because all
|
||||
reads use pread64, and any future write is preceded by
|
||||
another seek. */
|
||||
file_unlock (file_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
/* If we appended a new record this is only partially written.
|
||||
Remove it. */
|
||||
if (found < 0)
|
||||
(void) __ftruncate64 (file_fd, file_offset);
|
||||
pbuf = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
file_offset += sizeof (struct utmp);
|
||||
pbuf = (struct utmp *) data;
|
||||
if (!found)
|
||||
(void) __ftruncate64 (file_fd, write_offset);
|
||||
file_unlock (file_fd);
|
||||
/* Assume that the write failure was due to missing disk
|
||||
space. */
|
||||
__set_errno (ENOSPC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (file_fd);
|
||||
file_unlock (file_fd);
|
||||
file_offset = write_offset + sizeof (struct utmp);
|
||||
pbuf = (struct utmp *) data;
|
||||
|
||||
return pbuf;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
endutent_file (void)
|
||||
void
|
||||
__libc_endutent (void)
|
||||
{
|
||||
assert (file_fd >= 0);
|
||||
|
||||
__close_nocancel_nostatus (file_fd);
|
||||
file_fd = -1;
|
||||
if (file_fd >= 0)
|
||||
{
|
||||
__close_nocancel_nostatus (file_fd);
|
||||
file_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
int
|
||||
__libc_updwtmp (const char *file, const struct utmp *utmp)
|
||||
{
|
||||
int result = -1;
|
||||
off64_t offset;
|
||||
@@ -489,8 +469,11 @@ updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
LOCK_FILE (fd, F_WRLCK)
|
||||
LOCKING_FAILED ();
|
||||
if (try_file_lock (fd, F_WRLCK))
|
||||
{
|
||||
__close_nocancel_nostatus (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remember original size of log file. */
|
||||
offset = __lseek64 (fd, 0, SEEK_END);
|
||||
@@ -516,7 +499,7 @@ updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
result = 0;
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (fd);
|
||||
file_unlock (fd);
|
||||
|
||||
/* Close WTMP file. */
|
||||
__close_nocancel_nostatus (fd);
|
||||
|
||||
+1
-2
@@ -42,8 +42,7 @@ __utmpname (const char *file)
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
/* Close the old file. */
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
__libc_endutent ();
|
||||
|
||||
if (strcmp (file, __libc_utmp_file_name) != 0)
|
||||
{
|
||||
|
||||
+4
-2
@@ -27,7 +27,7 @@ headers := $(dist-headers) obstack.h mcheck.h
|
||||
tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-mcheck tst-mallocfork tst-trim1 \
|
||||
tst-malloc-usable tst-realloc tst-reallocarray tst-posix_memalign \
|
||||
tst-pvalloc tst-memalign tst-mallopt \
|
||||
tst-pvalloc tst-pvalloc-fortify tst-memalign tst-mallopt \
|
||||
tst-malloc-backtrace tst-malloc-thread-exit \
|
||||
tst-malloc-thread-fail tst-malloc-fork-deadlock \
|
||||
tst-mallocfork2 \
|
||||
@@ -54,7 +54,7 @@ tests-internal += \
|
||||
tst-dynarray-at-fail \
|
||||
|
||||
ifneq (no,$(have-tunables))
|
||||
tests += tst-malloc-usable-tunables
|
||||
tests += tst-malloc-usable-tunables tst-mxfast
|
||||
tests-static += tst-malloc-usable-static-tunables
|
||||
endif
|
||||
|
||||
@@ -196,6 +196,8 @@ tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV)
|
||||
tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
|
||||
tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
|
||||
|
||||
tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0
|
||||
|
||||
ifeq ($(experimental-malloc),yes)
|
||||
CPPFLAGS-malloc.c += -DUSE_TCACHE=1
|
||||
else
|
||||
|
||||
@@ -236,6 +236,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
|
||||
TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
|
||||
TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
|
||||
#endif
|
||||
TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t)
|
||||
#else
|
||||
/* Initialization routine. */
|
||||
#include <string.h>
|
||||
@@ -323,6 +324,7 @@ ptmalloc_init (void)
|
||||
TUNABLE_GET (tcache_unsorted_limit, size_t,
|
||||
TUNABLE_CALLBACK (set_tcache_unsorted_limit));
|
||||
# endif
|
||||
TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast));
|
||||
#else
|
||||
const char *s = NULL;
|
||||
if (__glibc_likely (_environ != NULL))
|
||||
|
||||
+22
-9
@@ -1621,7 +1621,7 @@ static INTERNAL_SIZE_T global_max_fast;
|
||||
|
||||
#define set_max_fast(s) \
|
||||
global_max_fast = (((s) == 0) \
|
||||
? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
|
||||
? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
|
||||
|
||||
static inline INTERNAL_SIZE_T
|
||||
get_max_fast (void)
|
||||
@@ -5115,6 +5115,19 @@ do_set_tcache_unsorted_limit (size_t value)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
__always_inline
|
||||
do_set_mxfast (size_t value)
|
||||
{
|
||||
if (value >= 0 && value <= MAX_FAST_SIZE)
|
||||
{
|
||||
LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
|
||||
set_max_fast (value);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__libc_mallopt (int param_number, int value)
|
||||
{
|
||||
@@ -5134,13 +5147,7 @@ __libc_mallopt (int param_number, int value)
|
||||
switch (param_number)
|
||||
{
|
||||
case M_MXFAST:
|
||||
if (value >= 0 && value <= MAX_FAST_SIZE)
|
||||
{
|
||||
LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
|
||||
set_max_fast (value);
|
||||
}
|
||||
else
|
||||
res = 0;
|
||||
do_set_mxfast (value);
|
||||
break;
|
||||
|
||||
case M_TRIM_THRESHOLD:
|
||||
@@ -5406,6 +5413,12 @@ __malloc_info (int options, FILE *fp)
|
||||
|
||||
__libc_lock_lock (ar_ptr->mutex);
|
||||
|
||||
/* Account for top chunk. The top-most available chunk is
|
||||
treated specially and is never in any bin. See "initial_top"
|
||||
comments. */
|
||||
avail = chunksize (ar_ptr->top);
|
||||
nblocks = 1; /* Top always exists. */
|
||||
|
||||
for (size_t i = 0; i < NFASTBINS; ++i)
|
||||
{
|
||||
mchunkptr p = fastbin (ar_ptr, i);
|
||||
@@ -5491,7 +5504,7 @@ __malloc_info (int options, FILE *fp)
|
||||
|
||||
for (size_t i = 0; i < nsizes; ++i)
|
||||
if (sizes[i].count != 0 && i != NFASTBINS)
|
||||
fprintf (fp, " \
|
||||
fprintf (fp, "\
|
||||
<size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
|
||||
sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count);
|
||||
|
||||
|
||||
+1
-2
@@ -71,8 +71,7 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__
|
||||
|
||||
/* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up
|
||||
__size to nearest pagesize. */
|
||||
extern void *pvalloc (size_t __size) __THROW __attribute_malloc__
|
||||
__attribute_alloc_size__ ((1)) __wur;
|
||||
extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur;
|
||||
|
||||
/* Underlying allocation function; successive calls should return
|
||||
contiguous pieces of memory. */
|
||||
|
||||
+28
-11
@@ -62,6 +62,9 @@ static volatile sig_atomic_t sigusr1_received;
|
||||
progress. Checked by liveness_signal_handler. */
|
||||
static volatile sig_atomic_t progress_indicator = 1;
|
||||
|
||||
/* Set to 1 if an error occurs in the signal handler. */
|
||||
static volatile sig_atomic_t error_indicator = 0;
|
||||
|
||||
static void
|
||||
sigusr1_handler (int signo)
|
||||
{
|
||||
@@ -72,7 +75,8 @@ sigusr1_handler (int signo)
|
||||
if (pid == -1)
|
||||
{
|
||||
write_message ("error: fork\n");
|
||||
abort ();
|
||||
error_indicator = 1;
|
||||
return;
|
||||
}
|
||||
if (pid == 0)
|
||||
_exit (0);
|
||||
@@ -81,12 +85,14 @@ sigusr1_handler (int signo)
|
||||
if (ret < 0)
|
||||
{
|
||||
write_message ("error: waitpid\n");
|
||||
abort ();
|
||||
error_indicator = 1;
|
||||
return;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
write_message ("error: unexpected exit status from subprocess\n");
|
||||
abort ();
|
||||
error_indicator = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +128,25 @@ signal_sender (int signo, bool sleep)
|
||||
}
|
||||
}
|
||||
|
||||
/* Children processes. */
|
||||
static pid_t sigusr1_sender_pids[5] = { 0 };
|
||||
static pid_t sigusr2_sender_pid = 0;
|
||||
|
||||
static void
|
||||
kill_children (void)
|
||||
{
|
||||
for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
|
||||
if (sigusr1_sender_pids[i] > 0)
|
||||
kill (sigusr1_sender_pids[i], SIGKILL);
|
||||
if (sigusr2_sender_pid > 0)
|
||||
kill (sigusr2_sender_pid, SIGKILL);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
atexit (kill_children);
|
||||
|
||||
/* shared->barrier is intialized along with sigusr1_sender_pids
|
||||
below. */
|
||||
shared = support_shared_allocate (sizeof (*shared));
|
||||
@@ -148,14 +170,13 @@ do_test (void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid_t sigusr2_sender_pid = xfork ();
|
||||
sigusr2_sender_pid = xfork ();
|
||||
if (sigusr2_sender_pid == 0)
|
||||
signal_sender (SIGUSR2, true);
|
||||
|
||||
/* Send SIGUSR1 signals from several processes. Hopefully, one
|
||||
signal will hit one of the ciritical functions. Use a barrier to
|
||||
avoid sending signals while not running fork/free/malloc. */
|
||||
pid_t sigusr1_sender_pids[5];
|
||||
{
|
||||
pthread_barrierattr_t attr;
|
||||
xpthread_barrierattr_init (&attr);
|
||||
@@ -166,7 +187,7 @@ do_test (void)
|
||||
}
|
||||
for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
|
||||
{
|
||||
sigusr1_sender_pids[i] = fork ();
|
||||
sigusr1_sender_pids[i] = xfork ();
|
||||
if (sigusr1_sender_pids[i] == 0)
|
||||
signal_sender (SIGUSR1, false);
|
||||
}
|
||||
@@ -211,7 +232,7 @@ do_test (void)
|
||||
++malloc_signals;
|
||||
xpthread_barrier_wait (&shared->barrier);
|
||||
|
||||
if (objects[slot] == NULL)
|
||||
if (objects[slot] == NULL || error_indicator != 0)
|
||||
{
|
||||
printf ("error: malloc: %m\n");
|
||||
for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
|
||||
@@ -225,10 +246,6 @@ do_test (void)
|
||||
for (int slot = 0; slot < malloc_objects; ++slot)
|
||||
free (objects[slot]);
|
||||
|
||||
for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
|
||||
kill (sigusr1_sender_pids[i], SIGKILL);
|
||||
kill (sigusr2_sender_pid, SIGKILL);
|
||||
|
||||
printf ("info: signals received during fork: %u\n", fork_signals);
|
||||
printf ("info: signals received during free: %u\n", free_signals);
|
||||
printf ("info: signals received during malloc: %u\n", malloc_signals);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Test that glibc.malloc.mxfast tunable works.
|
||||
Copyright (C) 2019 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This test verifies that setting the glibc.malloc.mxfast tunable to
|
||||
zero results in free'd blocks being returned to the small bins, not
|
||||
the fast bins. */
|
||||
|
||||
#include <malloc.h>
|
||||
#include <support/check.h>
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
struct mallinfo m;
|
||||
char *volatile p1;
|
||||
char *volatile p2;
|
||||
|
||||
/* Arbitrary value; must be in default fastbin range. */
|
||||
p1 = malloc (3);
|
||||
/* Something large so that p1 isn't a "top block" */
|
||||
p2 = malloc (512);
|
||||
free (p1);
|
||||
|
||||
m = mallinfo ();
|
||||
|
||||
/* This will fail if there are any blocks in the fastbins. */
|
||||
TEST_COMPARE (m.smblks, 0);
|
||||
|
||||
/* To keep gcc happy. */
|
||||
free (p2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Test fortify-source allocation size handling in pvalloc (bug 25401).
|
||||
Copyright (C) 2020 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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#undef _FORTIFY_SOURCE
|
||||
#define _FORTIFY_SOURCE 2
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* The test below assumes that pvalloc rounds up the allocation size
|
||||
to at least 8. */
|
||||
TEST_VERIFY (xsysconf (_SC_PAGESIZE) >= 8);
|
||||
|
||||
void *p = pvalloc (5);
|
||||
TEST_VERIFY_EXIT (p != NULL);
|
||||
|
||||
/* This is valid assuming the page size is at least 8 because
|
||||
pvalloc rounds up the allocation size to a multiple of the page
|
||||
size. Due to bug 25041, this used to trigger a compiler
|
||||
warning. */
|
||||
strcpy (p, "abcdefg");
|
||||
|
||||
asm ("" : : "g" (p) : "memory"); /* Optimization barrier. */
|
||||
TEST_VERIFY (malloc_usable_size (p) >= xsysconf (_SC_PAGESIZE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -214,6 +214,18 @@ pre-fill the per-thread cache with. The default, or when set to zero,
|
||||
is no limit.
|
||||
@end deftp
|
||||
|
||||
@deftp Tunable glibc.malloc.mxfast
|
||||
One of the optimizations malloc uses is to maintain a series of ``fast
|
||||
bins'' that hold chunks up to a specific size. The default and
|
||||
maximum size which may be held this way is 80 bytes on 32-bit systems
|
||||
or 160 bytes on 64-bit systems. Applications which value size over
|
||||
speed may choose to reduce the size of requests which are serviced
|
||||
from fast bins with this tunable. Note that the value specified
|
||||
includes malloc's internal overhead, which is normally the size of one
|
||||
pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size
|
||||
passed to @code{malloc} for the largest bin size to enable.
|
||||
@end deftp
|
||||
|
||||
@node Elision Tunables
|
||||
@section Elision Tunables
|
||||
@cindex elision tunables
|
||||
|
||||
+10
-10
@@ -894,9 +894,9 @@ The @code{getlogin} function is declared in @file{unistd.h}, while
|
||||
@c ttyname_r dup @ascuheap @acsmem @acsfd
|
||||
@c strncpy dup ok
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->setutent dup @mtasurace:utent @acsfd
|
||||
@c *libc_utmp_jump_table->getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@c *libc_utmp_jump_table->endutent dup @mtasurace:utent @asulock @aculock
|
||||
@c __libc_setutent dup @mtasurace:utent @acsfd
|
||||
@c __libc_getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@c __libc_endutent dup @mtasurace:utent @asulock @aculock
|
||||
@c libc_lock_unlock dup ok
|
||||
@c strlen dup ok
|
||||
@c memcpy dup ok
|
||||
@@ -1111,7 +1111,7 @@ compatibility only, @file{utmp.h} defines @code{ut_time} as an alias for
|
||||
|
||||
@c setutent @mtasurace:utent @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->setutent @mtasurace:utent @acsfd
|
||||
@c __libc_setutent @mtasurace:utent @acsfd
|
||||
@c setutent_unknown @mtasurace:utent @acsfd
|
||||
@c *libc_utmp_file_functions.setutent = setutent_file @mtasurace:utent @acsfd
|
||||
@c open_not_cancel_2 dup @acsfd
|
||||
@@ -1152,7 +1152,7 @@ A null pointer is returned in case no further entry is available.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c endutent @mtasurace:utent @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->endutent @mtasurace:utent @acsfd
|
||||
@c __libc_endutent @mtasurace:utent @acsfd
|
||||
@c endutent_unknown ok
|
||||
@c endutent_file @mtasurace:utent @acsfd
|
||||
@c close_not_cancel_no_status dup @acsfd
|
||||
@@ -1230,7 +1230,7 @@ over again.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c pututline_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c pututline_file @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@@ -1282,7 +1282,7 @@ user-provided buffer.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c getutent_r_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c getutent_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@@ -1319,7 +1319,7 @@ This function is a GNU extension.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c getutid_r_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c getutid_r_file @mtascusig:ALRM @mtascutimer
|
||||
@@ -1349,7 +1349,7 @@ This function is a GNU extension.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c getutline_r_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c getutline_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@@ -1393,7 +1393,7 @@ be used.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{} @ascuheap{}}@acunsafe{@aculock{} @acsmem{}}}
|
||||
@c utmpname @mtasurace:utent @asulock @ascuheap @aculock @acsmem
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->endutent dup @mtasurace:utent
|
||||
@c __libc_endutent dup @mtasurace:utent
|
||||
@c strcmp dup ok
|
||||
@c free dup @ascuheap @acsmem
|
||||
@c strdup dup @ascuheap @acsmem
|
||||
|
||||
+2
-1
@@ -86,7 +86,8 @@ tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
|
||||
tst-mntent-blank-corrupt tst-mntent-blank-passno bug18240 \
|
||||
tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
|
||||
tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
|
||||
tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt
|
||||
tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
|
||||
tst-syscalls
|
||||
|
||||
# Tests which need libdl.
|
||||
ifeq (yes,$(build-shared))
|
||||
|
||||
@@ -412,14 +412,6 @@
|
||||
# define __glibc_has_attribute(attr) 0
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
/* Do not use a function-like macro, so that __has_include can inhibit
|
||||
macro expansion. */
|
||||
# define __glibc_has_include __has_include
|
||||
#else
|
||||
# define __glibc_has_include(header) 0
|
||||
#endif
|
||||
|
||||
#if (!defined _Noreturn \
|
||||
&& (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \
|
||||
&& !__GNUC_PREREQ (4,7))
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/* Test for syscall interfaces.
|
||||
Copyright (C) 2020 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/>. */
|
||||
|
||||
/* This test verifies that the x32 system call handling zero-extends
|
||||
unsigned 32-bit arguments to the 64-bit argument registers for
|
||||
system calls (bug 25810). The bug is specific to x32, but the test
|
||||
should pass on all architectures. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
/* On x32, this can be passed in a single 64-bit integer register. */
|
||||
struct Array
|
||||
{
|
||||
size_t length;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
static int error_count;
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
struct Array
|
||||
allocate (size_t bytes)
|
||||
{
|
||||
if (!bytes)
|
||||
return __extension__ (struct Array) {0, 0};
|
||||
|
||||
void *p = mmap (0x0, bytes, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
return __extension__ (struct Array) {0, 0};
|
||||
|
||||
return __extension__ (struct Array) {bytes, p};
|
||||
}
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
void
|
||||
deallocate (struct Array b)
|
||||
{
|
||||
/* On x32, the 64-bit integer register containing `b' may be copied
|
||||
to another 64-bit integer register to pass the second argument to
|
||||
munmap. */
|
||||
if (b.length && munmap (b.ptr, b.length))
|
||||
{
|
||||
printf ("munmap error: %m\n");
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
void *
|
||||
do_mmap (void *addr, size_t length)
|
||||
{
|
||||
return mmap (addr, length, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
}
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
void *
|
||||
reallocate (struct Array b)
|
||||
{
|
||||
/* On x32, the 64-bit integer register containing `b' may be copied
|
||||
to another 64-bit integer register to pass the second argument to
|
||||
do_mmap. */
|
||||
if (b.length)
|
||||
return do_mmap (b.ptr, b.length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
void
|
||||
protect (struct Array b)
|
||||
{
|
||||
if (b.length)
|
||||
{
|
||||
/* On x32, the 64-bit integer register containing `b' may be copied
|
||||
to another 64-bit integer register to pass the second argument
|
||||
to mprotect. */
|
||||
if (mprotect (b.ptr, b.length,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
{
|
||||
printf ("mprotect error: %m\n");
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
ssize_t
|
||||
do_read (int fd, void *ptr, struct Array b)
|
||||
{
|
||||
/* On x32, the 64-bit integer register containing `b' may be copied
|
||||
to another 64-bit integer register to pass the second argument to
|
||||
read. */
|
||||
if (b.length)
|
||||
return read (fd, ptr, b.length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noclone, noinline))
|
||||
ssize_t
|
||||
do_write (int fd, void *ptr, struct Array b)
|
||||
{
|
||||
/* On x32, the 64-bit integer register containing `b' may be copied
|
||||
to another 64-bit integer register to pass the second argument to
|
||||
write. */
|
||||
if (b.length)
|
||||
return write (fd, ptr, b.length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct Array array;
|
||||
|
||||
array = allocate (1);
|
||||
protect (array);
|
||||
deallocate (array);
|
||||
void *p = reallocate (array);
|
||||
if (p == MAP_FAILED)
|
||||
{
|
||||
printf ("mmap error: %m\n");
|
||||
error_count++;
|
||||
}
|
||||
array.ptr = p;
|
||||
protect (array);
|
||||
deallocate (array);
|
||||
|
||||
int fd = xopen ("/dev/null", O_RDWR, 0);
|
||||
char buf[2];
|
||||
array.ptr = buf;
|
||||
if (do_read (fd, array.ptr, array) == -1)
|
||||
{
|
||||
printf ("read error: %m\n");
|
||||
error_count++;
|
||||
}
|
||||
if (do_write (fd, array.ptr, array) == -1)
|
||||
{
|
||||
printf ("write error: %m\n");
|
||||
error_count++;
|
||||
}
|
||||
xclose (fd);
|
||||
|
||||
return error_count ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -248,7 +248,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
: NULL);
|
||||
ndomain = (ndomain ? newbuf + ndomaindiff
|
||||
: NULL);
|
||||
buffer = newbuf;
|
||||
*tofreep = buffer = newbuf;
|
||||
}
|
||||
|
||||
nhost = memcpy (buffer + bufused,
|
||||
@@ -319,7 +319,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
|
||||
{
|
||||
buflen *= 2;
|
||||
buffer = xrealloc (buffer, buflen);
|
||||
*tofreep = buffer = xrealloc (buffer, buflen);
|
||||
}
|
||||
else if (status == NSS_STATUS_RETURN
|
||||
|| status == NSS_STATUS_NOTFOUND
|
||||
|
||||
@@ -142,7 +142,7 @@ _nss_compat_setgrent (int stayopen)
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
static enum nss_status __attribute_warn_unused_result__
|
||||
internal_endgrent (ent_t *ent)
|
||||
{
|
||||
if (ent->stream != NULL)
|
||||
@@ -163,6 +163,15 @@ internal_endgrent (ent_t *ent)
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Like internal_endgrent, but preserve errno in all cases. */
|
||||
static void
|
||||
internal_endgrent_noerror (ent_t *ent)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent);
|
||||
__set_errno (saved_errno);
|
||||
}
|
||||
|
||||
enum nss_status
|
||||
_nss_compat_endgrent (void)
|
||||
{
|
||||
@@ -483,7 +492,7 @@ _nss_compat_getgrnam_r (const char *name, struct group *grp,
|
||||
if (result == NSS_STATUS_SUCCESS)
|
||||
result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
|
||||
|
||||
internal_endgrent (&ent);
|
||||
internal_endgrent_noerror (&ent);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -612,7 +621,7 @@ _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
|
||||
if (result == NSS_STATUS_SUCCESS)
|
||||
result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
|
||||
|
||||
internal_endgrent (&ent);
|
||||
internal_endgrent_noerror (&ent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ internal_setgrent (ent_t *ent)
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
static enum nss_status __attribute_warn_unused_result__
|
||||
internal_endgrent (ent_t *ent)
|
||||
{
|
||||
if (ent->stream != NULL)
|
||||
@@ -157,6 +157,15 @@ internal_endgrent (ent_t *ent)
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Like internal_endgrent, but preserve errno in all cases. */
|
||||
static void
|
||||
internal_endgrent_noerror (ent_t *ent)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent);
|
||||
__set_errno (saved_errno);
|
||||
}
|
||||
|
||||
/* Add new group record. */
|
||||
static void
|
||||
add_group (long int *start, long int *size, gid_t **groupsp, long int limit,
|
||||
@@ -501,7 +510,7 @@ _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start,
|
||||
done:
|
||||
scratch_buffer_free (&tmpbuf);
|
||||
|
||||
internal_endgrent (&intern);
|
||||
internal_endgrent_noerror (&intern);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ _nss_compat_setpwent (int stayopen)
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
static enum nss_status __attribute_warn_unused_result__
|
||||
internal_endpwent (ent_t *ent)
|
||||
{
|
||||
if (ent->stream != NULL)
|
||||
@@ -287,6 +287,15 @@ internal_endpwent (ent_t *ent)
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Like internal_endpwent, but preserve errno in all cases. */
|
||||
static void
|
||||
internal_endpwent_noerror (ent_t *ent)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
enum nss_status unused __attribute__ ((unused)) = internal_endpwent (ent);
|
||||
__set_errno (saved_errno);
|
||||
}
|
||||
|
||||
enum nss_status
|
||||
_nss_compat_endpwent (void)
|
||||
{
|
||||
@@ -822,7 +831,7 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
|
||||
if (result == NSS_STATUS_SUCCESS)
|
||||
result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
|
||||
|
||||
internal_endpwent (&ent);
|
||||
internal_endpwent_noerror (&ent);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1061,7 +1070,7 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
|
||||
if (result == NSS_STATUS_SUCCESS)
|
||||
result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
|
||||
|
||||
internal_endpwent (&ent);
|
||||
internal_endpwent_noerror (&ent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ _nss_compat_setspent (int stayopen)
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
static enum nss_status __attribute_warn_unused_result__
|
||||
internal_endspent (ent_t *ent)
|
||||
{
|
||||
if (ent->stream != NULL)
|
||||
@@ -244,6 +244,15 @@ internal_endspent (ent_t *ent)
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Like internal_endspent, but preserve errno in all cases. */
|
||||
static void
|
||||
internal_endspent_noerror (ent_t *ent)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
enum nss_status unused __attribute__ ((unused)) = internal_endspent (ent);
|
||||
__set_errno (saved_errno);
|
||||
}
|
||||
|
||||
enum nss_status
|
||||
_nss_compat_endspent (void)
|
||||
{
|
||||
@@ -261,7 +270,6 @@ _nss_compat_endspent (void)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
|
||||
char *group, char *buffer, size_t buflen,
|
||||
@@ -786,7 +794,7 @@ _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
|
||||
if (result == NSS_STATUS_SUCCESS)
|
||||
result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
|
||||
|
||||
internal_endspent (&ent);
|
||||
internal_endspent_noerror (&ent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+13
-12
@@ -827,31 +827,32 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
|
||||
{
|
||||
size_t home_len = strlen (p->pw_dir);
|
||||
size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
|
||||
char *d;
|
||||
char *d, *newp;
|
||||
bool use_alloca = glob_use_alloca (alloca_used,
|
||||
home_len + rest_len + 1);
|
||||
|
||||
if (__glibc_unlikely (malloc_dirname))
|
||||
free (dirname);
|
||||
malloc_dirname = 0;
|
||||
|
||||
if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
|
||||
dirname = alloca_account (home_len + rest_len + 1,
|
||||
alloca_used);
|
||||
if (use_alloca)
|
||||
newp = alloca_account (home_len + rest_len + 1, alloca_used);
|
||||
else
|
||||
{
|
||||
dirname = malloc (home_len + rest_len + 1);
|
||||
if (dirname == NULL)
|
||||
newp = malloc (home_len + rest_len + 1);
|
||||
if (newp == NULL)
|
||||
{
|
||||
scratch_buffer_free (&pwtmpbuf);
|
||||
retval = GLOB_NOSPACE;
|
||||
goto out;
|
||||
}
|
||||
malloc_dirname = 1;
|
||||
}
|
||||
d = mempcpy (dirname, p->pw_dir, home_len);
|
||||
d = mempcpy (newp, p->pw_dir, home_len);
|
||||
if (end_name != NULL)
|
||||
d = mempcpy (d, end_name, rest_len);
|
||||
*d = '\0';
|
||||
|
||||
if (__glibc_unlikely (malloc_dirname))
|
||||
free (dirname);
|
||||
dirname = newp;
|
||||
malloc_dirname = !use_alloca;
|
||||
|
||||
dirlen = home_len + rest_len;
|
||||
dirname_modified = 1;
|
||||
}
|
||||
|
||||
+2
-1
@@ -70,7 +70,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
|
||||
test-canon test-canon2 tst-strtoll tst-environ \
|
||||
tst-xpg-basename tst-random tst-random2 tst-bsearch \
|
||||
tst-limits tst-rand48 bug-strtod tst-setcontext \
|
||||
tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \
|
||||
tst-setcontext2 test-a64l tst-qsort testmb2 \
|
||||
bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \
|
||||
tst-rand48-2 tst-makecontext tst-strtod5 \
|
||||
tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \
|
||||
@@ -92,6 +92,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
|
||||
tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
|
||||
tst-tls-atexit tst-tls-atexit-nodelete
|
||||
tests-static := tst-secure-getenv
|
||||
tests-container := tst-system
|
||||
|
||||
ifeq ($(build-hardcoded-path-in-tests),yes)
|
||||
tests += tst-empty-env
|
||||
|
||||
+18
-181
@@ -30,167 +30,12 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/test-driver.h>
|
||||
|
||||
static char MAGIC_ARGUMENT[] = "run-actual-test";
|
||||
#define MAGIC_STATUS 19
|
||||
|
||||
/* Return a GID which is not our current GID, but is present in the
|
||||
supplementary group list. */
|
||||
static gid_t
|
||||
choose_gid (void)
|
||||
{
|
||||
int count = getgroups (0, NULL);
|
||||
if (count < 0)
|
||||
{
|
||||
printf ("getgroups: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
gid_t *groups;
|
||||
groups = xcalloc (count, sizeof (*groups));
|
||||
int ret = getgroups (count, groups);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("getgroups: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
gid_t current = getgid ();
|
||||
gid_t not_current = 0;
|
||||
for (int i = 0; i < ret; ++i)
|
||||
{
|
||||
if (groups[i] != current)
|
||||
{
|
||||
not_current = groups[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (groups);
|
||||
return not_current;
|
||||
}
|
||||
|
||||
|
||||
/* Copies the executable into a restricted directory, so that we can
|
||||
safely make it SGID with the TARGET group ID. Then runs the
|
||||
executable. */
|
||||
static int
|
||||
run_executable_sgid (gid_t target)
|
||||
{
|
||||
char *dirname = xasprintf ("%s/secure-getenv.%jd",
|
||||
test_dir, (intmax_t) getpid ());
|
||||
char *execname = xasprintf ("%s/bin", dirname);
|
||||
int infd = -1;
|
||||
int outfd = -1;
|
||||
int ret = -1;
|
||||
if (mkdir (dirname, 0700) < 0)
|
||||
{
|
||||
printf ("mkdir: %m\n");
|
||||
goto err;
|
||||
}
|
||||
infd = open ("/proc/self/exe", O_RDONLY);
|
||||
if (infd < 0)
|
||||
{
|
||||
printf ("open (/proc/self/exe): %m\n");
|
||||
goto err;
|
||||
}
|
||||
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
|
||||
if (outfd < 0)
|
||||
{
|
||||
printf ("open (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
char buf[4096];
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rdcount = read (infd, buf, sizeof (buf));
|
||||
if (rdcount < 0)
|
||||
{
|
||||
printf ("read: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (rdcount == 0)
|
||||
break;
|
||||
char *p = buf;
|
||||
char *end = buf + rdcount;
|
||||
while (p != end)
|
||||
{
|
||||
ssize_t wrcount = write (outfd, buf, end - p);
|
||||
if (wrcount == 0)
|
||||
errno = ENOSPC;
|
||||
if (wrcount <= 0)
|
||||
{
|
||||
printf ("write: %m\n");
|
||||
goto err;
|
||||
}
|
||||
p += wrcount;
|
||||
}
|
||||
}
|
||||
if (fchown (outfd, getuid (), target) < 0)
|
||||
{
|
||||
printf ("fchown (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (fchmod (outfd, 02750) < 0)
|
||||
{
|
||||
printf ("fchmod (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (close (outfd) < 0)
|
||||
{
|
||||
printf ("close (outfd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (close (infd) < 0)
|
||||
{
|
||||
printf ("close (infd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
int kid = fork ();
|
||||
if (kid < 0)
|
||||
{
|
||||
printf ("fork: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (kid == 0)
|
||||
{
|
||||
/* Child process. */
|
||||
char *args[] = { execname, MAGIC_ARGUMENT, NULL };
|
||||
execve (execname, args, environ);
|
||||
printf ("execve (%s): %m\n", execname);
|
||||
_exit (1);
|
||||
}
|
||||
int status;
|
||||
if (waitpid (kid, &status, 0) < 0)
|
||||
{
|
||||
printf ("waitpid: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
|
||||
{
|
||||
printf ("Unexpected exit status %d from child process\n",
|
||||
status);
|
||||
goto err;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
if (outfd >= 0)
|
||||
close (outfd);
|
||||
if (infd >= 0)
|
||||
close (infd);
|
||||
if (execname)
|
||||
{
|
||||
unlink (execname);
|
||||
free (execname);
|
||||
}
|
||||
if (dirname)
|
||||
{
|
||||
rmdir (dirname);
|
||||
free (dirname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -212,15 +57,15 @@ do_test (void)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gid_t target = choose_gid ();
|
||||
if (target == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Could not find a suitable GID for user %jd, skipping test\n",
|
||||
(intmax_t) getuid ());
|
||||
exit (0);
|
||||
}
|
||||
return run_executable_sgid (target);
|
||||
int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
|
||||
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (!WIFEXITED (status))
|
||||
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -229,23 +74,15 @@ alternative_main (int argc, char **argv)
|
||||
if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
{
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
exit (MAGIC_STATUS);
|
||||
}
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
if (getenv ("PATH") == NULL)
|
||||
{
|
||||
printf ("PATH variable not present\n");
|
||||
exit (3);
|
||||
}
|
||||
FAIL_EXIT (3, "PATH variable not present\n");
|
||||
if (secure_getenv ("PATH") != NULL)
|
||||
{
|
||||
printf ("PATH variable not filtered out\n");
|
||||
exit (4);
|
||||
}
|
||||
exit (MAGIC_STATUS);
|
||||
FAIL_EXIT (4, "PATH variable not filtered out\n");
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+120
-4
@@ -17,14 +17,130 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/support.h>
|
||||
|
||||
static char *tmpdir;
|
||||
static long int namemax;
|
||||
|
||||
static void
|
||||
do_prepare (int argc, char *argv[])
|
||||
{
|
||||
tmpdir = support_create_temp_directory ("tst-system-");
|
||||
/* Include the last '/0'. */
|
||||
namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1;
|
||||
TEST_VERIFY_EXIT (namemax != -1);
|
||||
}
|
||||
#define PREPARE do_prepare
|
||||
|
||||
struct args
|
||||
{
|
||||
const char *command;
|
||||
int exit_status;
|
||||
int term_sig;
|
||||
const char *path;
|
||||
};
|
||||
|
||||
static void
|
||||
call_system (void *closure)
|
||||
{
|
||||
struct args *args = (struct args *) closure;
|
||||
int ret;
|
||||
|
||||
if (args->path != NULL)
|
||||
TEST_COMPARE (setenv ("PATH", args->path, 1), 0);
|
||||
ret = system (args->command);
|
||||
if (args->term_sig == 0)
|
||||
{
|
||||
/* Expect regular termination. */
|
||||
TEST_VERIFY (WIFEXITED (ret) != 0);
|
||||
TEST_COMPARE (WEXITSTATUS (ret), args->exit_status);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* status_or_signal < 0. Expect termination by signal. */
|
||||
TEST_VERIFY (WIFSIGNALED (ret) != 0);
|
||||
TEST_COMPARE (WTERMSIG (ret), args->term_sig);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
return system (":");
|
||||
TEST_VERIFY (system (NULL) != 0);
|
||||
|
||||
{
|
||||
char cmd[namemax];
|
||||
memset (cmd, 'a', sizeof(cmd));
|
||||
cmd[sizeof(cmd) - 1] = '\0';
|
||||
|
||||
struct support_capture_subprocess result;
|
||||
result = support_capture_subprocess (call_system,
|
||||
&(struct args) {
|
||||
cmd, 127, 0, tmpdir
|
||||
});
|
||||
support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
|
||||
|
||||
char *returnerr = xasprintf ("%s: execing %s failed: "
|
||||
"No such file or directory",
|
||||
basename(_PATH_BSHELL), cmd);
|
||||
TEST_COMPARE_STRING (result.err.buffer, returnerr);
|
||||
free (returnerr);
|
||||
}
|
||||
|
||||
{
|
||||
char cmd[namemax + 1];
|
||||
memset (cmd, 'a', sizeof(cmd));
|
||||
cmd[sizeof(cmd) - 1] = '\0';
|
||||
|
||||
struct support_capture_subprocess result;
|
||||
result = support_capture_subprocess (call_system,
|
||||
&(struct args) {
|
||||
cmd, 127, 0, tmpdir
|
||||
});
|
||||
support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
|
||||
|
||||
char *returnerr = xasprintf ("%s: execing %s failed: "
|
||||
"File name too long",
|
||||
basename(_PATH_BSHELL), cmd);
|
||||
TEST_COMPARE_STRING (result.err.buffer, returnerr);
|
||||
free (returnerr);
|
||||
}
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result;
|
||||
result = support_capture_subprocess (call_system,
|
||||
&(struct args) {
|
||||
"kill $$", 0, SIGTERM
|
||||
});
|
||||
support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
|
||||
}
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result;
|
||||
result = support_capture_subprocess (call_system,
|
||||
&(struct args) { "echo ...", 0 });
|
||||
support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout);
|
||||
TEST_COMPARE_STRING (result.out.buffer, "...\n");
|
||||
}
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result;
|
||||
result = support_capture_subprocess (call_system,
|
||||
&(struct args) { "exit 1", 1 });
|
||||
support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
|
||||
}
|
||||
|
||||
TEST_COMPARE (system (""), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
#include <support/test-driver.c>
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ __BEGIN_DECLS
|
||||
#include <stddef.h>
|
||||
|
||||
/* Tell the caller that we provide correct C++ prototypes. */
|
||||
#if defined __cplusplus && __GNUC_PREREQ (4, 4)
|
||||
#if defined __cplusplus && (__GNUC_PREREQ (4, 4) \
|
||||
|| __glibc_clang_prereq (3, 5))
|
||||
# define __CORRECT_ISO_CPP_STRING_H_PROTO
|
||||
#endif
|
||||
|
||||
|
||||
+36
-3
@@ -65,8 +65,8 @@ do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res)
|
||||
CHAR *res = CALL (impl, s, c, n);
|
||||
if (res != exp_res)
|
||||
{
|
||||
error (0, 0, "Wrong result in function %s %p %p", impl->name,
|
||||
res, exp_res);
|
||||
error (0, 0, "Wrong result in function %s (%p, %d, %zu) -> %p != %p",
|
||||
impl->name, s, c, n, res, exp_res);
|
||||
ret = 1;
|
||||
return;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
|
||||
}
|
||||
buf[align + len] = 0;
|
||||
|
||||
if (pos < len)
|
||||
if (pos < MIN(n, len))
|
||||
{
|
||||
buf[align + pos] = seek_char;
|
||||
buf[align + len] = -seek_char;
|
||||
@@ -107,6 +107,38 @@ do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
|
||||
do_one_test (impl, (CHAR *) (buf + align), seek_char, n, result);
|
||||
}
|
||||
|
||||
static void
|
||||
do_overflow_tests (void)
|
||||
{
|
||||
size_t i, j, len;
|
||||
const size_t one = 1;
|
||||
uintptr_t buf_addr = (uintptr_t) buf1;
|
||||
|
||||
for (i = 0; i < 750; ++i)
|
||||
{
|
||||
do_test (0, i, 751, SIZE_MAX - i, BIG_CHAR);
|
||||
do_test (0, i, 751, i - buf_addr, BIG_CHAR);
|
||||
do_test (0, i, 751, -buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, SIZE_MAX - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, SIZE_MAX - buf_addr + i, BIG_CHAR);
|
||||
|
||||
len = 0;
|
||||
for (j = 8 * sizeof(size_t) - 1; j ; --j)
|
||||
{
|
||||
len |= one << j;
|
||||
do_test (0, i, 751, len - i, BIG_CHAR);
|
||||
do_test (0, i, 751, len + i, BIG_CHAR);
|
||||
do_test (0, i, 751, len - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, len - buf_addr + i, BIG_CHAR);
|
||||
|
||||
do_test (0, i, 751, ~len - i, BIG_CHAR);
|
||||
do_test (0, i, 751, ~len + i, BIG_CHAR);
|
||||
do_test (0, i, 751, ~len - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, ~len - buf_addr + i, BIG_CHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_tests (void)
|
||||
{
|
||||
@@ -221,6 +253,7 @@ test_main (void)
|
||||
do_test (page_size / 2 - i, i, i, 1, 0x9B);
|
||||
|
||||
do_random_tests ();
|
||||
do_overflow_tests ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,66 @@ do_test (size_t align1, size_t align2, size_t len1, size_t len2,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_overflow_tests (void)
|
||||
{
|
||||
size_t i, j, len;
|
||||
const size_t one = 1;
|
||||
CHAR *s1, *s2;
|
||||
uintptr_t s1_addr;
|
||||
s1 = (CHAR *) buf1;
|
||||
s2 = (CHAR *) buf2;
|
||||
s1_addr = (uintptr_t)s1;
|
||||
for (j = 0; j < 200; ++j)
|
||||
s2[j] = 32 + 23 * j % (BIG_CHAR - 32);
|
||||
s2[200] = 0;
|
||||
for (i = 0; i < 750; ++i) {
|
||||
for (j = 0; j < i; ++j)
|
||||
s1[j] = 32 + 23 * j % (BIG_CHAR - 32);
|
||||
s1[i] = '\0';
|
||||
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, SIZE_MAX - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, i - s1_addr);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, -s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, SIZE_MAX - s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, SIZE_MAX - s1_addr + i);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (j = 8 * sizeof(size_t) - 1; j ; --j)
|
||||
{
|
||||
len |= one << j;
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len + i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len - s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len - s1_addr + i);
|
||||
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len + i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len - s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len - s1_addr + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_tests (void)
|
||||
{
|
||||
@@ -316,6 +376,7 @@ test_main (void)
|
||||
}
|
||||
|
||||
do_random_tests ();
|
||||
do_overflow_tests ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -403,6 +403,18 @@ check2 (void)
|
||||
free (s2);
|
||||
}
|
||||
|
||||
static void
|
||||
check3 (void)
|
||||
{
|
||||
const CHAR *s1 = L ("abc");
|
||||
CHAR *s2 = STRDUP (s1);
|
||||
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
check_result (impl, s1, s2, SIZE_MAX, 0);
|
||||
|
||||
free (s2);
|
||||
}
|
||||
|
||||
int
|
||||
test_main (void)
|
||||
{
|
||||
@@ -412,6 +424,7 @@ test_main (void)
|
||||
|
||||
check1 ();
|
||||
check2 ();
|
||||
check3 ();
|
||||
|
||||
printf ("%23s", "");
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
|
||||
+66
-1
@@ -27,6 +27,7 @@
|
||||
|
||||
#ifndef WIDE
|
||||
# define STRNLEN strnlen
|
||||
# define MEMSET memset
|
||||
# define CHAR char
|
||||
# define BIG_CHAR CHAR_MAX
|
||||
# define MIDDLE_CHAR 127
|
||||
@@ -34,6 +35,7 @@
|
||||
#else
|
||||
# include <wchar.h>
|
||||
# define STRNLEN wcsnlen
|
||||
# define MEMSET wmemset
|
||||
# define CHAR wchar_t
|
||||
# define BIG_CHAR WCHAR_MAX
|
||||
# define MIDDLE_CHAR 1121
|
||||
@@ -87,6 +89,38 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
|
||||
do_one_test (impl, (CHAR *) (buf + align), maxlen, MIN (len, maxlen));
|
||||
}
|
||||
|
||||
static void
|
||||
do_overflow_tests (void)
|
||||
{
|
||||
size_t i, j, len;
|
||||
const size_t one = 1;
|
||||
uintptr_t buf_addr = (uintptr_t) buf1;
|
||||
|
||||
for (i = 0; i < 750; ++i)
|
||||
{
|
||||
do_test (0, i, SIZE_MAX - i, BIG_CHAR);
|
||||
do_test (0, i, i - buf_addr, BIG_CHAR);
|
||||
do_test (0, i, -buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
|
||||
|
||||
len = 0;
|
||||
for (j = 8 * sizeof(size_t) - 1; j ; --j)
|
||||
{
|
||||
len |= one << j;
|
||||
do_test (0, i, len - i, BIG_CHAR);
|
||||
do_test (0, i, len + i, BIG_CHAR);
|
||||
do_test (0, i, len - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, len - buf_addr + i, BIG_CHAR);
|
||||
|
||||
do_test (0, i, ~len - i, BIG_CHAR);
|
||||
do_test (0, i, ~len + i, BIG_CHAR);
|
||||
do_test (0, i, ~len - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, ~len - buf_addr + i, BIG_CHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_tests (void)
|
||||
{
|
||||
@@ -153,7 +187,7 @@ do_page_tests (void)
|
||||
size_t last_offset = (page_size / sizeof (CHAR)) - 1;
|
||||
|
||||
CHAR *s = (CHAR *) buf2;
|
||||
memset (s, 65, (last_offset - 1));
|
||||
MEMSET (s, 65, (last_offset - 1));
|
||||
s[last_offset] = 0;
|
||||
|
||||
/* Place short strings ending at page boundary. */
|
||||
@@ -196,6 +230,35 @@ do_page_tests (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Tests meant to unveil fail on implementations that access bytes
|
||||
beyond the maxium length. */
|
||||
|
||||
static void
|
||||
do_page_2_tests (void)
|
||||
{
|
||||
size_t i, exp_len, offset;
|
||||
size_t last_offset = page_size / sizeof (CHAR);
|
||||
|
||||
CHAR *s = (CHAR *) buf2;
|
||||
MEMSET (s, 65, last_offset);
|
||||
|
||||
/* Place short strings ending at page boundary without the null
|
||||
byte. */
|
||||
offset = last_offset;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
/* Decrease offset to stress several sizes and alignments. */
|
||||
offset--;
|
||||
exp_len = last_offset - offset;
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
/* If an implementation goes beyond EXP_LEN, it will trigger
|
||||
the segfault. */
|
||||
do_one_test (impl, (CHAR *) (s + offset), exp_len, exp_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
test_main (void)
|
||||
{
|
||||
@@ -242,6 +305,8 @@ test_main (void)
|
||||
|
||||
do_random_tests ();
|
||||
do_page_tests ();
|
||||
do_page_2_tests ();
|
||||
do_overflow_tests ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+35
-6
@@ -139,16 +139,45 @@ check1 (void)
|
||||
static void
|
||||
check2 (void)
|
||||
{
|
||||
const char s1[] = ", enable_static, \0, enable_shared, ";
|
||||
const char s1_stack[] = ", enable_static, \0, enable_shared, ";
|
||||
const size_t s1_byte_count = 18;
|
||||
const char *s2_stack = &(s1_stack[s1_byte_count]);
|
||||
const size_t s2_byte_count = 18;
|
||||
char *exp_result;
|
||||
char *s2 = (void *) buf1 + page_size - 18;
|
||||
const size_t page_size_real = getpagesize ();
|
||||
|
||||
strcpy (s2, s1);
|
||||
exp_result = stupid_strstr (s1, s1 + 18);
|
||||
/* Haystack at end of page. The following page is protected. */
|
||||
char *s1_page_end = (void *) buf1 + page_size - s1_byte_count;
|
||||
strcpy (s1_page_end, s1_stack);
|
||||
|
||||
/* Haystack which crosses a page boundary.
|
||||
Note: page_size is at least 2 * getpagesize. See test_init. */
|
||||
char *s1_page_cross = (void *) buf1 + page_size_real - 8;
|
||||
strcpy (s1_page_cross, s1_stack);
|
||||
|
||||
/* Needle at end of page. The following page is protected. */
|
||||
char *s2_page_end = (void *) buf2 + page_size - s2_byte_count;
|
||||
strcpy (s2_page_end, s2_stack);
|
||||
|
||||
/* Needle which crosses a page boundary.
|
||||
Note: page_size is at least 2 * getpagesize. See test_init. */
|
||||
char *s2_page_cross = (void *) buf2 + page_size_real - 8;
|
||||
strcpy (s2_page_cross, s2_stack);
|
||||
|
||||
exp_result = stupid_strstr (s1_stack, s2_stack);
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
check_result (impl, s1, s1 + 18, exp_result);
|
||||
check_result (impl, s2, s1 + 18, exp_result);
|
||||
check_result (impl, s1_stack, s2_stack, exp_result);
|
||||
check_result (impl, s1_stack, s2_page_end, exp_result);
|
||||
check_result (impl, s1_stack, s2_page_cross, exp_result);
|
||||
|
||||
check_result (impl, s1_page_end, s2_stack, exp_result);
|
||||
check_result (impl, s1_page_end, s2_page_end, exp_result);
|
||||
check_result (impl, s1_page_end, s2_page_cross, exp_result);
|
||||
|
||||
check_result (impl, s1_page_cross, s2_stack, exp_result);
|
||||
check_result (impl, s1_page_cross, s2_page_end, exp_result);
|
||||
check_result (impl, s1_page_cross, s2_page_cross, exp_result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,12 @@ struct support_capture_subprocess support_capture_subprocess
|
||||
struct support_capture_subprocess support_capture_subprogram
|
||||
(const char *file, char *const argv[]);
|
||||
|
||||
/* Copy the running program into a setgid binary and run it with CHILD_ID
|
||||
argument. If execution is successful, return the exit status of the child
|
||||
program, otherwise return a non-zero failure exit code. */
|
||||
int support_capture_subprogram_self_sgid
|
||||
(char *child_id);
|
||||
|
||||
/* Deallocate the subprocess data captured by
|
||||
support_capture_subprocess. */
|
||||
void support_capture_subprocess_free (struct support_capture_subprocess *);
|
||||
|
||||
@@ -135,6 +135,37 @@ copy_func (char **argv)
|
||||
|
||||
}
|
||||
|
||||
/* Emulate the 'exit' builtin. The exit value is optional. */
|
||||
static int
|
||||
exit_func (char **argv)
|
||||
{
|
||||
int exit_val = 0;
|
||||
|
||||
if (argv[0] != 0)
|
||||
exit_val = atoi (argv[0]) & 0xff;
|
||||
exit (exit_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Emulate the "/bin/kill" command. Options are ignored. */
|
||||
static int
|
||||
kill_func (char **argv)
|
||||
{
|
||||
int signum = SIGTERM;
|
||||
int i;
|
||||
|
||||
for (i = 0; argv[i]; i++)
|
||||
{
|
||||
pid_t pid;
|
||||
if (strcmp (argv[i], "$$") == 0)
|
||||
pid = getpid ();
|
||||
else
|
||||
pid = atoi (argv[i]);
|
||||
kill (pid, signum);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a list of all the built-in commands we understand. */
|
||||
static struct {
|
||||
const char *name;
|
||||
@@ -143,6 +174,8 @@ static struct {
|
||||
{ "true", true_func },
|
||||
{ "echo", echo_func },
|
||||
{ "cp", copy_func },
|
||||
{ "exit", exit_func },
|
||||
{ "kill", kill_func },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -238,7 +271,7 @@ run_command_array (char **argv)
|
||||
|
||||
fprintf (stderr, "sh: execing %s failed: %s",
|
||||
argv[0], strerror (errno));
|
||||
exit (1);
|
||||
exit (127);
|
||||
}
|
||||
|
||||
waitpid (pid, &status, 0);
|
||||
@@ -251,6 +284,11 @@ run_command_array (char **argv)
|
||||
if (rv)
|
||||
exit (rv);
|
||||
}
|
||||
else if (WIFSIGNALED (status))
|
||||
{
|
||||
int sig = WTERMSIG (status);
|
||||
raise (sig);
|
||||
}
|
||||
else
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ struct support_subprocess support_subprocess
|
||||
struct support_subprocess support_subprogram
|
||||
(const char *file, char *const argv[]);
|
||||
|
||||
/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it
|
||||
to complete. Return program exit status. */
|
||||
int support_subprogram_wait
|
||||
(const char *file, char *const argv[]);
|
||||
|
||||
/* Wait for the subprocess indicated by PROC::PID. Return the status
|
||||
indicate by waitpid call. */
|
||||
int support_process_wait (struct support_subprocess *proc);
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
#include <support/capture_subprocess.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/xsocket.h>
|
||||
#include <support/xspawn.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
|
||||
static void
|
||||
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
|
||||
@@ -36,7 +39,7 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
|
||||
if (ret < 0)
|
||||
{
|
||||
support_record_failure ();
|
||||
printf ("error: reading from subprocess %s: %m", what);
|
||||
printf ("error: reading from subprocess %s: %m\n", what);
|
||||
pfd->events = 0;
|
||||
pfd->revents = 0;
|
||||
}
|
||||
@@ -102,6 +105,129 @@ support_capture_subprogram (const char *file, char *const argv[])
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Copies the executable into a restricted directory, so that we can
|
||||
safely make it SGID with the TARGET group ID. Then runs the
|
||||
executable. */
|
||||
static int
|
||||
copy_and_spawn_sgid (char *child_id, gid_t gid)
|
||||
{
|
||||
char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
|
||||
test_dir, (intmax_t) getpid ());
|
||||
char *execname = xasprintf ("%s/bin", dirname);
|
||||
int infd = -1;
|
||||
int outfd = -1;
|
||||
int ret = 1, status = 1;
|
||||
|
||||
TEST_VERIFY (mkdir (dirname, 0700) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
|
||||
infd = open ("/proc/self/exe", O_RDONLY);
|
||||
if (infd < 0)
|
||||
FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
|
||||
|
||||
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
|
||||
TEST_VERIFY (outfd >= 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
|
||||
char buf[4096];
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rdcount = read (infd, buf, sizeof (buf));
|
||||
TEST_VERIFY (rdcount >= 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
if (rdcount == 0)
|
||||
break;
|
||||
char *p = buf;
|
||||
char *end = buf + rdcount;
|
||||
while (p != end)
|
||||
{
|
||||
ssize_t wrcount = write (outfd, buf, end - p);
|
||||
if (wrcount == 0)
|
||||
errno = ENOSPC;
|
||||
TEST_VERIFY (wrcount > 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
p += wrcount;
|
||||
}
|
||||
}
|
||||
TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
TEST_VERIFY (fchmod (outfd, 02750) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
TEST_VERIFY (close (outfd) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
TEST_VERIFY (close (infd) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
|
||||
/* We have the binary, now spawn the subprocess. Avoid using
|
||||
support_subprogram because we only want the program exit status, not the
|
||||
contents. */
|
||||
ret = 0;
|
||||
|
||||
char * const args[] = {execname, child_id, NULL};
|
||||
|
||||
status = support_subprogram_wait (args[0], args);
|
||||
|
||||
err:
|
||||
if (outfd >= 0)
|
||||
close (outfd);
|
||||
if (infd >= 0)
|
||||
close (infd);
|
||||
if (execname != NULL)
|
||||
{
|
||||
unlink (execname);
|
||||
free (execname);
|
||||
}
|
||||
if (dirname != NULL)
|
||||
{
|
||||
rmdir (dirname);
|
||||
free (dirname);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
FAIL_EXIT1("Failed to make sgid executable for test\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
support_capture_subprogram_self_sgid (char *child_id)
|
||||
{
|
||||
gid_t target = 0;
|
||||
const int count = 64;
|
||||
gid_t groups[count];
|
||||
|
||||
/* Get a GID which is not our current GID, but is present in the
|
||||
supplementary group list. */
|
||||
int ret = getgroups (count, groups);
|
||||
if (ret < 0)
|
||||
FAIL_UNSUPPORTED("Could not get group list for user %jd\n",
|
||||
(intmax_t) getuid ());
|
||||
|
||||
gid_t current = getgid ();
|
||||
for (int i = 0; i < ret; ++i)
|
||||
{
|
||||
if (groups[i] != current)
|
||||
{
|
||||
target = groups[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == 0)
|
||||
FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
|
||||
(intmax_t) getuid ());
|
||||
|
||||
return copy_and_spawn_sgid (child_id, target);
|
||||
}
|
||||
|
||||
void
|
||||
support_capture_subprocess_free (struct support_capture_subprocess *p)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <support/subprocess.h>
|
||||
|
||||
static struct support_subprocess
|
||||
support_suprocess_init (void)
|
||||
support_subprocess_init (void)
|
||||
{
|
||||
struct support_subprocess result;
|
||||
|
||||
@@ -48,7 +48,7 @@ support_suprocess_init (void)
|
||||
struct support_subprocess
|
||||
support_subprocess (void (*callback) (void *), void *closure)
|
||||
{
|
||||
struct support_subprocess result = support_suprocess_init ();
|
||||
struct support_subprocess result = support_subprocess_init ();
|
||||
|
||||
result.pid = xfork ();
|
||||
if (result.pid == 0)
|
||||
@@ -71,7 +71,7 @@ support_subprocess (void (*callback) (void *), void *closure)
|
||||
struct support_subprocess
|
||||
support_subprogram (const char *file, char *const argv[])
|
||||
{
|
||||
struct support_subprocess result = support_suprocess_init ();
|
||||
struct support_subprocess result = support_subprocess_init ();
|
||||
|
||||
posix_spawn_file_actions_t fa;
|
||||
/* posix_spawn_file_actions_init does not fail. */
|
||||
@@ -84,7 +84,7 @@ support_subprogram (const char *file, char *const argv[])
|
||||
xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
|
||||
xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
|
||||
|
||||
result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
|
||||
result.pid = xposix_spawn (file, &fa, NULL, argv, environ);
|
||||
|
||||
xclose (result.stdout_pipe[1]);
|
||||
xclose (result.stderr_pipe[1]);
|
||||
@@ -92,6 +92,19 @@ support_subprogram (const char *file, char *const argv[])
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
support_subprogram_wait (const char *file, char *const argv[])
|
||||
{
|
||||
posix_spawn_file_actions_t fa;
|
||||
|
||||
posix_spawn_file_actions_init (&fa);
|
||||
struct support_subprocess res = support_subprocess_init ();
|
||||
|
||||
res.pid = xposix_spawn (file, &fa, NULL, argv, environ);
|
||||
|
||||
return support_process_wait (&res);
|
||||
}
|
||||
|
||||
int
|
||||
support_process_wait (struct support_subprocess *proc)
|
||||
{
|
||||
|
||||
@@ -391,13 +391,6 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
/* Check for unexpected PLT reloc type. */
|
||||
if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
|
||||
{
|
||||
if (map->l_mach.plt == 0)
|
||||
{
|
||||
/* Prelinking. */
|
||||
*reloc_addr += l_addr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
|
||||
{
|
||||
/* Check the symbol table for variant PCS symbols. */
|
||||
@@ -421,7 +414,10 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
}
|
||||
}
|
||||
|
||||
*reloc_addr = map->l_mach.plt;
|
||||
if (map->l_mach.plt == 0)
|
||||
*reloc_addr += l_addr;
|
||||
else
|
||||
*reloc_addr = map->l_mach.plt;
|
||||
}
|
||||
else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
|
||||
{
|
||||
|
||||
+122
-105
@@ -33,32 +33,24 @@
|
||||
#define A_l x6
|
||||
#define A_lw w6
|
||||
#define A_h x7
|
||||
#define A_hw w7
|
||||
#define B_l x8
|
||||
#define B_lw w8
|
||||
#define B_h x9
|
||||
#define C_l x10
|
||||
#define C_lw w10
|
||||
#define C_h x11
|
||||
#define D_l x12
|
||||
#define D_h x13
|
||||
#define E_l src
|
||||
#define E_h count
|
||||
#define F_l srcend
|
||||
#define F_h dst
|
||||
#define E_l x14
|
||||
#define E_h x15
|
||||
#define F_l x16
|
||||
#define F_h x17
|
||||
#define G_l count
|
||||
#define G_h dst
|
||||
#define H_l src
|
||||
#define H_h srcend
|
||||
#define tmp1 x14
|
||||
|
||||
/* Copies are split into 3 main cases: small copies of up to 16 bytes,
|
||||
medium copies of 17..96 bytes which are fully unrolled. Large copies
|
||||
of more than 96 bytes align the destination and use an unrolled loop
|
||||
processing 64 bytes per iteration.
|
||||
In order to share code with memmove, small and medium copies read all
|
||||
data before writing, allowing any kind of overlap. So small, medium
|
||||
and large backwards memmoves are handled by falling through into memcpy.
|
||||
Overlapping large forward memmoves use a loop that copies backwards.
|
||||
*/
|
||||
|
||||
#ifndef MEMMOVE
|
||||
# define MEMMOVE memmove
|
||||
#endif
|
||||
@@ -66,108 +58,115 @@
|
||||
# define MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
ENTRY_ALIGN (MEMMOVE, 6)
|
||||
/* This implementation supports both memcpy and memmove and shares most code.
|
||||
It uses unaligned accesses and branchless sequences to keep the code small,
|
||||
simple and improve performance.
|
||||
|
||||
Copies are split into 3 main cases: small copies of up to 32 bytes, medium
|
||||
copies of up to 128 bytes, and large copies. The overhead of the overlap
|
||||
check in memmove is negligible since it is only required for large copies.
|
||||
|
||||
Large copies use a software pipelined loop processing 64 bytes per
|
||||
iteration. The destination pointer is 16-byte aligned to minimize
|
||||
unaligned accesses. The loop tail is handled by always copying 64 bytes
|
||||
from the end.
|
||||
*/
|
||||
|
||||
ENTRY_ALIGN (MEMCPY, 6)
|
||||
DELOUSE (0)
|
||||
DELOUSE (1)
|
||||
DELOUSE (2)
|
||||
|
||||
sub tmp1, dstin, src
|
||||
cmp count, 96
|
||||
ccmp tmp1, count, 2, hi
|
||||
b.lo L(move_long)
|
||||
|
||||
/* Common case falls through into memcpy. */
|
||||
END (MEMMOVE)
|
||||
libc_hidden_builtin_def (MEMMOVE)
|
||||
ENTRY (MEMCPY)
|
||||
|
||||
DELOUSE (0)
|
||||
DELOUSE (1)
|
||||
DELOUSE (2)
|
||||
|
||||
prfm PLDL1KEEP, [src]
|
||||
add srcend, src, count
|
||||
add dstend, dstin, count
|
||||
cmp count, 16
|
||||
b.ls L(copy16)
|
||||
cmp count, 96
|
||||
cmp count, 128
|
||||
b.hi L(copy_long)
|
||||
cmp count, 32
|
||||
b.hi L(copy32_128)
|
||||
|
||||
/* Medium copies: 17..96 bytes. */
|
||||
sub tmp1, count, 1
|
||||
/* Small copies: 0..32 bytes. */
|
||||
cmp count, 16
|
||||
b.lo L(copy16)
|
||||
ldp A_l, A_h, [src]
|
||||
tbnz tmp1, 6, L(copy96)
|
||||
ldp D_l, D_h, [srcend, -16]
|
||||
tbz tmp1, 5, 1f
|
||||
ldp B_l, B_h, [src, 16]
|
||||
ldp C_l, C_h, [srcend, -32]
|
||||
stp B_l, B_h, [dstin, 16]
|
||||
stp C_l, C_h, [dstend, -32]
|
||||
1:
|
||||
stp A_l, A_h, [dstin]
|
||||
stp D_l, D_h, [dstend, -16]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Small copies: 0..16 bytes. */
|
||||
/* Copy 8-15 bytes. */
|
||||
L(copy16):
|
||||
cmp count, 8
|
||||
b.lo 1f
|
||||
tbz count, 3, L(copy8)
|
||||
ldr A_l, [src]
|
||||
ldr A_h, [srcend, -8]
|
||||
str A_l, [dstin]
|
||||
str A_h, [dstend, -8]
|
||||
ret
|
||||
.p2align 4
|
||||
1:
|
||||
tbz count, 2, 1f
|
||||
|
||||
.p2align 3
|
||||
/* Copy 4-7 bytes. */
|
||||
L(copy8):
|
||||
tbz count, 2, L(copy4)
|
||||
ldr A_lw, [src]
|
||||
ldr A_hw, [srcend, -4]
|
||||
ldr B_lw, [srcend, -4]
|
||||
str A_lw, [dstin]
|
||||
str A_hw, [dstend, -4]
|
||||
str B_lw, [dstend, -4]
|
||||
ret
|
||||
|
||||
/* Copy 0..3 bytes. Use a branchless sequence that copies the same
|
||||
byte 3 times if count==1, or the 2nd byte twice if count==2. */
|
||||
1:
|
||||
cbz count, 2f
|
||||
/* Copy 0..3 bytes using a branchless sequence. */
|
||||
L(copy4):
|
||||
cbz count, L(copy0)
|
||||
lsr tmp1, count, 1
|
||||
ldrb A_lw, [src]
|
||||
ldrb A_hw, [srcend, -1]
|
||||
ldrb C_lw, [srcend, -1]
|
||||
ldrb B_lw, [src, tmp1]
|
||||
strb A_lw, [dstin]
|
||||
strb B_lw, [dstin, tmp1]
|
||||
strb A_hw, [dstend, -1]
|
||||
2: ret
|
||||
|
||||
.p2align 4
|
||||
/* Copy 64..96 bytes. Copy 64 bytes from the start and
|
||||
32 bytes from the end. */
|
||||
L(copy96):
|
||||
ldp B_l, B_h, [src, 16]
|
||||
ldp C_l, C_h, [src, 32]
|
||||
ldp D_l, D_h, [src, 48]
|
||||
ldp E_l, E_h, [srcend, -32]
|
||||
ldp F_l, F_h, [srcend, -16]
|
||||
stp A_l, A_h, [dstin]
|
||||
stp B_l, B_h, [dstin, 16]
|
||||
stp C_l, C_h, [dstin, 32]
|
||||
stp D_l, D_h, [dstin, 48]
|
||||
stp E_l, E_h, [dstend, -32]
|
||||
stp F_l, F_h, [dstend, -16]
|
||||
strb C_lw, [dstend, -1]
|
||||
L(copy0):
|
||||
ret
|
||||
|
||||
/* Align DST to 16 byte alignment so that we don't cross cache line
|
||||
boundaries on both loads and stores. There are at least 96 bytes
|
||||
to copy, so copy 16 bytes unaligned and then align. The loop
|
||||
copies 64 bytes per iteration and prefetches one iteration ahead. */
|
||||
.p2align 4
|
||||
/* Medium copies: 33..128 bytes. */
|
||||
L(copy32_128):
|
||||
ldp A_l, A_h, [src]
|
||||
ldp B_l, B_h, [src, 16]
|
||||
ldp C_l, C_h, [srcend, -32]
|
||||
ldp D_l, D_h, [srcend, -16]
|
||||
cmp count, 64
|
||||
b.hi L(copy128)
|
||||
stp A_l, A_h, [dstin]
|
||||
stp B_l, B_h, [dstin, 16]
|
||||
stp C_l, C_h, [dstend, -32]
|
||||
stp D_l, D_h, [dstend, -16]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Copy 65..128 bytes. */
|
||||
L(copy128):
|
||||
ldp E_l, E_h, [src, 32]
|
||||
ldp F_l, F_h, [src, 48]
|
||||
cmp count, 96
|
||||
b.ls L(copy96)
|
||||
ldp G_l, G_h, [srcend, -64]
|
||||
ldp H_l, H_h, [srcend, -48]
|
||||
stp G_l, G_h, [dstend, -64]
|
||||
stp H_l, H_h, [dstend, -48]
|
||||
L(copy96):
|
||||
stp A_l, A_h, [dstin]
|
||||
stp B_l, B_h, [dstin, 16]
|
||||
stp E_l, E_h, [dstin, 32]
|
||||
stp F_l, F_h, [dstin, 48]
|
||||
stp C_l, C_h, [dstend, -32]
|
||||
stp D_l, D_h, [dstend, -16]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Copy more than 128 bytes. */
|
||||
L(copy_long):
|
||||
/* Copy 16 bytes and then align dst to 16-byte alignment. */
|
||||
ldp D_l, D_h, [src]
|
||||
and tmp1, dstin, 15
|
||||
bic dst, dstin, 15
|
||||
ldp D_l, D_h, [src]
|
||||
sub src, src, tmp1
|
||||
add count, count, tmp1 /* Count is now 16 too large. */
|
||||
ldp A_l, A_h, [src, 16]
|
||||
@@ -176,7 +175,8 @@ L(copy_long):
|
||||
ldp C_l, C_h, [src, 48]
|
||||
ldp D_l, D_h, [src, 64]!
|
||||
subs count, count, 128 + 16 /* Test and readjust count. */
|
||||
b.ls L(last64)
|
||||
b.ls L(copy64_from_end)
|
||||
|
||||
L(loop64):
|
||||
stp A_l, A_h, [dst, 16]
|
||||
ldp A_l, A_h, [src, 16]
|
||||
@@ -189,10 +189,8 @@ L(loop64):
|
||||
subs count, count, 64
|
||||
b.hi L(loop64)
|
||||
|
||||
/* Write the last full set of 64 bytes. The remainder is at most 64
|
||||
bytes, so it is safe to always copy 64 bytes from the end even if
|
||||
there is just 1 byte left. */
|
||||
L(last64):
|
||||
/* Write the last iteration and copy 64 bytes from the end. */
|
||||
L(copy64_from_end):
|
||||
ldp E_l, E_h, [srcend, -64]
|
||||
stp A_l, A_h, [dst, 16]
|
||||
ldp A_l, A_h, [srcend, -48]
|
||||
@@ -207,20 +205,42 @@ L(last64):
|
||||
stp C_l, C_h, [dstend, -16]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
L(move_long):
|
||||
cbz tmp1, 3f
|
||||
END (MEMCPY)
|
||||
libc_hidden_builtin_def (MEMCPY)
|
||||
|
||||
ENTRY_ALIGN (MEMMOVE, 4)
|
||||
DELOUSE (0)
|
||||
DELOUSE (1)
|
||||
DELOUSE (2)
|
||||
|
||||
add srcend, src, count
|
||||
add dstend, dstin, count
|
||||
cmp count, 128
|
||||
b.hi L(move_long)
|
||||
cmp count, 32
|
||||
b.hi L(copy32_128)
|
||||
|
||||
/* Align dstend to 16 byte alignment so that we don't cross cache line
|
||||
boundaries on both loads and stores. There are at least 96 bytes
|
||||
to copy, so copy 16 bytes unaligned and then align. The loop
|
||||
copies 64 bytes per iteration and prefetches one iteration ahead. */
|
||||
|
||||
and tmp1, dstend, 15
|
||||
/* Small copies: 0..32 bytes. */
|
||||
cmp count, 16
|
||||
b.lo L(copy16)
|
||||
ldp A_l, A_h, [src]
|
||||
ldp D_l, D_h, [srcend, -16]
|
||||
stp A_l, A_h, [dstin]
|
||||
stp D_l, D_h, [dstend, -16]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
L(move_long):
|
||||
/* Only use backward copy if there is an overlap. */
|
||||
sub tmp1, dstin, src
|
||||
cbz tmp1, L(copy0)
|
||||
cmp tmp1, count
|
||||
b.hs L(copy_long)
|
||||
|
||||
/* Large backwards copy for overlapping copies.
|
||||
Copy 16 bytes and then align dst to 16-byte alignment. */
|
||||
ldp D_l, D_h, [srcend, -16]
|
||||
and tmp1, dstend, 15
|
||||
sub srcend, srcend, tmp1
|
||||
sub count, count, tmp1
|
||||
ldp A_l, A_h, [srcend, -16]
|
||||
@@ -230,10 +250,9 @@ L(move_long):
|
||||
ldp D_l, D_h, [srcend, -64]!
|
||||
sub dstend, dstend, tmp1
|
||||
subs count, count, 128
|
||||
b.ls 2f
|
||||
b.ls L(copy64_from_start)
|
||||
|
||||
nop
|
||||
1:
|
||||
L(loop64_backwards):
|
||||
stp A_l, A_h, [dstend, -16]
|
||||
ldp A_l, A_h, [srcend, -16]
|
||||
stp B_l, B_h, [dstend, -32]
|
||||
@@ -243,12 +262,10 @@ L(move_long):
|
||||
stp D_l, D_h, [dstend, -64]!
|
||||
ldp D_l, D_h, [srcend, -64]!
|
||||
subs count, count, 64
|
||||
b.hi 1b
|
||||
b.hi L(loop64_backwards)
|
||||
|
||||
/* Write the last full set of 64 bytes. The remainder is at most 64
|
||||
bytes, so it is safe to always copy 64 bytes from the start even if
|
||||
there is just 1 byte left. */
|
||||
2:
|
||||
/* Write the last iteration and copy 64 bytes from the start. */
|
||||
L(copy64_from_start):
|
||||
ldp G_l, G_h, [src, 48]
|
||||
stp A_l, A_h, [dstend, -16]
|
||||
ldp A_l, A_h, [src, 32]
|
||||
@@ -261,7 +278,7 @@ L(move_long):
|
||||
stp A_l, A_h, [dstin, 32]
|
||||
stp B_l, B_h, [dstin, 16]
|
||||
stp C_l, C_h, [dstin]
|
||||
3: ret
|
||||
ret
|
||||
|
||||
END (MEMCPY)
|
||||
libc_hidden_builtin_def (MEMCPY)
|
||||
END (MEMMOVE)
|
||||
libc_hidden_builtin_def (MEMMOVE)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ifeq ($(subdir),string)
|
||||
sysdep_routines += memcpy_generic memcpy_thunderx memcpy_thunderx2 \
|
||||
sysdep_routines += memcpy_generic memcpy_advsimd memcpy_thunderx memcpy_thunderx2 \
|
||||
memcpy_falkor memmove_falkor \
|
||||
memset_generic memset_falkor memset_emag \
|
||||
memchr_generic memchr_nosimd \
|
||||
|
||||
@@ -42,11 +42,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||||
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
|
||||
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx2)
|
||||
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor)
|
||||
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_simd)
|
||||
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
|
||||
IFUNC_IMPL (i, name, memmove,
|
||||
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
|
||||
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx2)
|
||||
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
|
||||
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_simd)
|
||||
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
|
||||
IFUNC_IMPL (i, name, memset,
|
||||
/* Enable this on non-falkor processors too so that other cores
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
extern __typeof (__redirect_memcpy) __libc_memcpy;
|
||||
|
||||
extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
|
||||
extern __typeof (__redirect_memcpy) __memcpy_simd attribute_hidden;
|
||||
extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden;
|
||||
extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden;
|
||||
extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
|
||||
@@ -36,11 +37,14 @@ extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
|
||||
libc_ifunc (__libc_memcpy,
|
||||
(IS_THUNDERX (midr)
|
||||
? __memcpy_thunderx
|
||||
: (IS_FALKOR (midr) || IS_PHECDA (midr) || IS_ARES (midr)
|
||||
: (IS_FALKOR (midr) || IS_PHECDA (midr)
|
||||
? __memcpy_falkor
|
||||
: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
|
||||
? __memcpy_thunderx2
|
||||
: __memcpy_generic))));
|
||||
: (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)
|
||||
|| IS_NEOVERSE_V1 (midr)
|
||||
? __memcpy_simd
|
||||
: __memcpy_generic)))));
|
||||
|
||||
# undef memcpy
|
||||
strong_alias (__libc_memcpy, memcpy);
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/* Generic optimized memcpy using SIMD.
|
||||
Copyright (C) 2020 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/>. */
|
||||
|
||||
#include <sysdep.h>
|
||||
|
||||
/* Assumptions:
|
||||
*
|
||||
* ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
|
||||
*
|
||||
*/
|
||||
|
||||
#define dstin x0
|
||||
#define src x1
|
||||
#define count x2
|
||||
#define dst x3
|
||||
#define srcend x4
|
||||
#define dstend x5
|
||||
#define A_l x6
|
||||
#define A_lw w6
|
||||
#define A_h x7
|
||||
#define B_l x8
|
||||
#define B_lw w8
|
||||
#define B_h x9
|
||||
#define C_lw w10
|
||||
#define tmp1 x14
|
||||
|
||||
#define A_q q0
|
||||
#define B_q q1
|
||||
#define C_q q2
|
||||
#define D_q q3
|
||||
#define E_q q4
|
||||
#define F_q q5
|
||||
#define G_q q6
|
||||
#define H_q q7
|
||||
|
||||
|
||||
/* This implementation supports both memcpy and memmove and shares most code.
|
||||
It uses unaligned accesses and branchless sequences to keep the code small,
|
||||
simple and improve performance.
|
||||
|
||||
Copies are split into 3 main cases: small copies of up to 32 bytes, medium
|
||||
copies of up to 128 bytes, and large copies. The overhead of the overlap
|
||||
check in memmove is negligible since it is only required for large copies.
|
||||
|
||||
Large copies use a software pipelined loop processing 64 bytes per
|
||||
iteration. The destination pointer is 16-byte aligned to minimize
|
||||
unaligned accesses. The loop tail is handled by always copying 64 bytes
|
||||
from the end. */
|
||||
|
||||
ENTRY (__memcpy_simd)
|
||||
DELOUSE (0)
|
||||
DELOUSE (1)
|
||||
DELOUSE (2)
|
||||
|
||||
add srcend, src, count
|
||||
add dstend, dstin, count
|
||||
cmp count, 128
|
||||
b.hi L(copy_long)
|
||||
cmp count, 32
|
||||
b.hi L(copy32_128)
|
||||
|
||||
/* Small copies: 0..32 bytes. */
|
||||
cmp count, 16
|
||||
b.lo L(copy16)
|
||||
ldr A_q, [src]
|
||||
ldr B_q, [srcend, -16]
|
||||
str A_q, [dstin]
|
||||
str B_q, [dstend, -16]
|
||||
ret
|
||||
|
||||
/* Copy 8-15 bytes. */
|
||||
L(copy16):
|
||||
tbz count, 3, L(copy8)
|
||||
ldr A_l, [src]
|
||||
ldr A_h, [srcend, -8]
|
||||
str A_l, [dstin]
|
||||
str A_h, [dstend, -8]
|
||||
ret
|
||||
|
||||
/* Copy 4-7 bytes. */
|
||||
L(copy8):
|
||||
tbz count, 2, L(copy4)
|
||||
ldr A_lw, [src]
|
||||
ldr B_lw, [srcend, -4]
|
||||
str A_lw, [dstin]
|
||||
str B_lw, [dstend, -4]
|
||||
ret
|
||||
|
||||
/* Copy 0..3 bytes using a branchless sequence. */
|
||||
L(copy4):
|
||||
cbz count, L(copy0)
|
||||
lsr tmp1, count, 1
|
||||
ldrb A_lw, [src]
|
||||
ldrb C_lw, [srcend, -1]
|
||||
ldrb B_lw, [src, tmp1]
|
||||
strb A_lw, [dstin]
|
||||
strb B_lw, [dstin, tmp1]
|
||||
strb C_lw, [dstend, -1]
|
||||
L(copy0):
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Medium copies: 33..128 bytes. */
|
||||
L(copy32_128):
|
||||
ldp A_q, B_q, [src]
|
||||
ldp C_q, D_q, [srcend, -32]
|
||||
cmp count, 64
|
||||
b.hi L(copy128)
|
||||
stp A_q, B_q, [dstin]
|
||||
stp C_q, D_q, [dstend, -32]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Copy 65..128 bytes. */
|
||||
L(copy128):
|
||||
ldp E_q, F_q, [src, 32]
|
||||
cmp count, 96
|
||||
b.ls L(copy96)
|
||||
ldp G_q, H_q, [srcend, -64]
|
||||
stp G_q, H_q, [dstend, -64]
|
||||
L(copy96):
|
||||
stp A_q, B_q, [dstin]
|
||||
stp E_q, F_q, [dstin, 32]
|
||||
stp C_q, D_q, [dstend, -32]
|
||||
ret
|
||||
|
||||
/* Align loop64 below to 16 bytes. */
|
||||
nop
|
||||
|
||||
/* Copy more than 128 bytes. */
|
||||
L(copy_long):
|
||||
/* Copy 16 bytes and then align src to 16-byte alignment. */
|
||||
ldr D_q, [src]
|
||||
and tmp1, src, 15
|
||||
bic src, src, 15
|
||||
sub dst, dstin, tmp1
|
||||
add count, count, tmp1 /* Count is now 16 too large. */
|
||||
ldp A_q, B_q, [src, 16]
|
||||
str D_q, [dstin]
|
||||
ldp C_q, D_q, [src, 48]
|
||||
subs count, count, 128 + 16 /* Test and readjust count. */
|
||||
b.ls L(copy64_from_end)
|
||||
L(loop64):
|
||||
stp A_q, B_q, [dst, 16]
|
||||
ldp A_q, B_q, [src, 80]
|
||||
stp C_q, D_q, [dst, 48]
|
||||
ldp C_q, D_q, [src, 112]
|
||||
add src, src, 64
|
||||
add dst, dst, 64
|
||||
subs count, count, 64
|
||||
b.hi L(loop64)
|
||||
|
||||
/* Write the last iteration and copy 64 bytes from the end. */
|
||||
L(copy64_from_end):
|
||||
ldp E_q, F_q, [srcend, -64]
|
||||
stp A_q, B_q, [dst, 16]
|
||||
ldp A_q, B_q, [srcend, -32]
|
||||
stp C_q, D_q, [dst, 48]
|
||||
stp E_q, F_q, [dstend, -64]
|
||||
stp A_q, B_q, [dstend, -32]
|
||||
ret
|
||||
|
||||
END (__memcpy_simd)
|
||||
libc_hidden_builtin_def (__memcpy_simd)
|
||||
|
||||
|
||||
ENTRY (__memmove_simd)
|
||||
DELOUSE (0)
|
||||
DELOUSE (1)
|
||||
DELOUSE (2)
|
||||
|
||||
add srcend, src, count
|
||||
add dstend, dstin, count
|
||||
cmp count, 128
|
||||
b.hi L(move_long)
|
||||
cmp count, 32
|
||||
b.hi L(copy32_128)
|
||||
|
||||
/* Small moves: 0..32 bytes. */
|
||||
cmp count, 16
|
||||
b.lo L(copy16)
|
||||
ldr A_q, [src]
|
||||
ldr B_q, [srcend, -16]
|
||||
str A_q, [dstin]
|
||||
str B_q, [dstend, -16]
|
||||
ret
|
||||
|
||||
L(move_long):
|
||||
/* Only use backward copy if there is an overlap. */
|
||||
sub tmp1, dstin, src
|
||||
cbz tmp1, L(move0)
|
||||
cmp tmp1, count
|
||||
b.hs L(copy_long)
|
||||
|
||||
/* Large backwards copy for overlapping copies.
|
||||
Copy 16 bytes and then align srcend to 16-byte alignment. */
|
||||
L(copy_long_backwards):
|
||||
ldr D_q, [srcend, -16]
|
||||
and tmp1, srcend, 15
|
||||
bic srcend, srcend, 15
|
||||
sub count, count, tmp1
|
||||
ldp A_q, B_q, [srcend, -32]
|
||||
str D_q, [dstend, -16]
|
||||
ldp C_q, D_q, [srcend, -64]
|
||||
sub dstend, dstend, tmp1
|
||||
subs count, count, 128
|
||||
b.ls L(copy64_from_start)
|
||||
|
||||
L(loop64_backwards):
|
||||
str B_q, [dstend, -16]
|
||||
str A_q, [dstend, -32]
|
||||
ldp A_q, B_q, [srcend, -96]
|
||||
str D_q, [dstend, -48]
|
||||
str C_q, [dstend, -64]!
|
||||
ldp C_q, D_q, [srcend, -128]
|
||||
sub srcend, srcend, 64
|
||||
subs count, count, 64
|
||||
b.hi L(loop64_backwards)
|
||||
|
||||
/* Write the last iteration and copy 64 bytes from the start. */
|
||||
L(copy64_from_start):
|
||||
ldp E_q, F_q, [src, 32]
|
||||
stp A_q, B_q, [dstend, -32]
|
||||
ldp A_q, B_q, [src]
|
||||
stp C_q, D_q, [dstend, -64]
|
||||
stp E_q, F_q, [dstin, 32]
|
||||
stp A_q, B_q, [dstin]
|
||||
L(move0):
|
||||
ret
|
||||
|
||||
END (__memmove_simd)
|
||||
libc_hidden_builtin_def (__memmove_simd)
|
||||
@@ -29,6 +29,7 @@
|
||||
extern __typeof (__redirect_memmove) __libc_memmove;
|
||||
|
||||
extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
|
||||
extern __typeof (__redirect_memmove) __memmove_simd attribute_hidden;
|
||||
extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
|
||||
extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden;
|
||||
extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
|
||||
@@ -40,7 +41,10 @@ libc_ifunc (__libc_memmove,
|
||||
? __memmove_falkor
|
||||
: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
|
||||
? __memmove_thunderx2
|
||||
: __memmove_generic))));
|
||||
: (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)
|
||||
|| IS_NEOVERSE_V1 (midr)
|
||||
? __memmove_simd
|
||||
: __memmove_generic)))));
|
||||
|
||||
# undef memmove
|
||||
strong_alias (__libc_memmove, memmove);
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define ENTRY(name) \
|
||||
.globl C_SYMBOL_NAME(name); \
|
||||
.type C_SYMBOL_NAME(name),%function; \
|
||||
.align 4; \
|
||||
.p2align 6; \
|
||||
C_LABEL(name) \
|
||||
cfi_startproc; \
|
||||
CALL_MCOUNT
|
||||
|
||||
@@ -1084,10 +1084,10 @@ ildouble: 1
|
||||
ldouble: 1
|
||||
|
||||
Function: Real part of "cpow_downward":
|
||||
double: 2
|
||||
float: 4
|
||||
idouble: 2
|
||||
ifloat: 4
|
||||
double: 5
|
||||
float: 8
|
||||
idouble: 5
|
||||
ifloat: 8
|
||||
ildouble: 6
|
||||
ldouble: 6
|
||||
|
||||
@@ -1100,10 +1100,10 @@ ildouble: 2
|
||||
ldouble: 2
|
||||
|
||||
Function: Real part of "cpow_towardzero":
|
||||
double: 2
|
||||
float: 4
|
||||
idouble: 2
|
||||
ifloat: 4
|
||||
double: 5
|
||||
float: 8
|
||||
idouble: 5
|
||||
ifloat: 8
|
||||
ildouble: 6
|
||||
ldouble: 6
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ ENTRY(memcpy)
|
||||
|
||||
mov dst, dstin /* Preserve dstin, we need to return it. */
|
||||
cmp count, #64
|
||||
bge .Lcpy_not_short
|
||||
bhs .Lcpy_not_short
|
||||
/* Deal with small copies quickly by dropping straight into the
|
||||
exit block. */
|
||||
|
||||
@@ -351,10 +351,10 @@ ENTRY(memcpy)
|
||||
|
||||
1:
|
||||
subs tmp2, count, #64 /* Use tmp2 for count. */
|
||||
blt .Ltail63aligned
|
||||
blo .Ltail63aligned
|
||||
|
||||
cmp tmp2, #512
|
||||
bge .Lcpy_body_long
|
||||
bhs .Lcpy_body_long
|
||||
|
||||
.Lcpy_body_medium: /* Count in tmp2. */
|
||||
#ifdef USE_VFP
|
||||
@@ -378,7 +378,7 @@ ENTRY(memcpy)
|
||||
add src, src, #64
|
||||
vstr d1, [dst, #56]
|
||||
add dst, dst, #64
|
||||
bge 1b
|
||||
bhs 1b
|
||||
tst tmp2, #0x3f
|
||||
beq .Ldone
|
||||
|
||||
@@ -412,7 +412,7 @@ ENTRY(memcpy)
|
||||
ldrd A_l, A_h, [src, #64]!
|
||||
strd A_l, A_h, [dst, #64]!
|
||||
subs tmp2, tmp2, #64
|
||||
bge 1b
|
||||
bhs 1b
|
||||
tst tmp2, #0x3f
|
||||
bne 1f
|
||||
ldr tmp2,[sp], #FRAME_SIZE
|
||||
@@ -482,7 +482,7 @@ ENTRY(memcpy)
|
||||
add src, src, #32
|
||||
|
||||
subs tmp2, tmp2, #prefetch_lines * 64 * 2
|
||||
blt 2f
|
||||
blo 2f
|
||||
1:
|
||||
cpy_line_vfp d3, 0
|
||||
cpy_line_vfp d4, 64
|
||||
@@ -494,7 +494,7 @@ ENTRY(memcpy)
|
||||
add dst, dst, #2 * 64
|
||||
add src, src, #2 * 64
|
||||
subs tmp2, tmp2, #prefetch_lines * 64
|
||||
bge 1b
|
||||
bhs 1b
|
||||
|
||||
2:
|
||||
cpy_tail_vfp d3, 0
|
||||
@@ -615,8 +615,8 @@ ENTRY(memcpy)
|
||||
1:
|
||||
pld [src, #(3 * 64)]
|
||||
subs count, count, #64
|
||||
ldrmi tmp2, [sp], #FRAME_SIZE
|
||||
bmi .Ltail63unaligned
|
||||
ldrlo tmp2, [sp], #FRAME_SIZE
|
||||
blo .Ltail63unaligned
|
||||
pld [src, #(4 * 64)]
|
||||
|
||||
#ifdef USE_NEON
|
||||
@@ -633,7 +633,7 @@ ENTRY(memcpy)
|
||||
neon_load_multi d0-d3, src
|
||||
neon_load_multi d4-d7, src
|
||||
subs count, count, #64
|
||||
bmi 2f
|
||||
blo 2f
|
||||
1:
|
||||
pld [src, #(4 * 64)]
|
||||
neon_store_multi d0-d3, dst
|
||||
@@ -641,7 +641,7 @@ ENTRY(memcpy)
|
||||
neon_store_multi d4-d7, dst
|
||||
neon_load_multi d4-d7, src
|
||||
subs count, count, #64
|
||||
bpl 1b
|
||||
bhs 1b
|
||||
2:
|
||||
neon_store_multi d0-d3, dst
|
||||
neon_store_multi d4-d7, dst
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
arm/nofpu
|
||||
@@ -0,0 +1 @@
|
||||
arm/nofpu
|
||||
+10
-14
@@ -68,7 +68,7 @@ ENTRY(memcpy)
|
||||
cfi_remember_state
|
||||
|
||||
subs r2, r2, #4
|
||||
blt 8f
|
||||
blo 8f
|
||||
ands ip, r0, #3
|
||||
PLD( pld [r1, #0] )
|
||||
bne 9f
|
||||
@@ -82,7 +82,7 @@ ENTRY(memcpy)
|
||||
cfi_rel_offset (r6, 4)
|
||||
cfi_rel_offset (r7, 8)
|
||||
cfi_rel_offset (r8, 12)
|
||||
blt 5f
|
||||
blo 5f
|
||||
|
||||
CALGN( ands ip, r1, #31 )
|
||||
CALGN( rsb r3, ip, #32 )
|
||||
@@ -98,9 +98,9 @@ ENTRY(memcpy)
|
||||
#endif
|
||||
|
||||
PLD( pld [r1, #0] )
|
||||
2: PLD( subs r2, r2, #96 )
|
||||
2: PLD( cmp r2, #96 )
|
||||
PLD( pld [r1, #28] )
|
||||
PLD( blt 4f )
|
||||
PLD( blo 4f )
|
||||
PLD( pld [r1, #60] )
|
||||
PLD( pld [r1, #92] )
|
||||
|
||||
@@ -108,9 +108,7 @@ ENTRY(memcpy)
|
||||
4: ldmia r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
|
||||
subs r2, r2, #32
|
||||
stmia r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
|
||||
bge 3b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 4b )
|
||||
bhs 3b
|
||||
|
||||
5: ands ip, r2, #28
|
||||
rsb ip, ip, #32
|
||||
@@ -222,7 +220,7 @@ ENTRY(memcpy)
|
||||
strbge r4, [r0], #1
|
||||
subs r2, r2, ip
|
||||
strb lr, [r0], #1
|
||||
blt 8b
|
||||
blo 8b
|
||||
ands ip, r1, #3
|
||||
beq 1b
|
||||
|
||||
@@ -236,7 +234,7 @@ ENTRY(memcpy)
|
||||
.macro forward_copy_shift pull push
|
||||
|
||||
subs r2, r2, #28
|
||||
blt 14f
|
||||
blo 14f
|
||||
|
||||
CALGN( ands ip, r1, #31 )
|
||||
CALGN( rsb ip, ip, #32 )
|
||||
@@ -253,9 +251,9 @@ ENTRY(memcpy)
|
||||
cfi_rel_offset (r10, 16)
|
||||
|
||||
PLD( pld [r1, #0] )
|
||||
PLD( subs r2, r2, #96 )
|
||||
PLD( cmp r2, #96 )
|
||||
PLD( pld [r1, #28] )
|
||||
PLD( blt 13f )
|
||||
PLD( blo 13f )
|
||||
PLD( pld [r1, #60] )
|
||||
PLD( pld [r1, #92] )
|
||||
|
||||
@@ -280,9 +278,7 @@ ENTRY(memcpy)
|
||||
mov ip, ip, PULL #\pull
|
||||
orr ip, ip, lr, PUSH #\push
|
||||
stmia r0!, {r3, r4, r5, r6, r7, r8, r10, ip}
|
||||
bge 12b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 13b )
|
||||
bhs 12b
|
||||
|
||||
pop {r5 - r8, r10}
|
||||
cfi_adjust_cfa_offset (-20)
|
||||
|
||||
+10
-14
@@ -85,7 +85,7 @@ ENTRY(memmove)
|
||||
add r1, r1, r2
|
||||
add r0, r0, r2
|
||||
subs r2, r2, #4
|
||||
blt 8f
|
||||
blo 8f
|
||||
ands ip, r0, #3
|
||||
PLD( pld [r1, #-4] )
|
||||
bne 9f
|
||||
@@ -99,7 +99,7 @@ ENTRY(memmove)
|
||||
cfi_rel_offset (r6, 4)
|
||||
cfi_rel_offset (r7, 8)
|
||||
cfi_rel_offset (r8, 12)
|
||||
blt 5f
|
||||
blo 5f
|
||||
|
||||
CALGN( ands ip, r1, #31 )
|
||||
CALGN( sbcsne r4, ip, r2 ) @ C is always set here
|
||||
@@ -114,9 +114,9 @@ ENTRY(memmove)
|
||||
#endif
|
||||
|
||||
PLD( pld [r1, #-4] )
|
||||
2: PLD( subs r2, r2, #96 )
|
||||
2: PLD( cmp r2, #96 )
|
||||
PLD( pld [r1, #-32] )
|
||||
PLD( blt 4f )
|
||||
PLD( blo 4f )
|
||||
PLD( pld [r1, #-64] )
|
||||
PLD( pld [r1, #-96] )
|
||||
|
||||
@@ -124,9 +124,7 @@ ENTRY(memmove)
|
||||
4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
|
||||
subs r2, r2, #32
|
||||
stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
|
||||
bge 3b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 4b )
|
||||
bhs 3b
|
||||
|
||||
5: ands ip, r2, #28
|
||||
rsb ip, ip, #32
|
||||
@@ -237,7 +235,7 @@ ENTRY(memmove)
|
||||
strbge r4, [r0, #-1]!
|
||||
subs r2, r2, ip
|
||||
strb lr, [r0, #-1]!
|
||||
blt 8b
|
||||
blo 8b
|
||||
ands ip, r1, #3
|
||||
beq 1b
|
||||
|
||||
@@ -251,7 +249,7 @@ ENTRY(memmove)
|
||||
.macro backward_copy_shift push pull
|
||||
|
||||
subs r2, r2, #28
|
||||
blt 14f
|
||||
blo 14f
|
||||
|
||||
CALGN( ands ip, r1, #31 )
|
||||
CALGN( rsb ip, ip, #32 )
|
||||
@@ -268,9 +266,9 @@ ENTRY(memmove)
|
||||
cfi_rel_offset (r10, 16)
|
||||
|
||||
PLD( pld [r1, #-4] )
|
||||
PLD( subs r2, r2, #96 )
|
||||
PLD( cmp r2, #96 )
|
||||
PLD( pld [r1, #-32] )
|
||||
PLD( blt 13f )
|
||||
PLD( blo 13f )
|
||||
PLD( pld [r1, #-64] )
|
||||
PLD( pld [r1, #-96] )
|
||||
|
||||
@@ -295,9 +293,7 @@ ENTRY(memmove)
|
||||
mov r4, r4, PUSH #\push
|
||||
orr r4, r4, r3, PULL #\pull
|
||||
stmdb r0!, {r4 - r8, r10, ip, lr}
|
||||
bge 12b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 13b )
|
||||
bhs 12b
|
||||
|
||||
pop {r5 - r8, r10}
|
||||
cfi_adjust_cfa_offset (-20)
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
(void) __close (fd)
|
||||
#define __read_nocancel(fd, buf, n) \
|
||||
__read (fd, buf, n)
|
||||
#define __pread64_nocancel(fd, buf, count, offset) \
|
||||
__pread64 (fd, buf, count, offset)
|
||||
#define __write_nocancel(fd, buf, n) \
|
||||
__write (fd, buf, n)
|
||||
#define __writev_nocancel_nostatus(fd, iov, n) \
|
||||
|
||||
@@ -27,26 +27,16 @@
|
||||
static int
|
||||
__utmp_equal (const struct utmp *entry, const struct utmp *match)
|
||||
{
|
||||
return
|
||||
(
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(entry->ut_type == INIT_PROCESS
|
||||
|| entry->ut_type == LOGIN_PROCESS
|
||||
|| entry->ut_type == USER_PROCESS
|
||||
|| entry->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
(match->ut_type == INIT_PROCESS
|
||||
|| match->ut_type == LOGIN_PROCESS
|
||||
|| match->ut_type == USER_PROCESS
|
||||
|| match->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
#if _HAVE_UT_ID - 0
|
||||
(entry->ut_id[0] && match->ut_id[0]
|
||||
? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
: strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
|
||||
#else
|
||||
strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
|
||||
#endif
|
||||
);
|
||||
return (entry->ut_type == INIT_PROCESS
|
||||
|| entry->ut_type == LOGIN_PROCESS
|
||||
|| entry->ut_type == USER_PROCESS
|
||||
|| entry->ut_type == DEAD_PROCESS)
|
||||
&& (match->ut_type == INIT_PROCESS
|
||||
|| match->ut_type == LOGIN_PROCESS
|
||||
|| match->ut_type == USER_PROCESS
|
||||
|| match->ut_type == DEAD_PROCESS)
|
||||
&& (entry->ut_id[0] && match->ut_id[0]
|
||||
? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
: (strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line)
|
||||
== 0));
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/* The `struct utmp' type, describing entries in the utmp file. GNU version.
|
||||
Copyright (C) 1993-2019 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _UTMP_H
|
||||
# error "Never include <bits/utmp.h> directly; use <utmp.h> instead."
|
||||
#endif
|
||||
|
||||
#include <paths.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <bits/wordsize.h>
|
||||
|
||||
|
||||
#define UT_LINESIZE 32
|
||||
#define UT_NAMESIZE 32
|
||||
#define UT_HOSTSIZE 256
|
||||
|
||||
|
||||
/* The structure describing an entry in the database of
|
||||
previous logins. */
|
||||
struct lastlog
|
||||
{
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ll_time;
|
||||
#else
|
||||
__time_t ll_time;
|
||||
#endif
|
||||
char ll_line[UT_LINESIZE];
|
||||
char ll_host[UT_HOSTSIZE];
|
||||
};
|
||||
|
||||
|
||||
/* The structure describing the status of a terminated process. This
|
||||
type is used in `struct utmp' below. */
|
||||
struct exit_status
|
||||
{
|
||||
short int e_termination; /* Process termination status. */
|
||||
short int e_exit; /* Process exit status. */
|
||||
};
|
||||
|
||||
|
||||
/* The structure describing an entry in the user accounting database. */
|
||||
struct utmp
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_user[UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
/* The ut_session and ut_tv fields must be the same size when compiled
|
||||
32- and 64-bit. This allows data files and shared memory to be
|
||||
shared between 32- and 64-bit applications. */
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ut_session; /* Session ID, used for windowing. */
|
||||
struct
|
||||
{
|
||||
int32_t tv_sec; /* Seconds. */
|
||||
int32_t tv_usec; /* Microseconds. */
|
||||
} ut_tv; /* Time entry was made. */
|
||||
#else
|
||||
long int ut_session; /* Session ID, used for windowing. */
|
||||
struct timeval ut_tv; /* Time entry was made. */
|
||||
#endif
|
||||
|
||||
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
|
||||
char __glibc_reserved[20]; /* Reserved for future use. */
|
||||
};
|
||||
|
||||
/* Backwards compatibility hacks. */
|
||||
#define ut_name ut_user
|
||||
#ifndef _NO_UT_TIME
|
||||
/* We have a problem here: `ut_time' is also used otherwise. Define
|
||||
_NO_UT_TIME if the compiler complains. */
|
||||
# define ut_time ut_tv.tv_sec
|
||||
#endif
|
||||
#define ut_xtime ut_tv.tv_sec
|
||||
#define ut_addr ut_addr_v6[0]
|
||||
|
||||
|
||||
/* Values for the `ut_type' field of a `struct utmp'. */
|
||||
#define EMPTY 0 /* No valid user accounting information. */
|
||||
|
||||
#define RUN_LVL 1 /* The system's runlevel. */
|
||||
#define BOOT_TIME 2 /* Time of system boot. */
|
||||
#define NEW_TIME 3 /* Time after system clock changed. */
|
||||
#define OLD_TIME 4 /* Time when system clock changed. */
|
||||
|
||||
#define INIT_PROCESS 5 /* Process spawned by the init process. */
|
||||
#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */
|
||||
#define USER_PROCESS 7 /* Normal process. */
|
||||
#define DEAD_PROCESS 8 /* Terminated process. */
|
||||
|
||||
#define ACCOUNTING 9
|
||||
|
||||
/* Old Linux name for the EMPTY type. */
|
||||
#define UT_UNKNOWN EMPTY
|
||||
|
||||
|
||||
/* Tell the user that we have a modern system with UT_HOST, UT_PID,
|
||||
UT_TYPE, UT_ID and UT_TV fields. */
|
||||
#define _HAVE_UT_TYPE 1
|
||||
#define _HAVE_UT_PID 1
|
||||
#define _HAVE_UT_ID 1
|
||||
#define _HAVE_UT_TV 1
|
||||
#define _HAVE_UT_HOST 1
|
||||
@@ -56,10 +56,14 @@ struct utmpx
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
__pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[__UT_LINESIZE]; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_user[__UT_NAMESIZE]; /* Username. */
|
||||
char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */
|
||||
char ut_line[__UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]
|
||||
__attribute_nonstring__; /* Inittab ID. */
|
||||
char ut_user[__UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[__UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct __exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
|
||||
|
||||
+20
-6
@@ -172,8 +172,8 @@ make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp)
|
||||
}
|
||||
|
||||
install:
|
||||
fdesc->ip = ip;
|
||||
fdesc->gp = gp;
|
||||
fdesc->ip = ip;
|
||||
|
||||
return (ElfW(Addr)) fdesc;
|
||||
}
|
||||
@@ -350,7 +350,9 @@ ElfW(Addr)
|
||||
_dl_lookup_address (const void *address)
|
||||
{
|
||||
ElfW(Addr) addr = (ElfW(Addr)) address;
|
||||
unsigned int *desc, *gptr;
|
||||
ElfW(Word) reloc_arg;
|
||||
volatile unsigned int *desc;
|
||||
unsigned int *gptr;
|
||||
|
||||
/* Return ADDR if the least-significant two bits of ADDR are not consistent
|
||||
with ADDR being a linker defined function pointer. The normal value for
|
||||
@@ -367,7 +369,11 @@ _dl_lookup_address (const void *address)
|
||||
if (!_dl_read_access_allowed (desc))
|
||||
return addr;
|
||||
|
||||
/* Load first word of candidate descriptor. It should be a pointer
|
||||
/* First load the relocation offset. */
|
||||
reloc_arg = (ElfW(Word)) desc[1];
|
||||
atomic_full_barrier();
|
||||
|
||||
/* Then load first word of candidate descriptor. It should be a pointer
|
||||
with word alignment and point to memory that can be read. */
|
||||
gptr = (unsigned int *) desc[0];
|
||||
if (((unsigned int) gptr & 3) != 0
|
||||
@@ -377,8 +383,8 @@ _dl_lookup_address (const void *address)
|
||||
/* See if descriptor requires resolution. The following trampoline is
|
||||
used in each global offset table for function resolution:
|
||||
|
||||
ldw 0(r20),r22
|
||||
bv r0(r22)
|
||||
ldw 0(r20),r21
|
||||
bv r0(r21)
|
||||
ldw 4(r20),r21
|
||||
tramp: b,l .-12,r20
|
||||
depwi 0,31,2,r20
|
||||
@@ -389,7 +395,15 @@ _dl_lookup_address (const void *address)
|
||||
if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */
|
||||
&& gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */
|
||||
&& (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
|
||||
_dl_fixup ((struct link_map *) gptr[5], (ElfW(Word)) desc[1]);
|
||||
{
|
||||
struct link_map *l = (struct link_map *) gptr[5];
|
||||
|
||||
/* If gp has been resolved, we need to hunt for relocation offset. */
|
||||
if (!(reloc_arg & PA_GP_RELOC))
|
||||
reloc_arg = _dl_fix_reloc_arg (addr, l);
|
||||
|
||||
_dl_fixup (l, reloc_arg);
|
||||
}
|
||||
|
||||
return (ElfW(Addr)) desc[0];
|
||||
}
|
||||
|
||||
@@ -48,6 +48,14 @@
|
||||
#define GOT_FROM_PLT_STUB (4*4)
|
||||
#define PLT_ENTRY_SIZE (2*4)
|
||||
|
||||
/* The gp slot in the function descriptor contains the relocation offset
|
||||
before resolution. To distinguish between a resolved gp value and an
|
||||
unresolved relocation offset we set an unused bit in the relocation
|
||||
offset. This would allow us to do a synchronzied two word update
|
||||
using this bit (interlocked update), but instead of waiting for the
|
||||
update we simply recompute the gp value given that we know the ip. */
|
||||
#define PA_GP_RELOC 1
|
||||
|
||||
/* Initialize the function descriptor table before relocations */
|
||||
static inline void
|
||||
__hppa_init_bootstrap_fdesc_table (struct link_map *map)
|
||||
@@ -117,10 +125,28 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
||||
volatile Elf32_Addr *rfdesc = reloc_addr;
|
||||
/* map is the link_map for the caller, t is the link_map for the object
|
||||
being called */
|
||||
rfdesc[1] = value.gp;
|
||||
/* Need to ensure that the gp is visible before the code
|
||||
entry point is updated */
|
||||
rfdesc[0] = value.ip;
|
||||
|
||||
/* We would like the function descriptor to be double word aligned. This
|
||||
helps performance (ip and gp then reside on the same cache line) and
|
||||
we can update the pair atomically with a single store. The linker
|
||||
now ensures this alignment but we still have to handle old code. */
|
||||
if ((unsigned int)reloc_addr & 7)
|
||||
{
|
||||
/* Need to ensure that the gp is visible before the code
|
||||
entry point is updated */
|
||||
rfdesc[1] = value.gp;
|
||||
atomic_full_barrier();
|
||||
rfdesc[0] = value.ip;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update pair atomically with floating point store. */
|
||||
union { ElfW(Word) v[2]; double d; } u;
|
||||
|
||||
u.v[0] = value.ip;
|
||||
u.v[1] = value.gp;
|
||||
*(volatile double *)rfdesc = u.d;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -265,7 +291,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
here. The trampoline code will load the proper
|
||||
LTP and pass the reloc offset to the fixup
|
||||
function. */
|
||||
fptr->gp = iplt - jmprel;
|
||||
fptr->gp = (iplt - jmprel) | PA_GP_RELOC;
|
||||
} /* r_sym != 0 */
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* On-demand PLT fixup for shared objects. HPPA version.
|
||||
Copyright (C) 2019 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
/* Clear PA_GP_RELOC bit in relocation offset. */
|
||||
#define reloc_offset (reloc_arg & ~PA_GP_RELOC)
|
||||
#define reloc_index (reloc_arg & ~PA_GP_RELOC) / sizeof (PLTREL)
|
||||
|
||||
#include <elf/dl-runtime.c>
|
||||
|
||||
/* The caller has encountered a partially relocated function descriptor.
|
||||
The gp of the descriptor has been updated, but not the ip. We find
|
||||
the function descriptor again and compute the relocation offset and
|
||||
return that to the caller. The caller will continue on to call
|
||||
_dl_fixup with the relocation offset. */
|
||||
|
||||
ElfW(Word)
|
||||
attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||
_dl_fix_reloc_arg (struct fdesc *fptr, struct link_map *l)
|
||||
{
|
||||
Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type;
|
||||
const Elf32_Rela *reloc;
|
||||
|
||||
l_addr = l->l_addr;
|
||||
jmprel = D_PTR(l, l_info[DT_JMPREL]);
|
||||
end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
|
||||
|
||||
/* Look for the entry... */
|
||||
for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
|
||||
{
|
||||
reloc = (const Elf32_Rela *) iplt;
|
||||
r_type = ELF32_R_TYPE (reloc->r_info);
|
||||
|
||||
if (__builtin_expect (r_type == R_PARISC_IPLT, 1)
|
||||
&& fptr == (struct fdesc *) (reloc->r_offset + l_addr))
|
||||
/* Found entry. Return the reloc offset. */
|
||||
return iplt - jmprel;
|
||||
}
|
||||
|
||||
/* Crash if we weren't passed a valid function pointer. */
|
||||
ABORT_INSTRUCTION;
|
||||
return 0;
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
slow down __cffc when it attempts to call fixup to resolve function
|
||||
descriptor references. Please refer to gcc/gcc/config/pa/fptr.c
|
||||
|
||||
Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp. */
|
||||
Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp, r22 = fp. */
|
||||
|
||||
/* RELOCATION MARKER: bl to provide gcc's __cffc with fixup loc. */
|
||||
.text
|
||||
@@ -61,17 +61,20 @@ _dl_runtime_resolve:
|
||||
copy %sp, %r1 /* Copy previous sp */
|
||||
/* Save function result address (on entry) */
|
||||
stwm %r28,128(%sp)
|
||||
/* Fillin some frame info to follow ABI */
|
||||
/* Fill in some frame info to follow ABI */
|
||||
stw %r1,-4(%sp) /* Previous sp */
|
||||
stw %r21,-32(%sp) /* PIC register value */
|
||||
|
||||
/* Save input floating point registers. This must be done
|
||||
in the new frame since the previous frame doesn't have
|
||||
enough space */
|
||||
ldo -56(%sp),%r1
|
||||
ldo -64(%sp),%r1
|
||||
fstd,ma %fr4,-8(%r1)
|
||||
fstd,ma %fr5,-8(%r1)
|
||||
fstd,ma %fr6,-8(%r1)
|
||||
|
||||
/* Test PA_GP_RELOC bit. */
|
||||
bb,>= %r19,31,2f /* branch if not reloc offset */
|
||||
fstd,ma %fr7,-8(%r1)
|
||||
|
||||
/* Set up args to fixup func, needs only two arguments */
|
||||
@@ -79,7 +82,7 @@ _dl_runtime_resolve:
|
||||
copy %r19,%r25 /* (2) reloc offset */
|
||||
|
||||
/* Call the real address resolver. */
|
||||
bl _dl_fixup,%rp
|
||||
3: bl _dl_fixup,%rp
|
||||
copy %r21,%r19 /* set fixup func ltp */
|
||||
|
||||
/* While the linker will set a function pointer to NULL when it
|
||||
@@ -102,7 +105,7 @@ _dl_runtime_resolve:
|
||||
copy %r29, %r19
|
||||
|
||||
/* Reload arguments fp args */
|
||||
ldo -56(%sp),%r1
|
||||
ldo -64(%sp),%r1
|
||||
fldd,ma -8(%r1),%fr4
|
||||
fldd,ma -8(%r1),%fr5
|
||||
fldd,ma -8(%r1),%fr6
|
||||
@@ -129,6 +132,25 @@ _dl_runtime_resolve:
|
||||
bv %r0(%rp)
|
||||
ldo -128(%sp),%sp
|
||||
|
||||
2:
|
||||
/* Set up args for _dl_fix_reloc_arg. */
|
||||
copy %r22,%r26 /* (1) function pointer */
|
||||
depi 0,31,2,%r26 /* clear least significant bits */
|
||||
ldw 8+4(%r20),%r25 /* (2) got[1] == struct link_map */
|
||||
|
||||
/* Save ltp and link map arg for _dl_fixup. */
|
||||
stw %r21,-56(%sp) /* ltp */
|
||||
stw %r25,-60(%sp) /* struct link map */
|
||||
|
||||
/* Find reloc offset. */
|
||||
bl _dl_fix_reloc_arg,%rp
|
||||
copy %r21,%r19 /* set func ltp */
|
||||
|
||||
/* Set up args for _dl_fixup. */
|
||||
ldw -56(%sp),%r21 /* ltp */
|
||||
ldw -60(%sp),%r26 /* (1) struct link map */
|
||||
b 3b
|
||||
copy %ret0,%r25 /* (2) reloc offset */
|
||||
.EXIT
|
||||
.PROCEND
|
||||
cfi_endproc
|
||||
@@ -153,7 +175,7 @@ _dl_runtime_profile:
|
||||
copy %sp, %r1 /* Copy previous sp */
|
||||
/* Save function result address (on entry) */
|
||||
stwm %r28,192(%sp)
|
||||
/* Fillin some frame info to follow ABI */
|
||||
/* Fill in some frame info to follow ABI */
|
||||
stw %r1,-4(%sp) /* Previous sp */
|
||||
stw %r21,-32(%sp) /* PIC register value */
|
||||
|
||||
@@ -181,10 +203,11 @@ _dl_runtime_profile:
|
||||
fstd,ma %fr5,8(%r1)
|
||||
fstd,ma %fr6,8(%r1)
|
||||
fstd,ma %fr7,8(%r1)
|
||||
/* 32-bit stack pointer and return register */
|
||||
stw %sp,-56(%sp)
|
||||
stw %r2,-52(%sp)
|
||||
|
||||
/* Test PA_GP_RELOC bit. */
|
||||
bb,>= %r19,31,2f /* branch if not reloc offset */
|
||||
/* 32-bit stack pointer */
|
||||
stw %sp,-56(%sp)
|
||||
|
||||
/* Set up args to fixup func, needs five arguments */
|
||||
ldw 8+4(%r20),%r26 /* (1) got[1] == struct link_map */
|
||||
@@ -197,7 +220,7 @@ _dl_runtime_profile:
|
||||
stw %r1, -52(%sp) /* (5) long int *framesizep */
|
||||
|
||||
/* Call the real address resolver. */
|
||||
bl _dl_profile_fixup,%rp
|
||||
3: bl _dl_profile_fixup,%rp
|
||||
copy %r21,%r19 /* set fixup func ltp */
|
||||
|
||||
/* Load up the returned function descriptor */
|
||||
@@ -215,7 +238,9 @@ _dl_runtime_profile:
|
||||
fldd,ma 8(%r1),%fr5
|
||||
fldd,ma 8(%r1),%fr6
|
||||
fldd,ma 8(%r1),%fr7
|
||||
ldw -52(%sp),%rp
|
||||
|
||||
/* Reload rp register -(192+20) without adjusting stack */
|
||||
ldw -212(%sp),%rp
|
||||
|
||||
/* Reload static link register -(192+16) without adjusting stack */
|
||||
ldw -208(%sp),%r29
|
||||
@@ -303,6 +328,33 @@ L(cont):
|
||||
ldw -20(%sp),%rp
|
||||
/* Return */
|
||||
bv,n 0(%r2)
|
||||
|
||||
2:
|
||||
/* Set up args for _dl_fix_reloc_arg. */
|
||||
copy %r22,%r26 /* (1) function pointer */
|
||||
depi 0,31,2,%r26 /* clear least significant bits */
|
||||
ldw 8+4(%r20),%r25 /* (2) got[1] == struct link_map */
|
||||
|
||||
/* Save ltp and link map arg for _dl_fixup. */
|
||||
stw %r21,-92(%sp) /* ltp */
|
||||
stw %r25,-116(%sp) /* struct link map */
|
||||
|
||||
/* Find reloc offset. */
|
||||
bl _dl_fix_reloc_arg,%rp
|
||||
copy %r21,%r19 /* set func ltp */
|
||||
|
||||
/* Restore fixup ltp. */
|
||||
ldw -92(%sp),%r21 /* ltp */
|
||||
|
||||
/* Set up args to fixup func, needs five arguments */
|
||||
ldw -116(%sp),%r26 /* (1) struct link map */
|
||||
copy %ret0,%r25 /* (2) reloc offset */
|
||||
stw %r25,-120(%sp) /* Save reloc offset */
|
||||
ldw -212(%sp),%r24 /* (3) profile_fixup needs rp */
|
||||
ldo -56(%sp),%r23 /* (4) La_hppa_regs */
|
||||
ldo -112(%sp), %r1
|
||||
b 3b
|
||||
stw %r1, -52(%sp) /* (5) long int *framesizep */
|
||||
.EXIT
|
||||
.PROCEND
|
||||
cfi_endproc
|
||||
|
||||
@@ -544,9 +544,9 @@ idouble: 1
|
||||
ifloat: 1
|
||||
|
||||
Function: Imaginary part of "ccos_downward":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "ccos_towardzero":
|
||||
@@ -556,9 +556,9 @@ idouble: 1
|
||||
ifloat: 2
|
||||
|
||||
Function: Imaginary part of "ccos_towardzero":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "ccos_upward":
|
||||
@@ -588,29 +588,29 @@ idouble: 1
|
||||
ifloat: 1
|
||||
|
||||
Function: Real part of "ccosh_downward":
|
||||
double: 1
|
||||
double: 2
|
||||
float: 3
|
||||
idouble: 1
|
||||
idouble: 2
|
||||
ifloat: 3
|
||||
|
||||
Function: Imaginary part of "ccosh_downward":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "ccosh_towardzero":
|
||||
double: 1
|
||||
float: 3
|
||||
idouble: 1
|
||||
ifloat: 3
|
||||
|
||||
Function: Imaginary part of "ccosh_towardzero":
|
||||
double: 2
|
||||
float: 3
|
||||
idouble: 2
|
||||
ifloat: 3
|
||||
|
||||
Function: Imaginary part of "ccosh_towardzero":
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "ccosh_upward":
|
||||
double: 1
|
||||
float: 2
|
||||
@@ -636,27 +636,27 @@ idouble: 1
|
||||
ifloat: 2
|
||||
|
||||
Function: Real part of "cexp_downward":
|
||||
double: 1
|
||||
double: 2
|
||||
float: 2
|
||||
idouble: 1
|
||||
idouble: 2
|
||||
ifloat: 2
|
||||
|
||||
Function: Imaginary part of "cexp_downward":
|
||||
double: 1
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 1
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "cexp_towardzero":
|
||||
double: 1
|
||||
double: 2
|
||||
float: 2
|
||||
idouble: 1
|
||||
idouble: 2
|
||||
ifloat: 2
|
||||
|
||||
Function: Imaginary part of "cexp_towardzero":
|
||||
double: 1
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 1
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "cexp_upward":
|
||||
@@ -666,9 +666,9 @@ idouble: 1
|
||||
ifloat: 2
|
||||
|
||||
Function: Imaginary part of "cexp_upward":
|
||||
double: 1
|
||||
double: 3
|
||||
float: 2
|
||||
idouble: 1
|
||||
idouble: 3
|
||||
ifloat: 2
|
||||
|
||||
Function: Real part of "clog":
|
||||
@@ -800,21 +800,21 @@ idouble: 1
|
||||
ifloat: 1
|
||||
|
||||
Function: "cosh_downward":
|
||||
double: 1
|
||||
double: 2
|
||||
float: 1
|
||||
idouble: 1
|
||||
idouble: 2
|
||||
ifloat: 1
|
||||
|
||||
Function: "cosh_towardzero":
|
||||
double: 1
|
||||
double: 2
|
||||
float: 1
|
||||
idouble: 1
|
||||
idouble: 2
|
||||
ifloat: 1
|
||||
|
||||
Function: "cosh_upward":
|
||||
double: 1
|
||||
double: 2
|
||||
float: 2
|
||||
idouble: 1
|
||||
idouble: 2
|
||||
ifloat: 2
|
||||
|
||||
Function: Real part of "cpow":
|
||||
@@ -834,9 +834,9 @@ ildouble: 2
|
||||
ldouble: 2
|
||||
|
||||
Function: Real part of "cpow_downward":
|
||||
double: 4
|
||||
double: 5
|
||||
float: 8
|
||||
idouble: 4
|
||||
idouble: 5
|
||||
ifloat: 8
|
||||
|
||||
Function: Imaginary part of "cpow_downward":
|
||||
@@ -846,9 +846,9 @@ idouble: 2
|
||||
ifloat: 2
|
||||
|
||||
Function: Real part of "cpow_towardzero":
|
||||
double: 4
|
||||
double: 5
|
||||
float: 8
|
||||
idouble: 4
|
||||
idouble: 5
|
||||
ifloat: 8
|
||||
|
||||
Function: Imaginary part of "cpow_towardzero":
|
||||
@@ -876,9 +876,9 @@ idouble: 1
|
||||
ifloat: 1
|
||||
|
||||
Function: Real part of "csin_downward":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Imaginary part of "csin_downward":
|
||||
@@ -888,9 +888,9 @@ idouble: 1
|
||||
ifloat: 2
|
||||
|
||||
Function: Real part of "csin_towardzero":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Imaginary part of "csin_towardzero":
|
||||
@@ -930,9 +930,9 @@ idouble: 2
|
||||
ifloat: 2
|
||||
|
||||
Function: Imaginary part of "csinh_downward":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "csinh_towardzero":
|
||||
@@ -942,9 +942,9 @@ idouble: 2
|
||||
ifloat: 2
|
||||
|
||||
Function: Imaginary part of "csinh_towardzero":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 3
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 3
|
||||
|
||||
Function: Real part of "csinh_upward":
|
||||
@@ -1172,15 +1172,15 @@ ildouble: 6
|
||||
ldouble: 6
|
||||
|
||||
Function: "exp10_downward":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 1
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 1
|
||||
|
||||
Function: "exp10_towardzero":
|
||||
double: 2
|
||||
double: 3
|
||||
float: 1
|
||||
idouble: 2
|
||||
idouble: 3
|
||||
ifloat: 1
|
||||
|
||||
Function: "exp10_upward":
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user