mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-10 05:59:39 +08:00
Compare commits
175
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d69c4aad4 | ||
|
|
73886db621 | ||
|
|
c49cbcdc32 | ||
|
|
2777e19c05 | ||
|
|
3668134a9e | ||
|
|
5fa7884e25 | ||
|
|
d8ae6c00a9 | ||
|
|
670c675da3 | ||
|
|
8fb94f8824 | ||
|
|
ec51be40c7 | ||
|
|
bdaa594506 | ||
|
|
68d583bb1c | ||
|
|
222b1517cd | ||
|
|
62df32d604 | ||
|
|
711f183508 | ||
|
|
8b84316420 | ||
|
|
477587c75e | ||
|
|
4b8628acab | ||
|
|
59420258af | ||
|
|
e075046743 | ||
|
|
daf88b1dd1 | ||
|
|
b29853702e | ||
|
|
bad8d5ff60 | ||
|
|
d64ad0a517 | ||
|
|
34ce87638c | ||
|
|
0df8ecff9e | ||
|
|
26f5442ec1 | ||
|
|
4b64a4245c | ||
|
|
dc7f51bda9 | ||
|
|
8edc96aa33 | ||
|
|
599ebfacc0 | ||
|
|
bef0b1cb31 | ||
|
|
4d5cfeb510 | ||
|
|
92f04eedb5 | ||
|
|
5b4f7382af | ||
|
|
9456483fb2 | ||
|
|
373f8b06a3 | ||
|
|
4ec1b9e913 | ||
|
|
ecd6271ed8 | ||
|
|
bba6b9288f | ||
|
|
7a4da6ef7a | ||
|
|
5f0d2e0491 | ||
|
|
e6b7252040 | ||
|
|
c74b884f70 | ||
|
|
0fc5934ebd | ||
|
|
e0a0bd3acc | ||
|
|
638caf3000 | ||
|
|
d5f45a29ff | ||
|
|
7f690fafad | ||
|
|
40df047b3b | ||
|
|
062139f233 | ||
|
|
f3e2add213 | ||
|
|
22bd3ab40e | ||
|
|
bdd16894aa | ||
|
|
0b48caab9a | ||
|
|
949da7f2fd | ||
|
|
f056ac8363 | ||
|
|
5f90e009b1 | ||
|
|
54ba8bcd42 | ||
|
|
f9c3c12f33 | ||
|
|
1961e5c729 | ||
|
|
de9d4aa353 | ||
|
|
1ab314d8d3 | ||
|
|
9f44fa22cb | ||
|
|
2ebadb6451 | ||
|
|
3a5ae8db68 | ||
|
|
2c016ffa24 | ||
|
|
d8457edece | ||
|
|
55f8812858 | ||
|
|
efc3714845 | ||
|
|
a4690969ed | ||
|
|
6465327195 | ||
|
|
50117e00a1 | ||
|
|
68c2930a56 | ||
|
|
766e8fb932 | ||
|
|
3981fc3453 | ||
|
|
f6d0e8c36f | ||
|
|
2794474c65 | ||
|
|
d8ca7a0c71 | ||
|
|
f1e211096b | ||
|
|
4e9f34e54f | ||
|
|
e75481a7a7 | ||
|
|
0f79dc0be3 | ||
|
|
6b2dd53aa0 | ||
|
|
50477165b9 | ||
|
|
4b246928bd | ||
|
|
9f433fc791 | ||
|
|
1517dfb8aa | ||
|
|
1050634904 | ||
|
|
d8eee5ef55 | ||
|
|
5cd5309d91 | ||
|
|
1759ea197b | ||
|
|
77b4b8231e | ||
|
|
5bdb6897fc | ||
|
|
a127df9f3e | ||
|
|
3b3775697a | ||
|
|
9533f19aa5 | ||
|
|
2b47bb9cba | ||
|
|
2dab17550d | ||
|
|
a452341529 | ||
|
|
8623cfe300 | ||
|
|
68c1bf8097 | ||
|
|
718445e569 | ||
|
|
33d1bde2de | ||
|
|
5fab7fe1dc | ||
|
|
7602b9e48c | ||
|
|
4492721165 | ||
|
|
060eb7c3b5 | ||
|
|
3bb7482574 | ||
|
|
4476d16b03 | ||
|
|
4e0847afce | ||
|
|
ffc5623978 | ||
|
|
80c83e9114 | ||
|
|
b25e5e3c09 | ||
|
|
8308fb2182 | ||
|
|
4a87157435 | ||
|
|
78e48cb5e5 | ||
|
|
0262507918 | ||
|
|
6c99e37f6f | ||
|
|
50df56ca86 | ||
|
|
0cf8a53e5f | ||
|
|
f51c836768 | ||
|
|
0cd4a5e87f | ||
|
|
8af3185d3e | ||
|
|
b2dd29a7ca | ||
|
|
f19e67884c | ||
|
|
edbf537d07 | ||
|
|
db988e50a8 | ||
|
|
a06d48fb9f | ||
|
|
c550fff3b7 | ||
|
|
11dee02dc0 | ||
|
|
3ca9a9aeea | ||
|
|
d658d6d757 | ||
|
|
a8a7d4c5d8 | ||
|
|
1a90f09f24 | ||
|
|
36fed309f6 | ||
|
|
623f4aef13 | ||
|
|
ced2cd1ede | ||
|
|
39071a5539 | ||
|
|
55ad82e45c | ||
|
|
df3ff4e49d | ||
|
|
aab08776cc | ||
|
|
94145309f5 | ||
|
|
3b92252641 | ||
|
|
5d679b8bd7 | ||
|
|
95c8ffa521 | ||
|
|
207e51524b | ||
|
|
19be35a250 | ||
|
|
b63daad97e | ||
|
|
1e52d8e65a | ||
|
|
78a90c2f74 | ||
|
|
7c6304182b | ||
|
|
11dbb01577 | ||
|
|
8e79230a5e | ||
|
|
f36553bf6a | ||
|
|
ea4ea9f875 | ||
|
|
e12a365d3a | ||
|
|
b6c9b80e72 | ||
|
|
fc0ad3d5e7 | ||
|
|
3a53ef9b02 | ||
|
|
e51dfc04ef | ||
|
|
b4108a361f | ||
|
|
aa02f2b2f5 | ||
|
|
6031b49c39 | ||
|
|
d5f136743d | ||
|
|
1b7671f6e1 | ||
|
|
516fa60804 | ||
|
|
79543e5479 | ||
|
|
55171cd08f | ||
|
|
750a1c253f | ||
|
|
56170e064e | ||
|
|
00c5a2d77a | ||
|
|
c8ad6ac1d1 | ||
|
|
ce8a6550fa | ||
|
|
bdac1623cc |
@@ -441,15 +441,6 @@ Permission to use, copy, modify, and distribute this
|
||||
software is freely granted, provided that this notice
|
||||
is preserved.
|
||||
|
||||
Part of stdio-common/tst-printf.c is copyright C E Chew:
|
||||
|
||||
(C) Copyright C E Chew
|
||||
|
||||
Feel free to copy, use and distribute this software provided:
|
||||
|
||||
1. you do not pretend that you wrote it
|
||||
2. you leave this copyright notice intact.
|
||||
|
||||
Various long double libm functions are copyright Stephen L. Moshier:
|
||||
|
||||
Copyright 2001 by Stephen L. Moshier <moshier@na-net.ornl.gov>
|
||||
|
||||
@@ -4,6 +4,209 @@ 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.27.1
|
||||
|
||||
Major new features:
|
||||
|
||||
* The entry for the new Japanese era has been added for ja_JP locale.
|
||||
|
||||
* Nominative and genitive month names are now supported for the Catalan and
|
||||
Czech languages. The Catalan and Greek languages now support abbreviated
|
||||
alternative month names.
|
||||
|
||||
* Parsing of dynamic string tokens in DT_RPATH, DT_RUNPATH, DT_NEEDED,
|
||||
DT_AUXILIARY, and DT_FILTER has been expanded to support the full
|
||||
range of ELF gABI expressions including such constructs as
|
||||
'$ORIGIN$ORIGIN' (if valid). For SUID/GUID applications the rules
|
||||
have been further restricted, and where in the past a dynamic string
|
||||
token sequence may have been interpreted as a literal string it will
|
||||
now cause a load failure. These load failures were always considered
|
||||
unspecified behaviour from the perspective of the dynamic loader, and
|
||||
for safety are now load errors e.g. /foo/${ORIGIN}.so in DT_NEEDED
|
||||
results in a load failure now.
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
* The copy_file_range function fails with ENOSYS if the kernel does not
|
||||
support the system call of the same name. Previously, user space
|
||||
emulation was performed, but its behavior did not match the kernel
|
||||
behavior, which was deemed too confusing. Applications which use the
|
||||
copy_file_range function will have to be run on kernels which implement
|
||||
the copy_file_range system call. Support for most architectures was added
|
||||
in version 4.5 of the mainline Linux kernel.
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2016-10228: An infinite loop has been fixed in the iconv program when
|
||||
invoked with the -c option and when processing invalid multi-byte input
|
||||
sequences. Reported by Jan Engelhardt.
|
||||
|
||||
CVE-2017-18269: An SSE2-based memmove implementation for the i386
|
||||
architecture could corrupt memory. Reported by Max Horn.
|
||||
|
||||
CVE-2018-11236: Very long pathname arguments to realpath function could
|
||||
result in an integer overflow and buffer overflow. Reported by Alexey
|
||||
Izbyshev.
|
||||
|
||||
CVE-2018-11237: The mempcpy implementation for the Intel Xeon Phi
|
||||
architecture could write beyond the target buffer, resulting in a buffer
|
||||
overflow. Reported by Andreas Schwab.
|
||||
|
||||
CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a
|
||||
denial of service due to resource exhaustion when processing getaddrinfo
|
||||
calls with crafted host names. Reported by Guido Vranken.
|
||||
|
||||
CVE-2019-6488: On x32, the size_t parameter may be passed in the lower
|
||||
32 bits of a 64-bit register with with non-zero upper 32 bit. When it
|
||||
happened, accessing the 32-bit size_t value as the full 64-bit register
|
||||
in the assembly string/memory functions would cause a buffer overflow.
|
||||
Reported by H.J. Lu.
|
||||
|
||||
CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check
|
||||
size. For x86-64, memcmp on an object size larger than SSIZE_MAX
|
||||
has undefined behavior. On x32, the size_t argument may be passed
|
||||
in the lower 32 bits of the 64-bit RDX register with non-zero upper
|
||||
32 bits. When it happened with the sign bit of RDX register set,
|
||||
memcmp gave the wrong result since it treated the size argument as
|
||||
zero. Reported by H.J. Lu.
|
||||
|
||||
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-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-6096: A signed comparison vulnerability in the ARMv7 memcpy and
|
||||
memmove functions has been fixed. Discovered by Jason Royes and Samual
|
||||
Dytrych of the Cisco Security Assessment and Penetration Team (See
|
||||
TALOS-2020-1019).
|
||||
|
||||
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-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-27645: The nameserver caching daemon (nscd), when processing
|
||||
a request for netgroup lookup, may crash due to a double-free,
|
||||
potentially resulting in degraded service or Denial of Service on the
|
||||
local system. Reported by Chris Schanzle.
|
||||
|
||||
CVE-2021-35942: The wordexp function may overflow the positional
|
||||
parameter number when processing the expansion resulting in a crash.
|
||||
Reported by Philippe Antoine.
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[6889] 'PWD' mentioned but not specified
|
||||
[16335] Feature test macro documentation incomplete and out of date
|
||||
[17343] Signed integer overflow in /stdlib/random_r.c
|
||||
[18018] Additional $ORIGIN handling issues (CVE-2011-0536)
|
||||
[18035] Fix pldd hang
|
||||
[18830] locale: iconv -c -f ascii with >buffer size worth of input before
|
||||
invalid input drops valid char
|
||||
[19519] iconv(1) with -c option hangs on illegal multi-byte sequences
|
||||
(CVE-2016-10228)
|
||||
[20419] files with large allocated notes crash in open_verify
|
||||
[20568] Fix crash in _IO_wfile_sync
|
||||
[21269] i386 sigaction sa_restorer handling is wrong
|
||||
[21812] getifaddrs: Don't return ifa entries with NULL names
|
||||
[21942] _dl_dst_substitute incorrectly handles $ORIGIN: with AT_SECURE=1
|
||||
[22342] NSCD not properly caching netgroup
|
||||
[22638] sparc: static binaries are broken if glibc is built by gcc
|
||||
configured with --enable-default-pie
|
||||
[22644] memmove-sse2-unaligned on 32bit x86 produces garbage when crossing
|
||||
2GB threshold
|
||||
[22735] Misleading typo in time.h source comment regarding CLOCKS_PER_SECOND
|
||||
[22753] libc: preadv2/pwritev2 fallback code should handle offset=-1
|
||||
[22786] Stack buffer overflow in realpath() if input size is close
|
||||
to SSIZE_MAX
|
||||
[22797] Linux: use reserved name __key in pkey_get
|
||||
[22807] PTRACE_* constants missing for powerpc
|
||||
[22818] posix/tst-glob_lstat_compat failure on alpha
|
||||
[22827] RISC-V ELF64 parser mis-reads flag in ldconfig
|
||||
[22848] ca_ES: update date definitions from CLDR
|
||||
[22884] RISCV fmax/fmin handle signalling NANs incorrectly
|
||||
[22918] multiple common of `__nss_shadow_database'
|
||||
[22919] sparc32: backtrace yields infinite backtrace with makecontext
|
||||
[22926] FTBFS on powerpcspe
|
||||
[22927] libanl: properly cleanup if first helper thread creation failed
|
||||
[22932] lt_LT: Update of abbreviated month names from CLDR required
|
||||
[22937] Greek (el_GR, el_CY) locales actually need ab_alt_mon
|
||||
[22947] FAIL: misc/tst-preadvwritev2
|
||||
[22963] cs_CZ: Add alternative month names
|
||||
[22964] The Japanese Era name will be changed on May 1, 2019
|
||||
[22996] localedata: change LC_PAPER to en_US in es_BO locale
|
||||
[23005] Crash in __res_context_send after memory allocation failure
|
||||
[23036] regexec: Fix off-by-one bug in weight comparison
|
||||
[23037] initialize msg_flags to zero for sendmmsg() calls
|
||||
[23069] sigaction broken on riscv64-linux-gnu
|
||||
[23102] Incorrect parsing of consecutive $ variables in runpath entries
|
||||
[23132] localedata: Missing transliterations in Miscellaneous Mathematical
|
||||
Symbols-A/B Unicode blocks
|
||||
[23137] s390: pthread_join sometimes block indefinitely (on 31bit and libc
|
||||
build with -Os)
|
||||
[23152] gd_GB: Fix typo in "May" (abbreviated)
|
||||
[23166] sunrpc: Remove stray exports without --enable-obsolete-rpc
|
||||
[23171] Fix parameter type in C++ version of iseqsig
|
||||
[23196] __mempcpy_avx512_no_vzeroupper mishandles large copies
|
||||
[23236] Harden function pointers in _IO_str_fields
|
||||
[23253] Set 387 and SSE2 rounding mode for tgamma on i386
|
||||
[23259] Unsubstituted ${ORIGIN} remains in DT_NEEDED for AT_SECURE
|
||||
[23264] libc: posix_spawnp wrongly executes ENOEXEC in non compat mode
|
||||
[23275] Race in pthread_mutex_lock while promoting to PTHREAD_MUTEX_ELISION_NP
|
||||
[23313] libio: Disable vtable validation in case of interposition
|
||||
[23349] Various glibc headers no longer compatible with <linux/time.h>
|
||||
[23363] stdio-common/tst-printf.c has non-free license
|
||||
[23456] Wrong index_cpu_LZCNT
|
||||
[23459] COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors
|
||||
[23520] nscd: nscd: Use-after-free in addgetnetgrentX and its callers
|
||||
[23538] pthread_cond_broadcast: Fix waiters-after-spinning case
|
||||
[23562] signal: Use correct type for si_band in siginfo_t
|
||||
[23579] libc: Errors misreported in preadv2
|
||||
[23614] powerpc: missing CFI register information in __mpn_* functions
|
||||
[23690] Fix _dl_profile_fixup data-dependency issue
|
||||
[23709] Fix CPU string flags for Haswell-type CPUs
|
||||
[23821] si_band in siginfo_t has wrong type long int on sparc64
|
||||
[23822] ia64 static libm.a is missing exp2f, log2f and powf symbols
|
||||
[23861] rdlock stalls indefinitely on an unlocked pthread rwlock
|
||||
[23907] Incorrect double-free malloc tcache check disregards tcache size
|
||||
[23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591)
|
||||
[24018] gettext may return NULL
|
||||
[24027] malloc: Integer overflow in realloc
|
||||
[24097] Can't use 64-bit register for size_t in assembly codes for x32 (CVE-2019-6488)
|
||||
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
|
||||
[24180] pthread_mutex_trylock does not use the correct order of instructions
|
||||
while maintaining the robust mutex list due to missing compiler barriers
|
||||
[24228] old x86 applications that use legacy libio crash on exit
|
||||
[24531] Malloc tunables give tcache assertion failures
|
||||
[24744] io: Remove the copy_file_range emulation
|
||||
[25203] libio: Disable vtable validation for pre-2.1 interposed handles
|
||||
[25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs
|
||||
[25232] No const correctness for strchr et al. for Clang++
|
||||
[25414] 'glob' use-after-free bug (CVE-2020-1752)
|
||||
[25423] Array overflow in backtrace on powerpc
|
||||
[25487] sinl() stack corruption from crafted input (CVE-2020-10029)
|
||||
[25620] libc: Signed comparison vulnerability in the ARMv7 memcpy() (CVE-2020-6096)
|
||||
[26224] iconv hangs when converting some invalid inputs from several IBM
|
||||
character sets (CVE-2020-27618)
|
||||
[26383] bind_textdomain_codeset doesn't accept //TRANSLIT anymore
|
||||
[26923] Assertion failure in iconv when converting invalid UCS4 (CVE-2020-29562)
|
||||
[27462] nscd: double-free in nscd (CVE-2021-27645)
|
||||
[28011] libc: Wild read in wordexp (parse_param) (CVE-2021-35942)
|
||||
|
||||
|
||||
Version 2.27
|
||||
|
||||
@@ -262,6 +465,10 @@ Security related changes:
|
||||
an object size near the value of SIZE_MAX, would return a pointer to a
|
||||
buffer which is too small, instead of NULL. Reported by Jakub Wilk.
|
||||
|
||||
CVE-2018-6551: The malloc function, when called with an object size near
|
||||
the value of SIZE_MAX, would return a pointer to a buffer which is too
|
||||
small, instead of NULL.
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[866] glob: glob should match dangling symlinks
|
||||
@@ -334,6 +541,7 @@ The following bugs are resolved with this release:
|
||||
[21326] libc: C99 functions are not declared for C++11 and later if
|
||||
_GNU_SOURCE is not predefined by g++
|
||||
[21457] libc: sys/ucontext.h namespace
|
||||
[21508] locale: intl/tst-gettext failure with latest msgfmt
|
||||
[21530] libc: tmpfile() should be implemented using O_TMPFILE
|
||||
[21660] math: GCC fails to compile a formula with tgmath.h
|
||||
[21672] nptl: sys-libs/glibc on ia64 crashes on thread exit: signal
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define STRCASESTR simple_strcasestr
|
||||
#define NO_ALIAS
|
||||
#define __strncasecmp strncasecmp
|
||||
#define __strnlen strnlen
|
||||
#include "../string/strcasestr.c"
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
|
||||
#define STRSTR simple_strstr
|
||||
#undef libc_hidden_builtin_def
|
||||
#define libc_hidden_builtin_def(X)
|
||||
#define __strnlen strnlen
|
||||
#include "../string/strstr.c"
|
||||
|
||||
|
||||
|
||||
@@ -28,5 +28,6 @@
|
||||
#define RWF_DSYNC 0x00000002 /* per-IO O_DSYNC. */
|
||||
#define RWF_SYNC 0x00000004 /* per-IO O_SYNC. */
|
||||
#define RWF_NOWAIT 0x00000008 /* per-IO nonblocking mode. */
|
||||
#define RWF_APPEND 0x00000010 /* per-IO O_APPEND. */
|
||||
|
||||
#endif /* sys/uio_ext.h */
|
||||
|
||||
@@ -58,6 +58,11 @@ $1 ~ "msg(id|str)" {
|
||||
next
|
||||
}
|
||||
|
||||
/^"POT-Creation-Date: [0-9-]+ [0-9:+-]+\\n"/ {
|
||||
# Ignore POT-Creation-Date to match what is done in intl/Makefile.
|
||||
next
|
||||
}
|
||||
|
||||
/^".*"/ {
|
||||
# Append to current message
|
||||
sub(/^"/, "", $0)
|
||||
|
||||
+13
-13
@@ -367,7 +367,7 @@ while ($#headers >= 0) {
|
||||
s/^optional-//;
|
||||
$optional = 1;
|
||||
}
|
||||
if (/^element *({([^}]*)}|([^{ ]*)) *({([^}]*)}|([^{ ]*)) *([A-Za-z0-9_]*) *(.*)/) {
|
||||
if (/^element *(\{([^}]*)\}|([^{ ]*)) *(\{([^}]*)\}|([^{ ]*)) *([A-Za-z0-9_]*) *(.*)/) {
|
||||
my($struct) = "$2$3";
|
||||
my($type) = "$5$6";
|
||||
my($member) = "$7";
|
||||
@@ -556,7 +556,7 @@ while ($#headers >= 0) {
|
||||
"Symbol \"$symbol\" has not the right value.", $res,
|
||||
$xfail);
|
||||
}
|
||||
} elsif (/^type *({([^}]*)|([a-zA-Z0-9_]*))/) {
|
||||
} elsif (/^type *(\{([^}]*)|([a-zA-Z0-9_]*))/) {
|
||||
my($type) = "$2$3";
|
||||
my($maybe_opaque) = 0;
|
||||
|
||||
@@ -586,7 +586,7 @@ while ($#headers >= 0) {
|
||||
? "NOT AVAILABLE"
|
||||
: "Type \"$type\" not available."), $missing, $optional,
|
||||
$xfail);
|
||||
} elsif (/^tag *({([^}]*)|([a-zA-Z0-9_]*))/) {
|
||||
} elsif (/^tag *(\{([^}]*)|([a-zA-Z0-9_]*))/) {
|
||||
my($type) = "$2$3";
|
||||
|
||||
# Remember that this name is allowed.
|
||||
@@ -607,7 +607,7 @@ while ($#headers >= 0) {
|
||||
|
||||
compiletest ($fnamebase, "Testing for type $type",
|
||||
"Type \"$type\" not available.", $missing, 0, $xfail);
|
||||
} elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
} elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
my($rettype) = "$2$3";
|
||||
my($fname) = "$4";
|
||||
my($args) = "$5";
|
||||
@@ -644,7 +644,7 @@ while ($#headers >= 0) {
|
||||
"Function \"$fname\" has incorrect type.", $res, 0,
|
||||
$xfail);
|
||||
}
|
||||
} elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
} elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
my($rettype) = "$2$3";
|
||||
my($fname) = "$4";
|
||||
my($args) = "$5";
|
||||
@@ -681,7 +681,7 @@ while ($#headers >= 0) {
|
||||
"Function \"$fname\" has incorrect type.", $res, 0,
|
||||
$xfail);
|
||||
}
|
||||
} elsif (/^variable *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) *(.*)/) {
|
||||
} elsif (/^variable *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) *(.*)/) {
|
||||
my($type) = "$2$3";
|
||||
my($vname) = "$4";
|
||||
my($rest) = "$5";
|
||||
@@ -713,7 +713,7 @@ while ($#headers >= 0) {
|
||||
|
||||
compiletest ($fnamebase, "Test for type of variable $fname",
|
||||
"Variable \"$vname\" has incorrect type.", $res, 0, $xfail);
|
||||
} elsif (/^macro-function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
} elsif (/^macro-function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
my($rettype) = "$2$3";
|
||||
my($fname) = "$4";
|
||||
my($args) = "$5";
|
||||
@@ -812,11 +812,11 @@ while ($#headers >= 0) {
|
||||
|
||||
s/^xfail(\[([^\]]*)\])?-//;
|
||||
s/^optional-//;
|
||||
if (/^element *({([^}]*)}|([^ ]*)) *({([^}]*)}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) {
|
||||
if (/^element *(\{([^}]*)\}|([^ ]*)) *(\{([^}]*)\}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) {
|
||||
push @allow, $7;
|
||||
} elsif (/^(macro|constant|macro-constant|macro-int-constant) +([a-zA-Z0-9_]*) *(?:{([^}]*)} *)?(?:([>=<!]+) ([A-Za-z0-9_-]*))?/) {
|
||||
push @allow, $2;
|
||||
} elsif (/^(type|tag) *({([^}]*)|([a-zA-Z0-9_]*))/) {
|
||||
} elsif (/^(type|tag) *(\{([^}]*)|([a-zA-Z0-9_]*))/) {
|
||||
my($type) = "$3$4";
|
||||
|
||||
# Remember that this name is allowed.
|
||||
@@ -827,13 +827,13 @@ while ($#headers >= 0) {
|
||||
} else {
|
||||
push @allow, $type;
|
||||
}
|
||||
} elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
} elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
push @allow, $4;
|
||||
} elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
} elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
push @allow, $4;
|
||||
} elsif (/^variable *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*)/) {
|
||||
} elsif (/^variable *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*)/) {
|
||||
push @allow, $4;
|
||||
} elsif (/^macro-function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
} elsif (/^macro-function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) {
|
||||
push @allow, $4;
|
||||
} elsif (/^symbol *([a-zA-Z0-9_]*) *([A-Za-z0-9_-]*)?/) {
|
||||
push @allow, $1;
|
||||
|
||||
@@ -170,7 +170,8 @@ element siginfo_t pid_t si_pid
|
||||
element siginfo_t uid_t si_uid
|
||||
element siginfo_t {void*} si_addr
|
||||
element siginfo_t int si_status
|
||||
element siginfo_t long si_band
|
||||
// Bug 23821: si_band has type int on sparc64.
|
||||
xfail[sparc64-linux]-element siginfo_t long si_band
|
||||
# endif
|
||||
# ifndef XPG42
|
||||
element siginfo_t {union sigval} si_value
|
||||
|
||||
@@ -44,7 +44,8 @@ element siginfo_t pid_t si_pid
|
||||
element siginfo_t uid_t si_uid
|
||||
element siginfo_t {void*} si_addr
|
||||
element siginfo_t int si_status
|
||||
element siginfo_t long si_band
|
||||
// Bug 23821: si_band has type int on sparc64.
|
||||
xfail[sparc64-linux]-element siginfo_t long si_band
|
||||
# ifndef XPG42
|
||||
element siginfo_t {union sigval} si_value
|
||||
# endif
|
||||
|
||||
@@ -88,6 +88,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
|
||||
|
||||
@@ -55,8 +55,8 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
|
||||
_IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
|
||||
_IO_str_init_static_internal (&sf, string, init_string_size, string);
|
||||
sf._sbf._f._flags &= ~_IO_USER_BUF;
|
||||
sf._s._allocate_buffer = (_IO_alloc_type) malloc;
|
||||
sf._s._free_buffer = (_IO_free_type) free;
|
||||
sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
|
||||
sf._s._free_buffer_unused = (_IO_free_type) free;
|
||||
|
||||
/* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
|
||||
can only come from read-only format strings. */
|
||||
|
||||
+4
-1
@@ -197,7 +197,10 @@ check_free (struct dl_action_result *rec)
|
||||
Dl_info info;
|
||||
if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
|
||||
#endif
|
||||
free ((char *) rec->errstring);
|
||||
{
|
||||
free ((char *) rec->errstring);
|
||||
rec->errstring = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -187,7 +187,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
|
||||
tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
|
||||
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
|
||||
tst-debug1 tst-main1
|
||||
tst-debug1 tst-main1 tst-big-note
|
||||
# reldep9
|
||||
tests-internal += loadtest unload unload2 circleload1 \
|
||||
neededtest neededtest2 neededtest3 neededtest4 \
|
||||
@@ -272,7 +272,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
|
||||
tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
|
||||
tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
|
||||
tst-main1mod tst-libc_dlvsym-dso
|
||||
tst-main1mod tst-libc_dlvsym-dso \
|
||||
tst-big-note-lib
|
||||
|
||||
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
tests += tst-gnu2-tls1
|
||||
modules-names += tst-gnu2-tls1mod
|
||||
@@ -1446,3 +1448,5 @@ $(objpfx)tst-libc_dlvsym-static: $(common-objpfx)dlfcn/libdl.a
|
||||
tst-libc_dlvsym-static-ENV = \
|
||||
LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
|
||||
$(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so
|
||||
|
||||
$(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ struct list
|
||||
({ \
|
||||
const char *__str = (str); \
|
||||
const char *__result = __str; \
|
||||
size_t __dst_cnt = DL_DST_COUNT (__str); \
|
||||
size_t __dst_cnt = _dl_dst_count (__str); \
|
||||
\
|
||||
if (__dst_cnt != 0) \
|
||||
{ \
|
||||
|
||||
@@ -18,19 +18,6 @@
|
||||
|
||||
#include "trusted-dirs.h"
|
||||
|
||||
/* Determine the number of DST elements in the name. Only if IS_PATH is
|
||||
nonzero paths are recognized (i.e., multiple, ':' separated filenames). */
|
||||
#define DL_DST_COUNT(name) \
|
||||
({ \
|
||||
size_t __cnt = 0; \
|
||||
const char *__sf = strchr (name, '$'); \
|
||||
\
|
||||
if (__glibc_unlikely (__sf != NULL)) \
|
||||
__cnt = _dl_dst_count (__sf); \
|
||||
\
|
||||
__cnt; })
|
||||
|
||||
|
||||
#ifdef SHARED
|
||||
# define IS_RTLD(l) (l) == &GL(dl_rtld_map)
|
||||
#else
|
||||
|
||||
+153
-81
@@ -122,12 +122,6 @@ is_trusted_path_normalize (const char *path, size_t len)
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
if (*path == ':')
|
||||
{
|
||||
++path;
|
||||
--len;
|
||||
}
|
||||
|
||||
char *npath = (char *) alloca (len + 2);
|
||||
char *wnp = npath;
|
||||
while (*path != '\0')
|
||||
@@ -178,114 +172,165 @@ is_trusted_path_normalize (const char *path, size_t len)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Given a substring starting at INPUT, just after the DST '$' start
|
||||
token, determine if INPUT contains DST token REF, following the
|
||||
ELF gABI rules for DSTs:
|
||||
|
||||
* Longest possible sequence using the rules (greedy).
|
||||
|
||||
* Must start with a $ (enforced by caller).
|
||||
|
||||
* Must follow $ with one underscore or ASCII [A-Za-z] (caller
|
||||
follows these rules for REF) or '{' (start curly quoted name).
|
||||
|
||||
* Must follow first two characters with zero or more [A-Za-z0-9_]
|
||||
(enforced by caller) or '}' (end curly quoted name).
|
||||
|
||||
If the sequence is a DST matching REF then the length of the DST
|
||||
(excluding the $ sign but including curly braces, if any) is
|
||||
returned, otherwise 0. */
|
||||
static size_t
|
||||
is_dst (const char *start, const char *name, const char *str, int secure)
|
||||
is_dst (const char *input, const char *ref)
|
||||
{
|
||||
size_t len;
|
||||
bool is_curly = false;
|
||||
|
||||
if (name[0] == '{')
|
||||
/* Is a ${...} input sequence? */
|
||||
if (input[0] == '{')
|
||||
{
|
||||
is_curly = true;
|
||||
++name;
|
||||
++input;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
while (name[len] == str[len] && name[len] != '\0')
|
||||
++len;
|
||||
/* Check for matching name, following closing curly brace (if
|
||||
required), or trailing characters which are part of an
|
||||
identifier. */
|
||||
size_t rlen = strlen (ref);
|
||||
if (strncmp (input, ref, rlen) != 0
|
||||
|| (is_curly && input[rlen] != '}')
|
||||
|| ((input[rlen] >= 'A' && input[rlen] <= 'Z')
|
||||
|| (input[rlen] >= 'a' && input[rlen] <= 'z')
|
||||
|| (input[rlen] >= '0' && input[rlen] <= '9')
|
||||
|| (input[rlen] == '_')))
|
||||
return 0;
|
||||
|
||||
if (is_curly)
|
||||
{
|
||||
if (name[len] != '}')
|
||||
return 0;
|
||||
|
||||
/* Point again at the beginning of the name. */
|
||||
--name;
|
||||
/* Skip over closing curly brace and adjust for the --name. */
|
||||
len += 2;
|
||||
}
|
||||
else if (name[len] != '\0' && name[len] != '/')
|
||||
return 0;
|
||||
|
||||
if (__glibc_unlikely (secure)
|
||||
&& ((name[len] != '\0' && name[len] != '/')
|
||||
|| (name != start + 1)))
|
||||
return 0;
|
||||
|
||||
return len;
|
||||
/* Count the two curly braces. */
|
||||
return rlen + 2;
|
||||
else
|
||||
return rlen;
|
||||
}
|
||||
|
||||
|
||||
/* INPUT is the start of a DST sequence at the first '$' occurrence.
|
||||
If there is a DST we call into _dl_dst_count to count the number of
|
||||
DSTs. We count all known DSTs regardless of __libc_enable_secure;
|
||||
the caller is responsible for enforcing the security of the
|
||||
substitution rules (usually _dl_dst_substitute). */
|
||||
size_t
|
||||
_dl_dst_count (const char *name)
|
||||
_dl_dst_count (const char *input)
|
||||
{
|
||||
const char *const start = name;
|
||||
size_t cnt = 0;
|
||||
|
||||
input = strchr (input, '$');
|
||||
|
||||
/* Most likely there is no DST. */
|
||||
if (__glibc_likely (input == NULL))
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
size_t len;
|
||||
|
||||
/* $ORIGIN is not expanded for SUID/GUID programs (except if it
|
||||
is $ORIGIN alone) and it must always appear first in path. */
|
||||
++name;
|
||||
if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0
|
||||
|| (len = is_dst (start, name, "PLATFORM", 0)) != 0
|
||||
|| (len = is_dst (start, name, "LIB", 0)) != 0)
|
||||
++input;
|
||||
/* All DSTs must follow ELF gABI rules, see is_dst (). */
|
||||
if ((len = is_dst (input, "ORIGIN")) != 0
|
||||
|| (len = is_dst (input, "PLATFORM")) != 0
|
||||
|| (len = is_dst (input, "LIB")) != 0)
|
||||
++cnt;
|
||||
|
||||
name = strchr (name + len, '$');
|
||||
/* There may be more than one DST in the input. */
|
||||
input = strchr (input + len, '$');
|
||||
}
|
||||
while (name != NULL);
|
||||
while (input != NULL);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
/* Process INPUT for DSTs and store in RESULT using the information
|
||||
from link map L to resolve the DSTs. This function only handles one
|
||||
path at a time and does not handle colon-separated path lists (see
|
||||
fillin_rpath ()). Lastly the size of result in bytes should be at
|
||||
least equal to the value returned by DL_DST_REQUIRED. Note that it
|
||||
is possible for a DT_NEEDED, DT_AUXILIARY, and DT_FILTER entries to
|
||||
have colons, but we treat those as literal colons here, not as path
|
||||
list delimeters. */
|
||||
char *
|
||||
_dl_dst_substitute (struct link_map *l, const char *name, char *result)
|
||||
_dl_dst_substitute (struct link_map *l, const char *input, char *result)
|
||||
{
|
||||
const char *const start = name;
|
||||
|
||||
/* Now fill the result path. While copying over the string we keep
|
||||
track of the start of the last path element. When we come across
|
||||
a DST we copy over the value or (if the value is not available)
|
||||
leave the entire path element out. */
|
||||
/* Copy character-by-character from input into the working pointer
|
||||
looking for any DSTs. We track the start of input and if we are
|
||||
going to check for trusted paths, all of which are part of $ORIGIN
|
||||
handling in SUID/SGID cases (see below). In some cases, like when
|
||||
a DST cannot be replaced, we may set result to an empty string and
|
||||
return. */
|
||||
char *wp = result;
|
||||
char *last_elem = result;
|
||||
const char *start = input;
|
||||
bool check_for_trusted = false;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (*name == '$'))
|
||||
if (__glibc_unlikely (*input == '$'))
|
||||
{
|
||||
const char *repl = NULL;
|
||||
size_t len;
|
||||
|
||||
++name;
|
||||
if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0)
|
||||
++input;
|
||||
if ((len = is_dst (input, "ORIGIN")) != 0)
|
||||
{
|
||||
repl = l->l_origin;
|
||||
/* For SUID/GUID programs we normally ignore the path with
|
||||
$ORIGIN in DT_RUNPATH, or DT_RPATH. However, there is
|
||||
one exception to this rule, and it is:
|
||||
|
||||
* $ORIGIN appears as the first path element, and is
|
||||
the only string in the path or is immediately
|
||||
followed by a path separator and the rest of the
|
||||
path.
|
||||
|
||||
* The path is rooted in a trusted directory.
|
||||
|
||||
This exception allows such programs to reference
|
||||
shared libraries in subdirectories of trusted
|
||||
directories. The use case is one of general
|
||||
organization and deployment flexibility.
|
||||
Trusted directories are usually such paths as "/lib64"
|
||||
or "/usr/lib64", and the usual RPATHs take the form of
|
||||
[$ORIGIN/../$LIB/somedir]. */
|
||||
if (__glibc_unlikely (__libc_enable_secure)
|
||||
&& !(input == start + 1
|
||||
&& (input[len] == '\0' || input[len] == '/')))
|
||||
repl = (const char *) -1;
|
||||
else
|
||||
repl = l->l_origin;
|
||||
|
||||
check_for_trusted = (__libc_enable_secure
|
||||
&& l->l_type == lt_executable);
|
||||
}
|
||||
else if ((len = is_dst (start, name, "PLATFORM", 0)) != 0)
|
||||
else if ((len = is_dst (input, "PLATFORM")) != 0)
|
||||
repl = GLRO(dl_platform);
|
||||
else if ((len = is_dst (start, name, "LIB", 0)) != 0)
|
||||
else if ((len = is_dst (input, "LIB")) != 0)
|
||||
repl = DL_DST_LIB;
|
||||
|
||||
if (repl != NULL && repl != (const char *) -1)
|
||||
{
|
||||
wp = __stpcpy (wp, repl);
|
||||
name += len;
|
||||
input += len;
|
||||
}
|
||||
else if (len > 1)
|
||||
else if (len != 0)
|
||||
{
|
||||
/* We cannot use this path element, the value of the
|
||||
replacement is unknown. */
|
||||
wp = last_elem;
|
||||
break;
|
||||
/* We found a valid DST that we know about, but we could
|
||||
not find a replacement value for it, therefore we
|
||||
cannot use this path and discard it. */
|
||||
*result = '\0';
|
||||
return result;
|
||||
}
|
||||
else
|
||||
/* No DST we recognize. */
|
||||
@@ -293,16 +338,26 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result)
|
||||
}
|
||||
else
|
||||
{
|
||||
*wp++ = *name++;
|
||||
*wp++ = *input++;
|
||||
}
|
||||
}
|
||||
while (*name != '\0');
|
||||
while (*input != '\0');
|
||||
|
||||
/* In SUID/SGID programs, after $ORIGIN expansion the normalized
|
||||
path must be rooted in one of the trusted directories. */
|
||||
path must be rooted in one of the trusted directories. The $LIB
|
||||
and $PLATFORM DST cannot in any way be manipulated by the caller
|
||||
because they are fixed values that are set by the dynamic loader
|
||||
and therefore any paths using just $LIB or $PLATFORM need not be
|
||||
checked for trust, the authors of the binaries themselves are
|
||||
trusted to have designed this correctly. Only $ORIGIN is tested in
|
||||
this way because it may be manipulated in some ways with hard
|
||||
links. */
|
||||
if (__glibc_unlikely (check_for_trusted)
|
||||
&& !is_trusted_path_normalize (last_elem, wp - last_elem))
|
||||
wp = last_elem;
|
||||
&& !is_trusted_path_normalize (result, wp - result))
|
||||
{
|
||||
*result = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
*wp = '\0';
|
||||
|
||||
@@ -310,13 +365,13 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result)
|
||||
}
|
||||
|
||||
|
||||
/* Return copy of argument with all recognized dynamic string tokens
|
||||
($ORIGIN and $PLATFORM for now) replaced. On some platforms it
|
||||
might not be possible to determine the path from which the object
|
||||
belonging to the map is loaded. In this case the path element
|
||||
containing $ORIGIN is left out. */
|
||||
/* Return a malloc allocated copy of INPUT with all recognized DSTs
|
||||
replaced. On some platforms it might not be possible to determine the
|
||||
path from which the object belonging to the map is loaded. In this
|
||||
case the path containing the DST is left out. On error NULL
|
||||
is returned. */
|
||||
static char *
|
||||
expand_dynamic_string_token (struct link_map *l, const char *s)
|
||||
expand_dynamic_string_token (struct link_map *l, const char *input)
|
||||
{
|
||||
/* We make two runs over the string. First we determine how large the
|
||||
resulting string is and then we copy it over. Since this is no
|
||||
@@ -326,22 +381,22 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
|
||||
size_t total;
|
||||
char *result;
|
||||
|
||||
/* Determine the number of DST elements. */
|
||||
cnt = DL_DST_COUNT (s);
|
||||
/* Determine the number of DSTs. */
|
||||
cnt = _dl_dst_count (input);
|
||||
|
||||
/* If we do not have to replace anything simply copy the string. */
|
||||
if (__glibc_likely (cnt == 0))
|
||||
return __strdup (s);
|
||||
return __strdup (input);
|
||||
|
||||
/* Determine the length of the substituted string. */
|
||||
total = DL_DST_REQUIRED (l, s, strlen (s), cnt);
|
||||
total = DL_DST_REQUIRED (l, input, strlen (input), cnt);
|
||||
|
||||
/* Allocate the necessary memory. */
|
||||
result = (char *) malloc (total + 1);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
return _dl_dst_substitute (l, s, result);
|
||||
return _dl_dst_substitute (l, input, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1469,6 +1524,7 @@ open_verify (const char *name, int fd,
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr, *ph;
|
||||
ElfW(Word) *abi_note;
|
||||
ElfW(Word) *abi_note_malloced = NULL;
|
||||
unsigned int osversion;
|
||||
size_t maplength;
|
||||
|
||||
@@ -1640,10 +1696,25 @@ open_verify (const char *name, int fd,
|
||||
abi_note = (void *) (fbp->buf + ph->p_offset);
|
||||
else
|
||||
{
|
||||
abi_note = alloca (size);
|
||||
/* Note: __libc_use_alloca is not usable here, because
|
||||
thread info may not have been set up yet. */
|
||||
if (size < __MAX_ALLOCA_CUTOFF)
|
||||
abi_note = alloca (size);
|
||||
else
|
||||
{
|
||||
/* There could be multiple PT_NOTEs. */
|
||||
abi_note_malloced = realloc (abi_note_malloced, size);
|
||||
if (abi_note_malloced == NULL)
|
||||
goto read_error;
|
||||
|
||||
abi_note = abi_note_malloced;
|
||||
}
|
||||
__lseek (fd, ph->p_offset, SEEK_SET);
|
||||
if (__libc_read (fd, (void *) abi_note, size) != size)
|
||||
goto read_error;
|
||||
{
|
||||
free (abi_note_malloced);
|
||||
goto read_error;
|
||||
}
|
||||
}
|
||||
|
||||
while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
|
||||
@@ -1678,6 +1749,7 @@ open_verify (const char *name, int fd,
|
||||
|
||||
break;
|
||||
}
|
||||
free (abi_note_malloced);
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
+43
-5
@@ -184,10 +184,36 @@ _dl_profile_fixup (
|
||||
/* This is the address in the array where we store the result of previous
|
||||
relocations. */
|
||||
struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
|
||||
DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
|
||||
|
||||
DL_FIXUP_VALUE_TYPE value = *resultp;
|
||||
if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0)
|
||||
/* CONCURRENCY NOTES:
|
||||
|
||||
Multiple threads may be calling the same PLT sequence and with
|
||||
LD_AUDIT enabled they will be calling into _dl_profile_fixup to
|
||||
update the reloc_result with the result of the lazy resolution.
|
||||
The reloc_result guard variable is reloc_init, and we use
|
||||
acquire/release loads and store to it to ensure that the results of
|
||||
the structure are consistent with the loaded value of the guard.
|
||||
This does not fix all of the data races that occur when two or more
|
||||
threads read reloc_result->reloc_init with a value of zero and read
|
||||
and write to that reloc_result concurrently. The expectation is
|
||||
generally that while this is a data race it works because the
|
||||
threads write the same values. Until the data races are fixed
|
||||
there is a potential for problems to arise from these data races.
|
||||
The reloc result updates should happen in parallel but there should
|
||||
be an atomic RMW which does the final update to the real result
|
||||
entry (see bug 23790).
|
||||
|
||||
The following code uses reloc_result->init set to 0 to indicate if it is
|
||||
the first time this object is being relocated, otherwise 1 which
|
||||
indicates the object has already been relocated.
|
||||
|
||||
Reading/Writing from/to reloc_result->reloc_init must not happen
|
||||
before previous writes to reloc_result complete as they could
|
||||
end-up with an incomplete struct. */
|
||||
DL_FIXUP_VALUE_TYPE value;
|
||||
unsigned int init = atomic_load_acquire (&reloc_result->init);
|
||||
|
||||
if (init == 0)
|
||||
{
|
||||
/* This is the first time we have to relocate this object. */
|
||||
const ElfW(Sym) *const symtab
|
||||
@@ -349,19 +375,31 @@ _dl_profile_fixup (
|
||||
|
||||
/* Store the result for later runs. */
|
||||
if (__glibc_likely (! GLRO(dl_bind_not)))
|
||||
*resultp = value;
|
||||
{
|
||||
reloc_result->addr = value;
|
||||
/* Guarantee all previous writes complete before
|
||||
init is updated. See CONCURRENCY NOTES earlier */
|
||||
atomic_store_release (&reloc_result->init, 1);
|
||||
}
|
||||
init = 1;
|
||||
}
|
||||
else
|
||||
value = reloc_result->addr;
|
||||
|
||||
/* By default we do not call the pltexit function. */
|
||||
long int framesize = -1;
|
||||
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: report the PLT entering and allow the
|
||||
auditors to change the value. */
|
||||
if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0
|
||||
if (GLRO(dl_naudit) > 0
|
||||
/* Don't do anything if no auditor wants to intercept this call. */
|
||||
&& (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
|
||||
{
|
||||
/* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been
|
||||
initialized earlier in this function or in another thread. */
|
||||
assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0);
|
||||
ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
|
||||
l_info[DT_SYMTAB])
|
||||
+ reloc_result->boundndx);
|
||||
|
||||
@@ -2835,6 +2835,13 @@ enum
|
||||
#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
|
||||
#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
|
||||
|
||||
/* AArch64 specific values for the Dyn d_tag field. */
|
||||
#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5)
|
||||
#define DT_AARCH64_NUM 6
|
||||
|
||||
/* AArch64 specific values for the st_other field. */
|
||||
#define STO_AARCH64_VARIANT_PCS 0x80
|
||||
|
||||
/* ARM relocs. */
|
||||
|
||||
#define R_ARM_NONE 0 /* No reloc */
|
||||
|
||||
+40
-74
@@ -23,10 +23,6 @@
|
||||
#define EW_(e, w, t) EW__(e, w, _##t)
|
||||
#define EW__(e, w, t) e##w##t
|
||||
|
||||
#define pldd_assert(name, exp) \
|
||||
typedef int __assert_##name[((exp) != 0) - 1]
|
||||
|
||||
|
||||
struct E(link_map)
|
||||
{
|
||||
EW(Addr) l_addr;
|
||||
@@ -39,12 +35,12 @@ struct E(link_map)
|
||||
EW(Addr) l_libname;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
pldd_assert (l_addr, (offsetof (struct link_map, l_addr)
|
||||
== offsetof (struct E(link_map), l_addr)));
|
||||
pldd_assert (l_name, (offsetof (struct link_map, l_name)
|
||||
== offsetof (struct E(link_map), l_name)));
|
||||
pldd_assert (l_next, (offsetof (struct link_map, l_next)
|
||||
== offsetof (struct E(link_map), l_next)));
|
||||
_Static_assert (offsetof (struct link_map, l_addr)
|
||||
== offsetof (struct E(link_map), l_addr), "l_addr");
|
||||
_Static_assert (offsetof (struct link_map, l_name)
|
||||
== offsetof (struct E(link_map), l_name), "l_name");
|
||||
_Static_assert (offsetof (struct link_map, l_next)
|
||||
== offsetof (struct E(link_map), l_next), "l_next");
|
||||
#endif
|
||||
|
||||
|
||||
@@ -54,10 +50,10 @@ struct E(libname_list)
|
||||
EW(Addr) next;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
pldd_assert (name, (offsetof (struct libname_list, name)
|
||||
== offsetof (struct E(libname_list), name)));
|
||||
pldd_assert (next, (offsetof (struct libname_list, next)
|
||||
== offsetof (struct E(libname_list), next)));
|
||||
_Static_assert (offsetof (struct libname_list, name)
|
||||
== offsetof (struct E(libname_list), name), "name");
|
||||
_Static_assert (offsetof (struct libname_list, next)
|
||||
== offsetof (struct E(libname_list), next), "next");
|
||||
#endif
|
||||
|
||||
struct E(r_debug)
|
||||
@@ -69,16 +65,17 @@ struct E(r_debug)
|
||||
EW(Addr) r_map;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
pldd_assert (r_version, (offsetof (struct r_debug, r_version)
|
||||
== offsetof (struct E(r_debug), r_version)));
|
||||
pldd_assert (r_map, (offsetof (struct r_debug, r_map)
|
||||
== offsetof (struct E(r_debug), r_map)));
|
||||
_Static_assert (offsetof (struct r_debug, r_version)
|
||||
== offsetof (struct E(r_debug), r_version), "r_version");
|
||||
_Static_assert (offsetof (struct r_debug, r_map)
|
||||
== offsetof (struct E(r_debug), r_map), "r_map");
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
|
||||
E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv,
|
||||
size_t auxv_size)
|
||||
{
|
||||
EW(Addr) phdr = 0;
|
||||
unsigned int phnum = 0;
|
||||
@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
if (phdr == 0 || phnum == 0 || phent == 0)
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
|
||||
|
||||
EW(Phdr) *p = alloca (phnum * phent);
|
||||
if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent)
|
||||
{
|
||||
error (0, 0, gettext ("cannot read program header"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
EW(Phdr) *p = xmalloc (phnum * phent);
|
||||
if (pread (memfd, p, phnum * phent, phdr) != phnum * phent)
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot read program header"));
|
||||
|
||||
/* Determine the load offset. We need this for interpreting the
|
||||
other program header entries so we do this in a separate loop.
|
||||
@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
if (p[i].p_type == PT_DYNAMIC)
|
||||
{
|
||||
EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
|
||||
if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
|
||||
if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
|
||||
!= p[i].p_filesz)
|
||||
{
|
||||
error (0, 0, gettext ("cannot read dynamic section"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section"));
|
||||
|
||||
/* Search for the DT_DEBUG entry. */
|
||||
for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
|
||||
if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
|
||||
{
|
||||
struct E(r_debug) r;
|
||||
if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
|
||||
if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
|
||||
!= sizeof (r))
|
||||
{
|
||||
error (0, 0, gettext ("cannot read r_debug"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot read r_debug"));
|
||||
|
||||
if (r.r_map != 0)
|
||||
{
|
||||
@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
}
|
||||
else if (p[i].p_type == PT_INTERP)
|
||||
{
|
||||
interp = alloca (p[i].p_filesz);
|
||||
if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
|
||||
interp = xmalloc (p[i].p_filesz);
|
||||
if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
|
||||
!= p[i].p_filesz)
|
||||
{
|
||||
error (0, 0, gettext ("cannot read program interpreter"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter"));
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
if (interp == NULL)
|
||||
{
|
||||
// XXX check whether the executable itself is the loader
|
||||
return EXIT_FAILURE;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// XXX perhaps try finding ld.so and _r_debug in it
|
||||
|
||||
return EXIT_FAILURE;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free (p);
|
||||
free (interp);
|
||||
|
||||
/* Print the PID and program name first. */
|
||||
printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
|
||||
|
||||
@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
do
|
||||
{
|
||||
struct E(link_map) m;
|
||||
if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m))
|
||||
{
|
||||
error (0, 0, gettext ("cannot read link map"));
|
||||
status = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
if (pread (memfd, &m, sizeof (m), list) != sizeof (m))
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot read link map"));
|
||||
|
||||
EW(Addr) name_offset = m.l_name;
|
||||
again:
|
||||
while (1)
|
||||
{
|
||||
ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
|
||||
ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset);
|
||||
if (n == -1)
|
||||
{
|
||||
error (0, 0, gettext ("cannot read object name"));
|
||||
status = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
error (EXIT_FAILURE, 0, gettext ("cannot read object name"));
|
||||
|
||||
if (memchr (tmpbuf.data, '\0', n) != NULL)
|
||||
break;
|
||||
|
||||
if (!scratch_buffer_grow (&tmpbuf))
|
||||
{
|
||||
error (0, 0, gettext ("cannot allocate buffer for object name"));
|
||||
status = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
error (EXIT_FAILURE, 0,
|
||||
gettext ("cannot allocate buffer for object name"));
|
||||
}
|
||||
|
||||
if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name
|
||||
&& m.l_libname != 0)
|
||||
{
|
||||
/* Try the l_libname element. */
|
||||
struct E(libname_list) ln;
|
||||
if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
|
||||
{
|
||||
name_offset = ln.name;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
/* The m.l_name and m.l_libname.name for loader linkmap points to same
|
||||
values (since BZ#387 fix). Trying to use l_libname name as the
|
||||
shared object name might lead to an infinite loop (BZ#18035). */
|
||||
|
||||
/* Skip over the executable. */
|
||||
if (((char *)tmpbuf.data)[0] != '\0')
|
||||
@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
|
||||
}
|
||||
while (list != 0);
|
||||
|
||||
out:
|
||||
scratch_buffer_free (&tmpbuf);
|
||||
return status;
|
||||
}
|
||||
|
||||
+30
-34
@@ -17,23 +17,17 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <alloca.h>
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <argp.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <link.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <scratch_buffer.h>
|
||||
|
||||
@@ -76,14 +70,9 @@ static struct argp argp =
|
||||
options, parse_opt, args_doc, doc, NULL, more_help, NULL
|
||||
};
|
||||
|
||||
// File descriptor of /proc/*/mem file.
|
||||
static int memfd;
|
||||
|
||||
/* Name of the executable */
|
||||
static char *exe;
|
||||
|
||||
/* Local functions. */
|
||||
static int get_process_info (int dfd, long int pid);
|
||||
static int get_process_info (const char *exe, int dfd, long int pid);
|
||||
static void wait_for_ptrace_stop (long int pid);
|
||||
|
||||
|
||||
@@ -102,8 +91,10 @@ main (int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert (sizeof (pid_t) == sizeof (int)
|
||||
|| sizeof (pid_t) == sizeof (long int));
|
||||
_Static_assert (sizeof (pid_t) == sizeof (int)
|
||||
|| sizeof (pid_t) == sizeof (long int),
|
||||
"sizeof (pid_t) != sizeof (int) or sizeof (long int)");
|
||||
|
||||
char *endp;
|
||||
errno = 0;
|
||||
long int pid = strtol (argv[remaining], &endp, 10);
|
||||
@@ -119,25 +110,24 @@ main (int argc, char *argv[])
|
||||
if (dfd == -1)
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
|
||||
|
||||
struct scratch_buffer exebuf;
|
||||
scratch_buffer_init (&exebuf);
|
||||
/* Name of the executable */
|
||||
struct scratch_buffer exe;
|
||||
scratch_buffer_init (&exe);
|
||||
ssize_t nexe;
|
||||
while ((nexe = readlinkat (dfd, "exe",
|
||||
exebuf.data, exebuf.length)) == exebuf.length)
|
||||
exe.data, exe.length)) == exe.length)
|
||||
{
|
||||
if (!scratch_buffer_grow (&exebuf))
|
||||
if (!scratch_buffer_grow (&exe))
|
||||
{
|
||||
nexe = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nexe == -1)
|
||||
exe = (char *) "<program name undetermined>";
|
||||
/* Default stack allocation is at least 1024. */
|
||||
snprintf (exe.data, exe.length, "<program name undetermined>");
|
||||
else
|
||||
{
|
||||
exe = exebuf.data;
|
||||
exe[nexe] = '\0';
|
||||
}
|
||||
((char*)exe.data)[nexe] = '\0';
|
||||
|
||||
/* Stop all threads since otherwise the list of loaded modules might
|
||||
change while we are reading it. */
|
||||
@@ -155,8 +145,8 @@ main (int argc, char *argv[])
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
|
||||
buf);
|
||||
|
||||
struct dirent64 *d;
|
||||
while ((d = readdir64 (dir)) != NULL)
|
||||
struct dirent *d;
|
||||
while ((d = readdir (dir)) != NULL)
|
||||
{
|
||||
if (! isdigit (d->d_name[0]))
|
||||
continue;
|
||||
@@ -182,7 +172,7 @@ main (int argc, char *argv[])
|
||||
|
||||
wait_for_ptrace_stop (tid);
|
||||
|
||||
struct thread_list *newp = alloca (sizeof (*newp));
|
||||
struct thread_list *newp = xmalloc (sizeof (*newp));
|
||||
newp->tid = tid;
|
||||
newp->next = thread_list;
|
||||
thread_list = newp;
|
||||
@@ -190,17 +180,22 @@ main (int argc, char *argv[])
|
||||
|
||||
closedir (dir);
|
||||
|
||||
int status = get_process_info (dfd, pid);
|
||||
if (thread_list == NULL)
|
||||
error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf);
|
||||
|
||||
int status = get_process_info (exe.data, dfd, pid);
|
||||
|
||||
assert (thread_list != NULL);
|
||||
do
|
||||
{
|
||||
ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
|
||||
struct thread_list *prev = thread_list;
|
||||
thread_list = thread_list->next;
|
||||
free (prev);
|
||||
}
|
||||
while (thread_list != NULL);
|
||||
|
||||
close (dfd);
|
||||
scratch_buffer_free (&exe);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
|
||||
|
||||
|
||||
static int
|
||||
get_process_info (int dfd, long int pid)
|
||||
get_process_info (const char *exe, int dfd, long int pid)
|
||||
{
|
||||
memfd = openat (dfd, "mem", O_RDONLY);
|
||||
/* File descriptor of /proc/<pid>/mem file. */
|
||||
int memfd = openat (dfd, "mem", O_RDONLY);
|
||||
if (memfd == -1)
|
||||
goto no_info;
|
||||
|
||||
@@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid)
|
||||
|
||||
int retval;
|
||||
if (e_ident[EI_CLASS] == ELFCLASS32)
|
||||
retval = find_maps32 (pid, auxv, auxv_size);
|
||||
retval = find_maps32 (exe, memfd, pid, auxv, auxv_size);
|
||||
else
|
||||
retval = find_maps64 (pid, auxv, auxv_size);
|
||||
retval = find_maps64 (exe, memfd, pid, auxv, auxv_size);
|
||||
|
||||
free (auxv);
|
||||
close (memfd);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify()
|
||||
Copyright (C) 2018 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 creates a .so with 8MiB PT_NOTE segment.
|
||||
On a typical Linux system with 8MiB "ulimit -s", that was enough
|
||||
to trigger stack overflow in open_verify. */
|
||||
|
||||
.pushsection .note.big,"a"
|
||||
.balign 4
|
||||
.fill 8*1024*1024, 1, 0
|
||||
.popsection
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Test the fallback implementation of copy_file_range.
|
||||
Copyright (C) 2017-2018 Free Software Foundation, Inc.
|
||||
/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify()
|
||||
Copyright (C) 2018 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
|
||||
@@ -16,15 +16,11 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Get the declaration of the official copy_of_range function. */
|
||||
#include <unistd.h>
|
||||
/* This file must be run from within a directory called "elf". */
|
||||
|
||||
/* Compile a local version of copy_file_range. */
|
||||
#define COPY_FILE_RANGE_DECL static
|
||||
#define COPY_FILE_RANGE copy_file_range_compat
|
||||
#include <io/copy_file_range-compat.c>
|
||||
|
||||
/* Re-use the test, but run it against copy_file_range_compat defined
|
||||
above. */
|
||||
#define copy_file_range copy_file_range_compat
|
||||
#include "tst-copy_file_range.c"
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
/* Nothing to do here: merely linking against tst-big-note-lib.so triggers
|
||||
the bug. */
|
||||
return 0;
|
||||
}
|
||||
+16
-2
@@ -26,7 +26,7 @@ headers = iconv.h gconv.h
|
||||
routines = iconv_open iconv iconv_close \
|
||||
gconv_open gconv gconv_close gconv_db gconv_conf \
|
||||
gconv_builtin gconv_simple gconv_trans gconv_cache
|
||||
routines += gconv_dl
|
||||
routines += gconv_dl gconv_charset
|
||||
|
||||
vpath %.c ../locale/programs ../intl
|
||||
|
||||
@@ -43,7 +43,8 @@ CFLAGS-charmap.c += -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \
|
||||
CFLAGS-linereader.c += -DNO_TRANSLITERATION
|
||||
CFLAGS-simple-hash.c += -I../locale
|
||||
|
||||
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6
|
||||
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \
|
||||
tst-iconv7 tst-iconv8 tst-iconv-opt
|
||||
|
||||
others = iconv_prog iconvconfig
|
||||
install-others-programs = $(inst_bindir)/iconv
|
||||
@@ -60,6 +61,7 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
xtests-special += $(objpfx)test-iconvconfig.out
|
||||
tests-special += $(objpfx)tst-iconv_prog.out
|
||||
endif
|
||||
|
||||
# Make a copy of the file because gconv module names are constructed
|
||||
@@ -78,6 +80,13 @@ endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
LOCALES := en_US.UTF-8
|
||||
include ../gen-locales.mk
|
||||
|
||||
$(objpfx)tst-iconv-opt.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
$(inst_bindir)/iconv: $(objpfx)iconv_prog $(+force)
|
||||
$(do-install-program)
|
||||
|
||||
@@ -92,3 +101,8 @@ $(objpfx)test-iconvconfig.out: /dev/null $(objpfx)iconvconfig
|
||||
cmp $$tmp $(inst_gconvdir)/gconv-modules.cache; \
|
||||
rm -f $$tmp) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
|
||||
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
|
||||
'$(run-program-env)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
@@ -7,6 +7,9 @@ libc {
|
||||
# functions shared with iconv program
|
||||
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
|
||||
|
||||
# functions used elsewhere in glibc
|
||||
__gconv_open; __gconv_create_spec; __gconv_destroy_spec;
|
||||
|
||||
# function used by the gconv modules
|
||||
__gconv_transliterate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/* Charset name normalization.
|
||||
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/>. */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "gconv_int.h"
|
||||
#include "gconv_charset.h"
|
||||
|
||||
|
||||
/* This function returns a pointer to the last suffix in a conversion code
|
||||
string. Valid suffixes matched by this function are of the form: '/' or ','
|
||||
followed by arbitrary text that doesn't contain '/' or ','. It does not
|
||||
edit the string in any way. The caller is expected to parse the suffix and
|
||||
remove it (by e.g. truncating the string) before the next call. */
|
||||
static char *
|
||||
find_suffix (char *s)
|
||||
{
|
||||
/* The conversion code is in the form of a triplet, separated by '/' chars.
|
||||
The third component of the triplet contains suffixes. If we don't have two
|
||||
slashes, we don't have a suffix. */
|
||||
|
||||
int slash_count = 0;
|
||||
char *suffix_term = NULL;
|
||||
|
||||
for (int i = 0; s[i] != '\0'; i++)
|
||||
switch (s[i])
|
||||
{
|
||||
case '/':
|
||||
slash_count++;
|
||||
/* Fallthrough */
|
||||
case ',':
|
||||
suffix_term = &s[i];
|
||||
}
|
||||
|
||||
if (slash_count >= 2)
|
||||
return suffix_term;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct gconv_parsed_code
|
||||
{
|
||||
char *code;
|
||||
bool translit;
|
||||
bool ignore;
|
||||
};
|
||||
|
||||
|
||||
/* This function parses an iconv_open encoding PC.CODE, strips any suffixes
|
||||
(such as TRANSLIT or IGNORE) from it and sets corresponding flags in it. */
|
||||
static void
|
||||
gconv_parse_code (struct gconv_parsed_code *pc)
|
||||
{
|
||||
pc->translit = false;
|
||||
pc->ignore = false;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* First drop any trailing whitespaces and separators. */
|
||||
size_t len = strlen (pc->code);
|
||||
while ((len > 0)
|
||||
&& (isspace (pc->code[len - 1])
|
||||
|| pc->code[len - 1] == ','
|
||||
|| pc->code[len - 1] == '/'))
|
||||
len--;
|
||||
|
||||
pc->code[len] = '\0';
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
char * suffix = find_suffix (pc->code);
|
||||
if (suffix == NULL)
|
||||
{
|
||||
/* At this point, we have processed and removed all suffixes from the
|
||||
code and what remains of the code is suffix free. */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A suffix is processed from the end of the code array going
|
||||
backwards, one suffix at a time. The suffix is an index into the
|
||||
code character array and points to: one past the end of the code
|
||||
and any unprocessed suffixes, and to the beginning of the suffix
|
||||
currently being processed during this iteration. We must process
|
||||
this suffix and then drop it from the code by terminating the
|
||||
preceding text with NULL.
|
||||
|
||||
We want to allow and recognize suffixes such as:
|
||||
|
||||
"/TRANSLIT" i.e. single suffix
|
||||
"//TRANSLIT" i.e. single suffix and multiple separators
|
||||
"//TRANSLIT/IGNORE" i.e. suffixes separated by "/"
|
||||
"/TRANSLIT//IGNORE" i.e. suffixes separated by "//"
|
||||
"//IGNORE,TRANSLIT" i.e. suffixes separated by ","
|
||||
"//IGNORE," i.e. trailing ","
|
||||
"//TRANSLIT/" i.e. trailing "/"
|
||||
"//TRANSLIT//" i.e. trailing "//"
|
||||
"/" i.e. empty suffix.
|
||||
|
||||
Unknown suffixes are silently discarded and ignored. */
|
||||
|
||||
if ((__strcasecmp_l (suffix,
|
||||
GCONV_TRIPLE_SEPARATOR
|
||||
GCONV_TRANSLIT_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0)
|
||||
|| (__strcasecmp_l (suffix,
|
||||
GCONV_SUFFIX_SEPARATOR
|
||||
GCONV_TRANSLIT_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0))
|
||||
pc->translit = true;
|
||||
|
||||
if ((__strcasecmp_l (suffix,
|
||||
GCONV_TRIPLE_SEPARATOR
|
||||
GCONV_IGNORE_ERRORS_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0)
|
||||
|| (__strcasecmp_l (suffix,
|
||||
GCONV_SUFFIX_SEPARATOR
|
||||
GCONV_IGNORE_ERRORS_SUFFIX,
|
||||
_nl_C_locobj_ptr) == 0))
|
||||
pc->ignore = true;
|
||||
|
||||
/* We just processed this suffix. We can now drop it from the
|
||||
code string by truncating it at the suffix's position. */
|
||||
suffix[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This function accepts the charset names of the source and destination of the
|
||||
conversion and populates *conv_spec with an equivalent conversion
|
||||
specification that may later be used by __gconv_open. The charset names
|
||||
might contain options in the form of suffixes that alter the conversion,
|
||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||
and truncating any suffix options in fromcode, and processing and truncating
|
||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||
NULL upon failure. conv_spec must be allocated and freed by the caller. */
|
||||
struct gconv_spec *
|
||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||
const char *tocode)
|
||||
{
|
||||
struct gconv_parsed_code pfc, ptc;
|
||||
struct gconv_spec *ret = NULL;
|
||||
|
||||
pfc.code = __strdup (fromcode);
|
||||
ptc.code = __strdup (tocode);
|
||||
|
||||
if ((pfc.code == NULL)
|
||||
|| (ptc.code == NULL))
|
||||
goto out;
|
||||
|
||||
gconv_parse_code (&pfc);
|
||||
gconv_parse_code (&ptc);
|
||||
|
||||
/* We ignore suffixes in the fromcode because that is how the current
|
||||
implementation has always handled them. Only suffixes in the tocode are
|
||||
processed and handled. The reality is that invalid input in the input
|
||||
character set should only be ignored if the fromcode specifies IGNORE.
|
||||
The current implementation ignores invalid intput in the input character
|
||||
set if the tocode contains IGNORE. We preserve this behavior for
|
||||
backwards compatibility. In the future we may split the handling of
|
||||
IGNORE to allow a finer grained specification of ignorning invalid input
|
||||
and/or ignoring invalid output. */
|
||||
conv_spec->translit = ptc.translit;
|
||||
conv_spec->ignore = ptc.ignore;
|
||||
|
||||
/* 3 extra bytes because 1 extra for '\0', and 2 extra so strip might
|
||||
be able to add one or two trailing '/' characters if necessary. */
|
||||
conv_spec->fromcode = malloc (strlen (fromcode) + 3);
|
||||
if (conv_spec->fromcode == NULL)
|
||||
goto out;
|
||||
|
||||
conv_spec->tocode = malloc (strlen (tocode) + 3);
|
||||
if (conv_spec->tocode == NULL)
|
||||
{
|
||||
free (conv_spec->fromcode);
|
||||
conv_spec->fromcode = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Strip unrecognized characters and ensure that the code has two '/'
|
||||
characters as per conversion code triplet specification. */
|
||||
strip (conv_spec->fromcode, pfc.code);
|
||||
strip (conv_spec->tocode, ptc.code);
|
||||
ret = conv_spec;
|
||||
|
||||
out:
|
||||
free (pfc.code);
|
||||
free (ptc.code);
|
||||
|
||||
return ret;
|
||||
}
|
||||
libc_hidden_def (__gconv_create_spec)
|
||||
|
||||
|
||||
void
|
||||
__gconv_destroy_spec (struct gconv_spec *conv_spec)
|
||||
{
|
||||
free (conv_spec->fromcode);
|
||||
free (conv_spec->tocode);
|
||||
return;
|
||||
}
|
||||
libc_hidden_def (__gconv_destroy_spec)
|
||||
+33
-1
@@ -19,9 +19,41 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include "gconv_int.h"
|
||||
|
||||
|
||||
static void
|
||||
/* An iconv encoding is in the form of a triplet, with parts separated by
|
||||
a '/' character. The first part is the standard name, the second part is
|
||||
the character set, and the third part is the error handler. If the first
|
||||
part is sufficient to identify both the standard and the character set
|
||||
then the second part can be empty e.g. UTF-8//. If the first part is not
|
||||
sufficient to identify both the standard and the character set then the
|
||||
second part is required e.g. ISO-10646/UTF8/. If neither the first or
|
||||
second parts are provided e.g. //, then the current locale is used.
|
||||
The actual values used in the first and second parts are not entirely
|
||||
relevant to the implementation. The values themselves are used in a hash
|
||||
table to lookup modules and so the naming convention of the first two parts
|
||||
is somewhat arbitrary and only helps locate the entries in the cache.
|
||||
The third part is the error handler and is comprised of a ',' or '/'
|
||||
separated list of suffixes. Currently, we support "TRANSLIT" for
|
||||
transliteration and "IGNORE" for ignoring conversion errors due to
|
||||
unrecognized input characters. */
|
||||
#define GCONV_TRIPLE_SEPARATOR "/"
|
||||
#define GCONV_SUFFIX_SEPARATOR ","
|
||||
#define GCONV_TRANSLIT_SUFFIX "TRANSLIT"
|
||||
#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
|
||||
|
||||
|
||||
/* This function copies in-order, characters from the source 's' that are
|
||||
either alpha-numeric or one in one of these: "_-.,:/" - into the destination
|
||||
'wp' while dropping all other characters. In the process, it converts all
|
||||
alphabetical characters to upper case. It then appends up to two '/'
|
||||
characters so that the total number of '/'es in the destination is 2. */
|
||||
static inline void __attribute__ ((unused, always_inline))
|
||||
strip (char *wp, const char *s)
|
||||
{
|
||||
int slash_count = 0;
|
||||
|
||||
+36
-4
@@ -92,6 +92,15 @@ struct gconv_module
|
||||
};
|
||||
|
||||
|
||||
/* The specification of the conversion that needs to be performed. */
|
||||
struct gconv_spec
|
||||
{
|
||||
char *fromcode;
|
||||
char *tocode;
|
||||
bool translit;
|
||||
bool ignore;
|
||||
};
|
||||
|
||||
/* Flags for `gconv_open'. */
|
||||
enum
|
||||
{
|
||||
@@ -154,10 +163,33 @@ __libc_lock_define (extern, __gconv_lock attribute_hidden)
|
||||
})
|
||||
|
||||
|
||||
/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */
|
||||
extern int __gconv_open (const char *toset, const char *fromset,
|
||||
__gconv_t *handle, int flags)
|
||||
attribute_hidden;
|
||||
/* Return in *HANDLE, a decriptor for the transformation. The function expects
|
||||
the specification of the transformation in the structure pointed to by
|
||||
CONV_SPEC. It only reads *CONV_SPEC and does not take ownership of it. */
|
||||
extern int __gconv_open (struct gconv_spec *conv_spec,
|
||||
__gconv_t *handle, int flags);
|
||||
libc_hidden_proto (__gconv_open)
|
||||
|
||||
/* This function accepts the charset names of the source and destination of the
|
||||
conversion and populates *conv_spec with an equivalent conversion
|
||||
specification that may later be used by __gconv_open. The charset names
|
||||
might contain options in the form of suffixes that alter the conversion,
|
||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||
and truncating any suffix options in fromcode, and processing and truncating
|
||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||
NULL upon failure. */
|
||||
extern struct gconv_spec *
|
||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||
const char *tocode);
|
||||
libc_hidden_proto (__gconv_create_spec)
|
||||
|
||||
/* This function frees all heap memory allocated by __gconv_create_spec. */
|
||||
extern void
|
||||
__gconv_destroy_spec (struct gconv_spec *conv_spec);
|
||||
libc_hidden_proto (__gconv_destroy_spec)
|
||||
|
||||
/* Free resources associated with transformation descriptor CD. */
|
||||
extern int __gconv_close (__gconv_t cd)
|
||||
|
||||
+13
-51
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
int
|
||||
__gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
|
||||
__gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle,
|
||||
int flags)
|
||||
{
|
||||
struct __gconv_step *steps;
|
||||
@@ -36,77 +36,38 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
|
||||
size_t cnt = 0;
|
||||
int res;
|
||||
int conv_flags = 0;
|
||||
const char *errhand;
|
||||
const char *ignore;
|
||||
bool translit = false;
|
||||
char *tocode, *fromcode;
|
||||
|
||||
/* Find out whether any error handling method is specified. */
|
||||
errhand = strchr (toset, '/');
|
||||
if (errhand != NULL)
|
||||
errhand = strchr (errhand + 1, '/');
|
||||
if (__glibc_likely (errhand != NULL))
|
||||
{
|
||||
if (*++errhand == '\0')
|
||||
errhand = NULL;
|
||||
else
|
||||
{
|
||||
/* Make copy without the error handling description. */
|
||||
char *newtoset = (char *) alloca (errhand - toset + 1);
|
||||
char *tok;
|
||||
char *ptr = NULL /* Work around a bogus warning */;
|
||||
translit = conv_spec->translit;
|
||||
|
||||
newtoset[errhand - toset] = '\0';
|
||||
toset = memcpy (newtoset, toset, errhand - toset);
|
||||
if (conv_spec->ignore)
|
||||
conv_flags |= __GCONV_IGNORE_ERRORS;
|
||||
|
||||
/* Find the appropriate transliteration handlers. */
|
||||
tok = strdupa (errhand);
|
||||
|
||||
tok = __strtok_r (tok, ",", &ptr);
|
||||
while (tok != NULL)
|
||||
{
|
||||
if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0)
|
||||
translit = true;
|
||||
else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0)
|
||||
/* Set the flag to ignore all errors. */
|
||||
conv_flags |= __GCONV_IGNORE_ERRORS;
|
||||
|
||||
tok = __strtok_r (NULL, ",", &ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For the source character set we ignore the error handler specification.
|
||||
XXX Is this really always the best? */
|
||||
ignore = strchr (fromset, '/');
|
||||
if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL
|
||||
&& *++ignore != '\0')
|
||||
{
|
||||
char *newfromset = (char *) alloca (ignore - fromset + 1);
|
||||
|
||||
newfromset[ignore - fromset] = '\0';
|
||||
fromset = memcpy (newfromset, fromset, ignore - fromset);
|
||||
}
|
||||
tocode = conv_spec->tocode;
|
||||
fromcode = conv_spec->fromcode;
|
||||
|
||||
/* If the string is empty define this to mean the charset of the
|
||||
currently selected locale. */
|
||||
if (strcmp (toset, "//") == 0)
|
||||
if (strcmp (tocode, "//") == 0)
|
||||
{
|
||||
const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
|
||||
size_t len = strlen (codeset);
|
||||
char *dest;
|
||||
toset = dest = (char *) alloca (len + 3);
|
||||
tocode = dest = (char *) alloca (len + 3);
|
||||
memcpy (__mempcpy (dest, codeset, len), "//", 3);
|
||||
}
|
||||
if (strcmp (fromset, "//") == 0)
|
||||
if (strcmp (fromcode, "//") == 0)
|
||||
{
|
||||
const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
|
||||
size_t len = strlen (codeset);
|
||||
char *dest;
|
||||
fromset = dest = (char *) alloca (len + 3);
|
||||
fromcode = dest = (char *) alloca (len + 3);
|
||||
memcpy (__mempcpy (dest, codeset, len), "//", 3);
|
||||
}
|
||||
|
||||
res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags);
|
||||
res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags);
|
||||
if (res == __GCONV_OK)
|
||||
{
|
||||
/* Allocate room for handle. */
|
||||
@@ -205,3 +166,4 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
|
||||
*handle = result;
|
||||
return res;
|
||||
}
|
||||
libc_hidden_def (__gconv_open)
|
||||
|
||||
+24
-24
@@ -76,7 +76,7 @@ __attribute ((always_inline))
|
||||
internal_ucs4_loop (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp, const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp, const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
const unsigned char *inptr = *inptrp;
|
||||
@@ -120,7 +120,8 @@ internal_ucs4_loop_unaligned (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
const unsigned char *inptr = *inptrp;
|
||||
@@ -169,7 +170,8 @@ internal_ucs4_loop_single (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
mbstate_t *state = step_data->__statep;
|
||||
@@ -231,17 +233,15 @@ __attribute ((always_inline))
|
||||
ucs4_internal_loop (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp, const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp, const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -298,17 +298,16 @@ ucs4_internal_loop_unaligned (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
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))
|
||||
{
|
||||
@@ -368,7 +367,8 @@ ucs4_internal_loop_single (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
mbstate_t *state = step_data->__statep;
|
||||
@@ -443,7 +443,7 @@ __attribute ((always_inline))
|
||||
internal_ucs4le_loop (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp, const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp, const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
const unsigned char *inptr = *inptrp;
|
||||
@@ -488,7 +488,8 @@ internal_ucs4le_loop_unaligned (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
const unsigned char *inptr = *inptrp;
|
||||
@@ -540,7 +541,8 @@ internal_ucs4le_loop_single (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
mbstate_t *state = step_data->__statep;
|
||||
@@ -601,17 +603,15 @@ __attribute ((always_inline))
|
||||
ucs4le_internal_loop (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp, const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp, const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -671,17 +671,16 @@ ucs4le_internal_loop_unaligned (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
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))
|
||||
{
|
||||
@@ -745,7 +744,8 @@ ucs4le_internal_loop_single (struct __gconv_step *step,
|
||||
struct __gconv_step_data *step_data,
|
||||
const unsigned char **inptrp,
|
||||
const unsigned char *inend,
|
||||
unsigned char **outptrp, unsigned char *outend,
|
||||
unsigned char **outptrp,
|
||||
const unsigned char *outend,
|
||||
size_t *irreversible)
|
||||
{
|
||||
mbstate_t *state = step_data->__statep;
|
||||
|
||||
+7
-41
@@ -31,49 +31,15 @@
|
||||
iconv_t
|
||||
iconv_open (const char *tocode, const char *fromcode)
|
||||
{
|
||||
/* Normalize the name. We remove all characters beside alpha-numeric,
|
||||
'_', '-', '/', '.', and ':'. */
|
||||
size_t tocode_len = strlen (tocode) + 3;
|
||||
char *tocode_conv;
|
||||
bool tocode_usealloca = __libc_use_alloca (tocode_len);
|
||||
if (tocode_usealloca)
|
||||
tocode_conv = (char *) alloca (tocode_len);
|
||||
else
|
||||
{
|
||||
tocode_conv = (char *) malloc (tocode_len);
|
||||
if (tocode_conv == NULL)
|
||||
return (iconv_t) -1;
|
||||
}
|
||||
strip (tocode_conv, tocode);
|
||||
tocode = (tocode_conv[2] == '\0' && tocode[0] != '\0'
|
||||
? upstr (tocode_conv, tocode) : tocode_conv);
|
||||
|
||||
size_t fromcode_len = strlen (fromcode) + 3;
|
||||
char *fromcode_conv;
|
||||
bool fromcode_usealloca = __libc_use_alloca (fromcode_len);
|
||||
if (fromcode_usealloca)
|
||||
fromcode_conv = (char *) alloca (fromcode_len);
|
||||
else
|
||||
{
|
||||
fromcode_conv = (char *) malloc (fromcode_len);
|
||||
if (fromcode_conv == NULL)
|
||||
{
|
||||
if (! tocode_usealloca)
|
||||
free (tocode_conv);
|
||||
return (iconv_t) -1;
|
||||
}
|
||||
}
|
||||
strip (fromcode_conv, fromcode);
|
||||
fromcode = (fromcode_conv[2] == '\0' && fromcode[0] != '\0'
|
||||
? upstr (fromcode_conv, fromcode) : fromcode_conv);
|
||||
|
||||
__gconv_t cd;
|
||||
int res = __gconv_open (tocode, fromcode, &cd, 0);
|
||||
struct gconv_spec conv_spec;
|
||||
|
||||
if (! fromcode_usealloca)
|
||||
free (fromcode_conv);
|
||||
if (! tocode_usealloca)
|
||||
free (tocode_conv);
|
||||
if (__gconv_create_spec (&conv_spec, fromcode, tocode) == NULL)
|
||||
return (iconv_t) -1;
|
||||
|
||||
int res = __gconv_open (&conv_spec, &cd, 0);
|
||||
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
|
||||
{
|
||||
|
||||
+23
-40
@@ -39,6 +39,7 @@
|
||||
#include <gconv_int.h>
|
||||
#include "iconv_prog.h"
|
||||
#include "iconvconfig.h"
|
||||
#include "gconv_charset.h"
|
||||
|
||||
/* Get libc version number. */
|
||||
#include "../version.h"
|
||||
@@ -118,8 +119,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int status = EXIT_SUCCESS;
|
||||
int remaining;
|
||||
iconv_t cd;
|
||||
const char *orig_to_code;
|
||||
__gconv_t cd;
|
||||
struct charmap_t *from_charmap = NULL;
|
||||
struct charmap_t *to_charmap = NULL;
|
||||
|
||||
@@ -139,39 +139,6 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* If we have to ignore errors make sure we use the appropriate name for
|
||||
the to-character-set. */
|
||||
orig_to_code = to_code;
|
||||
if (omit_invalid)
|
||||
{
|
||||
const char *errhand = strchrnul (to_code, '/');
|
||||
int nslash = 2;
|
||||
char *newp;
|
||||
char *cp;
|
||||
|
||||
if (*errhand == '/')
|
||||
{
|
||||
--nslash;
|
||||
errhand = strchrnul (errhand + 1, '/');
|
||||
|
||||
if (*errhand == '/')
|
||||
{
|
||||
--nslash;
|
||||
errhand = strchr (errhand, '\0');
|
||||
}
|
||||
}
|
||||
|
||||
newp = (char *) alloca (errhand - to_code + nslash + 7 + 1);
|
||||
cp = mempcpy (newp, to_code, errhand - to_code);
|
||||
while (nslash-- > 0)
|
||||
*cp++ = '/';
|
||||
if (cp[-1] != '/')
|
||||
*cp++ = ',';
|
||||
memcpy (cp, "IGNORE", sizeof ("IGNORE"));
|
||||
|
||||
to_code = newp;
|
||||
}
|
||||
|
||||
/* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f
|
||||
can be file names of charmaps. In this case iconv will have to read
|
||||
those charmaps and use them to do the conversion. But there are
|
||||
@@ -184,10 +151,10 @@ main (int argc, char *argv[])
|
||||
file. */
|
||||
from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0, 0);
|
||||
|
||||
if (strchr (orig_to_code, '/') != NULL)
|
||||
if (strchr (to_code, '/') != NULL)
|
||||
/* The to-name might be a charmap file name. Try reading the
|
||||
file. */
|
||||
to_charmap = charmap_read (orig_to_code, /*0, 1,*/1, 0, 0, 0);
|
||||
to_charmap = charmap_read (to_code, /*0, 1,*/1, 0, 0, 0);
|
||||
|
||||
|
||||
/* At this point we have to handle two cases. The first one is
|
||||
@@ -201,9 +168,25 @@ main (int argc, char *argv[])
|
||||
argc, remaining, argv, output_file);
|
||||
else
|
||||
{
|
||||
struct gconv_spec conv_spec;
|
||||
int res;
|
||||
|
||||
if (__gconv_create_spec (&conv_spec, from_code, to_code) == NULL)
|
||||
{
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to start conversion processing"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (omit_invalid)
|
||||
conv_spec.ignore = true;
|
||||
|
||||
/* Let's see whether we have these coded character sets. */
|
||||
cd = iconv_open (to_code, from_code);
|
||||
if (cd == (iconv_t) -1)
|
||||
res = __gconv_open (&conv_spec, &cd, 0);
|
||||
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (res != __GCONV_OK)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
{
|
||||
@@ -221,7 +204,7 @@ main (int argc, char *argv[])
|
||||
const char *from_pretty =
|
||||
(from_code[0] ? from_code : nl_langinfo (CODESET));
|
||||
const char *to_pretty =
|
||||
(orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
|
||||
(to_code[0] ? to_code : nl_langinfo (CODESET));
|
||||
|
||||
if (from_wrong)
|
||||
{
|
||||
|
||||
+28
-7
@@ -83,6 +83,11 @@
|
||||
RESET_INPUT_BUFFER If the input character sets allow this the macro
|
||||
can be defined to reset the input buffer pointers
|
||||
to cover only those characters up to the error.
|
||||
Note that if the conversion has skipped over
|
||||
irreversible characters (due to
|
||||
__GCONV_IGNORE_ERRORS) there is no longer a direct
|
||||
correspondence between input and output pointers,
|
||||
and this macro is not called.
|
||||
|
||||
FUNCTION_NAME if not set the conversion function is named `gconv'.
|
||||
|
||||
@@ -597,6 +602,12 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
inptr = *inptrp;
|
||||
/* The outbuf buffer is empty. */
|
||||
outstart = outbuf;
|
||||
#ifdef RESET_INPUT_BUFFER
|
||||
/* Remember how many irreversible characters were skipped before
|
||||
this round. */
|
||||
size_t loop_irreversible
|
||||
= lirreversible + (irreversible ? *irreversible : 0);
|
||||
#endif
|
||||
|
||||
#ifdef SAVE_RESET_STATE
|
||||
SAVE_RESET_STATE (1);
|
||||
@@ -671,8 +682,16 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
if (__glibc_unlikely (outerr != outbuf))
|
||||
{
|
||||
#ifdef RESET_INPUT_BUFFER
|
||||
RESET_INPUT_BUFFER;
|
||||
#else
|
||||
/* RESET_INPUT_BUFFER can only work when there were
|
||||
no new irreversible characters skipped during
|
||||
this round. */
|
||||
if (loop_irreversible
|
||||
== lirreversible + (irreversible ? *irreversible : 0))
|
||||
{
|
||||
RESET_INPUT_BUFFER;
|
||||
goto done_reset;
|
||||
}
|
||||
#endif
|
||||
/* We have a problem in one of the functions below.
|
||||
Undo the conversion upto the error point. */
|
||||
size_t nstatus __attribute__ ((unused));
|
||||
@@ -682,9 +701,9 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
outbuf = outstart;
|
||||
|
||||
/* Restore the state. */
|
||||
# ifdef SAVE_RESET_STATE
|
||||
#ifdef SAVE_RESET_STATE
|
||||
SAVE_RESET_STATE (0);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (__glibc_likely (!unaligned))
|
||||
{
|
||||
@@ -701,7 +720,7 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
lirreversiblep
|
||||
EXTRA_LOOP_ARGS);
|
||||
}
|
||||
# if POSSIBLY_UNALIGNED
|
||||
#if POSSIBLY_UNALIGNED
|
||||
else
|
||||
{
|
||||
if (FROM_DIRECTION)
|
||||
@@ -720,7 +739,7 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
lirreversiblep
|
||||
EXTRA_LOOP_ARGS);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* We must run out of output buffer space in this
|
||||
rerun. */
|
||||
@@ -731,9 +750,11 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
|
||||
the invocation counter. */
|
||||
if (__glibc_unlikely (outbuf == outstart))
|
||||
--data->__invocation_counter;
|
||||
#endif /* reset input buffer */
|
||||
}
|
||||
|
||||
#ifdef RESET_INPUT_BUFFER
|
||||
done_reset:
|
||||
#endif
|
||||
/* Change the status. */
|
||||
status = result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
/* Test iconv's TRANSLIT and IGNORE option handling
|
||||
|
||||
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 <iconv.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <support/support.h>
|
||||
#include <support/check.h>
|
||||
|
||||
|
||||
/* Run one iconv test. Arguments:
|
||||
to: destination character set and options
|
||||
from: source character set
|
||||
input: input string to be converted
|
||||
exp_in: expected number of bytes consumed
|
||||
exp_ret: expected return value (error or number of irreversible conversions)
|
||||
exp_out: expected output string
|
||||
exp_err: expected value of `errno' after iconv returns. */
|
||||
static void
|
||||
test_iconv (const char *to, const char *from, char *input, size_t exp_in,
|
||||
size_t exp_ret, const char *exp_out, int exp_err)
|
||||
{
|
||||
iconv_t cd;
|
||||
char outbuf[500];
|
||||
size_t inlen, outlen;
|
||||
char *inptr, *outptr;
|
||||
size_t n;
|
||||
|
||||
cd = iconv_open (to, from);
|
||||
TEST_VERIFY (cd != (iconv_t) -1);
|
||||
|
||||
inlen = strlen (input);
|
||||
outlen = sizeof (outbuf);
|
||||
inptr = input;
|
||||
outptr = outbuf;
|
||||
|
||||
errno = 0;
|
||||
n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
|
||||
|
||||
TEST_COMPARE (n, exp_ret);
|
||||
TEST_VERIFY (inptr == input + exp_in);
|
||||
TEST_COMPARE (errno, exp_err);
|
||||
TEST_COMPARE_BLOB (outbuf, outptr - outbuf, exp_out, strlen (exp_out));
|
||||
TEST_VERIFY (iconv_close (cd) == 0);
|
||||
}
|
||||
|
||||
|
||||
/* We test option parsing by converting UTF-8 inputs to ASCII under various
|
||||
option combinations. The UTF-8 inputs fall into three categories:
|
||||
- ASCII-only,
|
||||
- non-ASCII,
|
||||
- non-ASCII with invalid UTF-8 characters. */
|
||||
|
||||
/* 1. */
|
||||
char ascii[] = "Just some ASCII text";
|
||||
|
||||
/* 2. Valid UTF-8 input and some corresponding expected outputs with various
|
||||
options. The two non-ASCII characters below are accented alphabets:
|
||||
an `a' then an `o'. */
|
||||
char utf8[] = "UTF-8 text with \u00E1 couple \u00F3f non-ASCII characters";
|
||||
char u2a[] = "UTF-8 text with ";
|
||||
char u2a_translit[] = "UTF-8 text with a couple of non-ASCII characters";
|
||||
char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters";
|
||||
|
||||
/* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is
|
||||
invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */
|
||||
char iutf8[] = "Invalid UTF-8 \xff\u27E6text\u27E7";
|
||||
char iu2a[] = "Invalid UTF-8 ";
|
||||
char iu2a_ignore[] = "Invalid UTF-8 text";
|
||||
char iu2a_both[] = "Invalid UTF-8 [|text|]";
|
||||
|
||||
/* 4. Another invalid UTF-8 input and corresponding expected outputs. This time
|
||||
the valid non-ASCII UTF-8 characters appear before the invalid \xff. */
|
||||
char jutf8[] = "Invalid \u27E6UTF-8\u27E7 \xfftext";
|
||||
char ju2a[] = "Invalid ";
|
||||
char ju2a_translit[] = "Invalid [|UTF-8|] ";
|
||||
char ju2a_ignore[] = "Invalid UTF-8 text";
|
||||
char ju2a_both[] = "Invalid [|UTF-8|] text";
|
||||
|
||||
/* We also test option handling for character set names that have the form
|
||||
"A/B". In this test, we test conversions "ISO-10646/UTF-8", and either
|
||||
ISO-8859-1 or ASCII. */
|
||||
|
||||
/* 5. Accented 'A' and 'a' characters in ISO-8859-1 and UTF-8, and an
|
||||
equivalent ASCII transliteration. */
|
||||
char iso8859_1_a[] = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, /* Accented A's. */
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, /* Accented a's. */
|
||||
0x00};
|
||||
char utf8_a[] = "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5"
|
||||
"\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5";
|
||||
char ascii_a[] = "AAAAAAaaaaaa";
|
||||
|
||||
/* 6. An invalid ASCII string where [0] is invalid and [1] is '~'. */
|
||||
char iascii [] = {0x80, '~', '\0'};
|
||||
char empty[] = "";
|
||||
char ia2u_ignore[] = "~";
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
xsetlocale (LC_ALL, "en_US.UTF-8");
|
||||
|
||||
|
||||
/* 0. iconv_open should gracefully fail for invalid character sets. */
|
||||
|
||||
TEST_VERIFY (iconv_open ("INVALID", "UTF-8") == (iconv_t) -1);
|
||||
TEST_VERIFY (iconv_open ("UTF-8", "INVALID") == (iconv_t) -1);
|
||||
TEST_VERIFY (iconv_open ("INVALID", "INVALID") == (iconv_t) -1);
|
||||
|
||||
|
||||
/* 1. ASCII-only UTF-8 input should convert to ASCII with no changes: */
|
||||
|
||||
test_iconv ("ASCII", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//TRANSLIT//", "UTF-8", ascii, strlen (ascii), 0, ascii,
|
||||
0);
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
test_iconv ("ASCII//IGNORE//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
|
||||
|
||||
|
||||
/* 2. Valid UTF-8 input with non-ASCII characters: */
|
||||
|
||||
/* EILSEQ when converted to ASCII. */
|
||||
test_iconv ("ASCII", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, EILSEQ);
|
||||
|
||||
/* Converted without error with TRANSLIT enabled. */
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, u2a_translit,
|
||||
0);
|
||||
|
||||
/* EILSEQ with IGNORE enabled. Non-ASCII chars dropped from output. */
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1,
|
||||
u2a_ignore, EILSEQ);
|
||||
|
||||
/* With TRANSLIT and IGNORE enabled, transliterated without error. We test
|
||||
four combinations. */
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
|
||||
/* Misspellings of TRANSLIT and IGNORE are ignored, but conversion still
|
||||
works while respecting any other correctly spelled options. */
|
||||
|
||||
test_iconv ("ASCII//T", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
test_iconv ("ASCII//TRANSLITERATE", "UTF-8", utf8, strlen (u2a), (size_t) -1,
|
||||
u2a, EILSEQ);
|
||||
test_iconv ("ASCII//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
test_iconv ("ASCII//IGNORED", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
test_iconv ("ASCII//TRANSLITERATE//IGNORED", "UTF-8", utf8, strlen (u2a),
|
||||
(size_t) -1, u2a, EILSEQ);
|
||||
test_iconv ("ASCII//IGNORED,TRANSLITERATE", "UTF-8", utf8, strlen (u2a),
|
||||
(size_t) -1, u2a, EILSEQ);
|
||||
test_iconv ("ASCII//T//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
|
||||
EILSEQ);
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT//I", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//I//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//IGNORED,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORED", "UTF-8", utf8, strlen (utf8), 2,
|
||||
u2a_translit, 0);
|
||||
|
||||
test_iconv ("ASCII//IGNORE,T", "UTF-8", utf8, strlen (utf8), (size_t) -1,
|
||||
u2a_ignore, EILSEQ);
|
||||
test_iconv ("ASCII//T,IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1,
|
||||
u2a_ignore, EILSEQ);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
|
||||
test_iconv ("ASCII//TRANSLITERATE//IGNORE", "UTF-8", utf8, strlen (utf8),
|
||||
(size_t) -1, u2a_ignore, EILSEQ);
|
||||
test_iconv ("ASCII//IGNORE//TRANSLITERATE", "UTF-8", utf8, strlen (utf8),
|
||||
(size_t) -1, u2a_ignore, EILSEQ);
|
||||
|
||||
|
||||
/* 3. Invalid UTF-8 followed by some valid non-ASCII UTF-8 characters: */
|
||||
|
||||
/* EILSEQ; output is truncated at the first invalid UTF-8 character. */
|
||||
test_iconv ("ASCII", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, iu2a,
|
||||
EILSEQ);
|
||||
|
||||
/* With TRANSLIT enabled: EILSEQ; output still truncated at the first invalid
|
||||
UTF-8 character. */
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", iutf8, strlen (iu2a), (size_t) -1,
|
||||
iu2a, EILSEQ);
|
||||
|
||||
/* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and
|
||||
valid UTF-8 non-ASCII characters. */
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", iutf8, strlen (iutf8), (size_t) -1,
|
||||
iu2a_ignore, EILSEQ);
|
||||
|
||||
/* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8
|
||||
characters and transliterates valid non-ASCII UTF-8 characters. We test
|
||||
four combinations. */
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
|
||||
test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2,
|
||||
iu2a_both, 0);
|
||||
|
||||
|
||||
/* 4. Invalid UTF-8 with valid non-ASCII UTF-8 chars appearing first: */
|
||||
|
||||
/* EILSEQ; output is truncated at the first non-ASCII character. */
|
||||
test_iconv ("ASCII", "UTF-8", jutf8, strlen (ju2a), (size_t) -1, ju2a,
|
||||
EILSEQ);
|
||||
|
||||
/* With TRANSLIT enabled: EILSEQ; output now truncated at the first invalid
|
||||
UTF-8 character. */
|
||||
test_iconv ("ASCII//TRANSLIT", "UTF-8", jutf8, strlen (jutf8) - 5,
|
||||
(size_t) -1, ju2a_translit, EILSEQ);
|
||||
test_iconv ("ASCII//translit", "UTF-8", jutf8, strlen (jutf8) - 5,
|
||||
(size_t) -1, ju2a_translit, EILSEQ);
|
||||
|
||||
/* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and
|
||||
valid UTF-8 non-ASCII characters. */
|
||||
test_iconv ("ASCII//IGNORE", "UTF-8", jutf8, strlen (jutf8), (size_t) -1,
|
||||
ju2a_ignore, EILSEQ);
|
||||
test_iconv ("ASCII//ignore", "UTF-8", jutf8, strlen (jutf8), (size_t) -1,
|
||||
ju2a_ignore, EILSEQ);
|
||||
|
||||
/* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8
|
||||
characters and transliterates valid non-ASCII UTF-8 characters. We test
|
||||
several combinations. */
|
||||
|
||||
test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
|
||||
test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
/* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
|
||||
test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//translit,ignore", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
/* Trailing whitespace and separators should be ignored. */
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT ", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT/", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT//", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT,", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT,,", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
test_iconv ("ASCII//IGNORE,TRANSLIT /,", "UTF-8", jutf8, strlen (jutf8), 2,
|
||||
ju2a_both, 0);
|
||||
|
||||
/* TRANSLIT or IGNORE suffixes in fromcode should be ignored. */
|
||||
test_iconv ("ASCII", "UTF-8//TRANSLIT", jutf8, strlen (ju2a), (size_t) -1,
|
||||
ju2a, EILSEQ);
|
||||
test_iconv ("ASCII", "UTF-8//IGNORE", jutf8, strlen (ju2a), (size_t) -1,
|
||||
ju2a, EILSEQ);
|
||||
test_iconv ("ASCII", "UTF-8//TRANSLIT,IGNORE", jutf8, strlen (ju2a),
|
||||
(size_t) -1, ju2a, EILSEQ);
|
||||
|
||||
|
||||
/* 5. Charset names of the form "A/B/": */
|
||||
|
||||
/* ISO-8859-1 is converted to UTF-8 without needing transliteration. */
|
||||
test_iconv ("ISO-10646/UTF-8", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT/IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ISO-8859-1", iso8859_1_a,
|
||||
strlen (iso8859_1_a), 0, utf8_a, 0);
|
||||
|
||||
/* UTF-8 with accented A's is converted to ASCII with transliteration. */
|
||||
test_iconv ("ASCII", "ISO-10646/UTF-8", utf8_a,
|
||||
0, (size_t) -1, empty, EILSEQ);
|
||||
test_iconv ("ASCII//IGNORE", "ISO-10646/UTF-8", utf8_a,
|
||||
strlen (utf8_a), (size_t) -1, empty, EILSEQ);
|
||||
test_iconv ("ASCII//TRANSLIT", "ISO-10646/UTF-8", utf8_a,
|
||||
strlen (utf8_a), 12, ascii_a, 0);
|
||||
|
||||
/* Invalid ASCII is converted to UTF-8 only with IGNORE. */
|
||||
test_iconv ("ISO-10646/UTF-8", "ASCII", iascii, strlen (empty), (size_t) -1,
|
||||
empty, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ASCII", iascii, strlen (empty),
|
||||
(size_t) -1, empty, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8/IGNORE", "ASCII", iascii, strlen (iascii),
|
||||
(size_t) -1, ia2u_ignore, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
/* Due to bug 19519, iconv was ignoring IGNORE for the following three
|
||||
inputs: */
|
||||
test_iconv ("ISO-10646/UTF-8/TRANSLIT/IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT,IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ASCII", iascii,
|
||||
strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Test iconv buffer handling with the IGNORE error handler.
|
||||
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/>. */
|
||||
|
||||
/* Derived from BZ #18830 */
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* This conversion needs two steps, from ASCII to INTERNAL to ASCII. */
|
||||
iconv_t cd = iconv_open ("ASCII//IGNORE", "ASCII");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
/* Convert some irreversible sequence, enough to trigger an overflow of
|
||||
the output buffer before the irreversible character in the second
|
||||
step, but after going past the irreversible character in the first
|
||||
step. */
|
||||
char input[4 + 4] = { '0', '1', '2', '3', '4', '5', '\266', '7' };
|
||||
char *inptr = input;
|
||||
size_t insize = sizeof (input);
|
||||
char output[4];
|
||||
char *outptr = output;
|
||||
size_t outsize = sizeof (output);
|
||||
|
||||
/* The conversion should fail. */
|
||||
TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1);
|
||||
TEST_VERIFY (errno == E2BIG);
|
||||
/* The conversion should not consume more than it was able to store in
|
||||
the output buffer. */
|
||||
TEST_COMPARE (inptr - input, sizeof (output) - outsize);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -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
|
||||
+2
-12
@@ -157,24 +157,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; \
|
||||
|
||||
@@ -216,6 +216,10 @@ struct link_map
|
||||
unsigned int boundndx;
|
||||
uint32_t enterexit;
|
||||
unsigned int flags;
|
||||
/* CONCURRENCY NOTE: This is used to guard the concurrent initialization
|
||||
of the relocation result across multiple threads. See the more
|
||||
detailed notes in elf/dl-runtime.c. */
|
||||
unsigned int init;
|
||||
} *l_reloc_result;
|
||||
|
||||
/* Pointer to the version information if available. */
|
||||
|
||||
@@ -28,6 +28,7 @@ libc_hidden_proto (clntudp_create)
|
||||
libc_hidden_proto (get_myaddress)
|
||||
libc_hidden_proto (clntunix_create)
|
||||
libc_hidden_proto (__libc_clntudp_bufcreate)
|
||||
libc_hidden_proto (rpc_createerr)
|
||||
|
||||
# endif /* !_ISOMAC */
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
# ifndef _ISOMAC
|
||||
|
||||
libc_hidden_proto (svc_pollfd)
|
||||
libc_hidden_proto (svc_max_pollfd)
|
||||
libc_hidden_proto (svc_fdset)
|
||||
|
||||
libc_hidden_proto (xprt_register)
|
||||
libc_hidden_proto (xprt_unregister)
|
||||
libc_hidden_proto (svc_register)
|
||||
|
||||
@@ -77,6 +77,8 @@ extern char *__getcwd (char *__buf, size_t __size) attribute_hidden;
|
||||
extern int __rmdir (const char *__path) attribute_hidden;
|
||||
extern int __execvpe (const char *file, char *const argv[],
|
||||
char *const envp[]) attribute_hidden;
|
||||
extern int __execvpex (const char *file, char *const argv[],
|
||||
char *const envp[]) attribute_hidden;
|
||||
|
||||
/* Get the canonical absolute name of the named directory, and put it in SIZE
|
||||
bytes of BUF. Returns NULL if the directory couldn't be determined or
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ aux := check_pf check_native ifreq
|
||||
tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
|
||||
tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
|
||||
tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \
|
||||
tst-sockaddr test-hnto-types
|
||||
tst-sockaddr test-hnto-types tst-if_index-long
|
||||
|
||||
# tst-deadline must be linked statically so that we can access
|
||||
# internal functions.
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Check for descriptor leak in if_nametoindex with a long interface name.
|
||||
Copyright (C) 2018 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 checks for a descriptor leak in case of a long interface
|
||||
name (CVE-2018-19591, bug 23927). */
|
||||
|
||||
#include <errno.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/descriptors.h>
|
||||
#include <support/support.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct support_descriptors *descrs = support_descriptors_list ();
|
||||
|
||||
/* Prepare a name which is just as long as required for trigging the
|
||||
bug. */
|
||||
char name[IFNAMSIZ + 1];
|
||||
memset (name, 'A', IFNAMSIZ);
|
||||
name[IFNAMSIZ] = '\0';
|
||||
TEST_COMPARE (strlen (name), IFNAMSIZ);
|
||||
struct ifreq ifr;
|
||||
TEST_COMPARE (strlen (name), sizeof (ifr.ifr_name));
|
||||
|
||||
/* Test directly via if_nametoindex. */
|
||||
TEST_COMPARE (if_nametoindex (name), 0);
|
||||
TEST_COMPARE (errno, ENODEV);
|
||||
support_descriptors_check (descrs);
|
||||
|
||||
/* Same test via getaddrinfo. */
|
||||
char *host = xasprintf ("fea0::%%%s", name);
|
||||
struct addrinfo hints = { .ai_flags = AI_NUMERICHOST, };
|
||||
struct addrinfo *ai;
|
||||
TEST_COMPARE (getaddrinfo (host, NULL, &hints, &ai), EAI_NONAME);
|
||||
support_descriptors_check (descrs);
|
||||
|
||||
support_descriptors_free (descrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+5
-1
@@ -120,7 +120,11 @@ $(objpfx)tst-gettext6.out: $(gen-locales)
|
||||
$(objpfx)tst-translit.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
$(objpfx)msgs.h: po2test.awk ../po/de.po
|
||||
$(objpfx)tst-gettext-de.po: ../po/de.po
|
||||
$(make-target-directory)
|
||||
LC_ALL=C $(AWK) '!/^"POT-Creation-Date: [0-9-]+ [0-9:+-]+\\n"$$/' $^ > $@
|
||||
|
||||
$(objpfx)msgs.h: po2test.awk $(objpfx)tst-gettext-de.po
|
||||
$(make-target-directory)
|
||||
LC_ALL=C $(AWK) -f $^ > $@
|
||||
|
||||
|
||||
+13
-5
@@ -631,7 +631,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
|
||||
int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname);
|
||||
free (cwd);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
goto return_untranslated;
|
||||
dirname = xdirname;
|
||||
}
|
||||
#ifndef IN_LIBGLOCALE
|
||||
@@ -1120,11 +1120,19 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
|
||||
outcharset = encoding;
|
||||
|
||||
# ifdef _LIBC
|
||||
|
||||
struct gconv_spec conv_spec;
|
||||
|
||||
__gconv_create_spec (&conv_spec, charset, outcharset);
|
||||
|
||||
/* We always want to use transliteration. */
|
||||
outcharset = norm_add_slashes (outcharset, "TRANSLIT");
|
||||
charset = norm_add_slashes (charset, "");
|
||||
int r = __gconv_open (outcharset, charset, &convd->conv,
|
||||
GCONV_AVOID_NOCONV);
|
||||
conv_spec.translit = true;
|
||||
|
||||
int r = __gconv_open (&conv_spec, &convd->conv,
|
||||
GCONV_AVOID_NOCONV);
|
||||
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (__builtin_expect (r != __GCONV_OK, 0))
|
||||
{
|
||||
/* If the output encoding is the same there is
|
||||
|
||||
+14
-20
@@ -22,13 +22,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char *s;
|
||||
int result = 0;
|
||||
|
||||
unsetenv ("LANGUAGE");
|
||||
unsetenv ("OUTPUT_CHARSET");
|
||||
setlocale (LC_ALL, "de_DE.ISO-8859-1");
|
||||
@@ -36,25 +34,21 @@ do_test (void)
|
||||
bindtextdomain ("codeset", OBJPFX "domaindir");
|
||||
|
||||
/* Here we expect output in ISO-8859-1. */
|
||||
s = gettext ("cheese");
|
||||
if (strcmp (s, "K\344se"))
|
||||
{
|
||||
printf ("call 1 returned: %s\n", s);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
bind_textdomain_codeset ("codeset", "UTF-8");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "K\344se");
|
||||
|
||||
/* Here we expect output in UTF-8. */
|
||||
s = gettext ("cheese");
|
||||
if (strcmp (s, "K\303\244se"))
|
||||
{
|
||||
printf ("call 2 returned: %s\n", s);
|
||||
result = 1;
|
||||
}
|
||||
bind_textdomain_codeset ("codeset", "UTF-8");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se");
|
||||
|
||||
return result;
|
||||
/* `a with umlaut' is transliterated to `ae'. */
|
||||
bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
|
||||
|
||||
/* Transliteration also works by default even if not set. */
|
||||
bind_textdomain_codeset ("codeset", "ASCII");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
#include <support/test-driver.c>
|
||||
|
||||
+2
-2
@@ -42,9 +42,9 @@ mkdir -p ${objpfx}domaindir/existing-locale/LC_MESSAGES
|
||||
mkdir -p ${objpfx}domaindir/existing-locale/LC_TIME
|
||||
# Populate them.
|
||||
msgfmt -o ${objpfx}domaindir/existing-locale/LC_MESSAGES/existing-domain.mo \
|
||||
-f ../po/de.po
|
||||
-f ${objpfx}tst-gettext-de.po
|
||||
msgfmt -o ${objpfx}domaindir/existing-locale/LC_TIME/existing-time-domain.mo \
|
||||
-f ../po/de.po
|
||||
-f ${objpfx}tst-gettext-de.po
|
||||
|
||||
# Now run the test.
|
||||
${test_program_prefix_before_env} \
|
||||
|
||||
@@ -73,11 +73,6 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
|
||||
tst-fts tst-fts-lfs tst-open-tmpfile \
|
||||
tst-copy_file_range tst-getcwd-abspath \
|
||||
|
||||
# This test includes the compat implementation of copy_file_range,
|
||||
# which uses internal, unexported libc functions.
|
||||
tests-static += tst-copy_file_range-compat
|
||||
tests-internal += tst-copy_file_range-compat
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)ftwtest.out
|
||||
endif
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/* Emulation of copy_file_range.
|
||||
Copyright (C) 2017-2018 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/>. */
|
||||
|
||||
/* The following macros should be defined before including this
|
||||
file:
|
||||
|
||||
COPY_FILE_RANGE_DECL Declaration specifiers for the function below.
|
||||
COPY_FILE_RANGE Name of the function to define. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
COPY_FILE_RANGE_DECL
|
||||
ssize_t
|
||||
COPY_FILE_RANGE (int infd, __off64_t *pinoff,
|
||||
int outfd, __off64_t *poutoff,
|
||||
size_t length, unsigned int flags)
|
||||
{
|
||||
if (flags != 0)
|
||||
{
|
||||
__set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
struct stat64 instat;
|
||||
struct stat64 outstat;
|
||||
if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0)
|
||||
return -1;
|
||||
if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode))
|
||||
{
|
||||
__set_errno (EISDIR);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode))
|
||||
{
|
||||
/* We need a regular input file so that the we can seek
|
||||
backwards in case of a write failure. */
|
||||
__set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
if (instat.st_dev != outstat.st_dev)
|
||||
{
|
||||
/* Cross-device copies are not supported. */
|
||||
__set_errno (EXDEV);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The output descriptor must not have O_APPEND set. */
|
||||
{
|
||||
int flags = __fcntl (outfd, F_GETFL);
|
||||
if (flags & O_APPEND)
|
||||
{
|
||||
__set_errno (EBADF);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid an overflow in the result. */
|
||||
if (length > SSIZE_MAX)
|
||||
length = SSIZE_MAX;
|
||||
|
||||
/* Main copying loop. The buffer size is arbitrary and is a
|
||||
trade-off between stack size consumption, cache usage, and
|
||||
amortization of system call overhead. */
|
||||
size_t copied = 0;
|
||||
char buf[8192];
|
||||
while (length > 0)
|
||||
{
|
||||
size_t to_read = length;
|
||||
if (to_read > sizeof (buf))
|
||||
to_read = sizeof (buf);
|
||||
|
||||
/* Fill the buffer. */
|
||||
ssize_t read_count;
|
||||
if (pinoff == NULL)
|
||||
read_count = read (infd, buf, to_read);
|
||||
else
|
||||
read_count = __libc_pread64 (infd, buf, to_read, *pinoff);
|
||||
if (read_count == 0)
|
||||
/* End of file reached prematurely. */
|
||||
return copied;
|
||||
if (read_count < 0)
|
||||
{
|
||||
if (copied > 0)
|
||||
/* Report the number of bytes copied so far. */
|
||||
return copied;
|
||||
return -1;
|
||||
}
|
||||
if (pinoff != NULL)
|
||||
*pinoff += read_count;
|
||||
|
||||
/* Write the buffer part which was read to the destination. */
|
||||
char *end = buf + read_count;
|
||||
for (char *p = buf; p < end; )
|
||||
{
|
||||
ssize_t write_count;
|
||||
if (poutoff == NULL)
|
||||
write_count = write (outfd, p, end - p);
|
||||
else
|
||||
write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff);
|
||||
if (write_count < 0)
|
||||
{
|
||||
/* Adjust the input read position to match what we have
|
||||
written, so that the caller can pick up after the
|
||||
error. */
|
||||
size_t written = p - buf;
|
||||
/* NB: This needs to be signed so that we can form the
|
||||
negative value below. */
|
||||
ssize_t overread = read_count - written;
|
||||
if (pinoff == NULL)
|
||||
{
|
||||
if (overread > 0)
|
||||
{
|
||||
/* We are on an error recovery path, so we
|
||||
cannot deal with failure here. */
|
||||
int save_errno = errno;
|
||||
(void) __libc_lseek64 (infd, -overread, SEEK_CUR);
|
||||
__set_errno (save_errno);
|
||||
}
|
||||
}
|
||||
else /* pinoff != NULL */
|
||||
*pinoff -= overread;
|
||||
|
||||
if (copied + written > 0)
|
||||
/* Report the number of bytes copied so far. */
|
||||
return copied + written;
|
||||
return -1;
|
||||
}
|
||||
p += write_count;
|
||||
if (poutoff != NULL)
|
||||
*poutoff += write_count;
|
||||
} /* Write loop. */
|
||||
|
||||
copied += read_count;
|
||||
length -= read_count;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
+13
-5
@@ -1,5 +1,5 @@
|
||||
/* Generic implementation of copy_file_range.
|
||||
Copyright (C) 2017-2018 Free Software Foundation, Inc.
|
||||
/* Stub implementation of copy_file_range.
|
||||
Copyright (C) 2017-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
|
||||
@@ -16,7 +16,15 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define COPY_FILE_RANGE_DECL
|
||||
#define COPY_FILE_RANGE copy_file_range
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <io/copy_file_range-compat.c>
|
||||
ssize_t
|
||||
copy_file_range (int infd, __off64_t *pinoff,
|
||||
int outfd, __off64_t *poutoff,
|
||||
size_t length, unsigned int flags)
|
||||
{
|
||||
__set_errno (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
stub_warning (copy_file_range)
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ typedef __pid_t pid_t;
|
||||
# define SEEK_END 2 /* Seek from end of file. */
|
||||
#endif /* XPG */
|
||||
|
||||
/* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EASSESS
|
||||
/* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS
|
||||
is meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
|
||||
unlinkat. The two functions do completely different things and therefore,
|
||||
the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
|
||||
|
||||
+10
-547
@@ -1,5 +1,5 @@
|
||||
/* Tests for copy_file_range.
|
||||
Copyright (C) 2017-2018 Free Software Foundation, Inc.
|
||||
Copyright (C) 2017-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
|
||||
@@ -20,22 +20,15 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libgen.h>
|
||||
#include <poll.h>
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.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/test-driver.h>
|
||||
#include <support/xunistd.h>
|
||||
#ifdef CLONE_NEWNS
|
||||
# include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
/* Boolean flags which indicate whether to use pointers with explicit
|
||||
output flags. */
|
||||
@@ -49,10 +42,6 @@ static int infd;
|
||||
static char *outfile;
|
||||
static int outfd;
|
||||
|
||||
/* Like the above, but on a different file system. xdevfile can be
|
||||
NULL if no suitable file system has been found. */
|
||||
static char *xdevfile;
|
||||
|
||||
/* Input and output offsets. Set according to do_inoff and do_outoff
|
||||
before the test. The offsets themselves are always set to
|
||||
zero. */
|
||||
@@ -61,13 +50,10 @@ static off64_t *pinoff;
|
||||
static off64_t outoff;
|
||||
static off64_t *poutoff;
|
||||
|
||||
/* These are a collection of copy sizes used in tests. The selection
|
||||
takes into account that the fallback implementation uses an
|
||||
internal buffer of 8192 bytes. */
|
||||
/* These are a collection of copy sizes used in tests. */
|
||||
enum { maximum_size = 99999 };
|
||||
static const int typical_sizes[] =
|
||||
{ 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
|
||||
maximum_size };
|
||||
{ 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size };
|
||||
|
||||
/* The random contents of this array can be used as a pattern to check
|
||||
for correct write operations. */
|
||||
@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size];
|
||||
/* The size chosen by the test harness. */
|
||||
static int current_size;
|
||||
|
||||
/* Maximum writable file offset. Updated by find_maximum_offset
|
||||
below. */
|
||||
static off64_t maximum_offset;
|
||||
|
||||
/* Error code when crossing the offset. */
|
||||
static int maximum_offset_errno;
|
||||
|
||||
/* If true: Writes which cross the limit will fail. If false: Writes
|
||||
which cross the limit will result in a partial write. */
|
||||
static bool maximum_offset_hard_limit;
|
||||
|
||||
/* Fills maximum_offset etc. above. Truncates outfd as a side
|
||||
effect. */
|
||||
static void
|
||||
find_maximum_offset (void)
|
||||
{
|
||||
xftruncate (outfd, 0);
|
||||
if (maximum_offset != 0)
|
||||
return;
|
||||
|
||||
uint64_t upper = -1;
|
||||
upper >>= 1; /* Maximum of off64_t. */
|
||||
TEST_VERIFY ((off64_t) upper > 0);
|
||||
TEST_VERIFY ((off64_t) (upper + 1) < 0);
|
||||
if (lseek64 (outfd, upper, SEEK_SET) >= 0)
|
||||
{
|
||||
if (write (outfd, "", 1) == 1)
|
||||
FAIL_EXIT1 ("created a file larger than the off64_t range");
|
||||
}
|
||||
|
||||
uint64_t lower = 1024 * 1024; /* A reasonable minimum file size. */
|
||||
/* Loop invariant: writing at lower succeeds, writing at upper fails. */
|
||||
while (lower + 1 < upper)
|
||||
{
|
||||
uint64_t middle = (lower + upper) / 2;
|
||||
if (test_verbose > 0)
|
||||
printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64
|
||||
", probe at %" PRIu64 "\n", __func__, lower, upper, middle);
|
||||
xftruncate (outfd, 0);
|
||||
if (lseek64 (outfd, middle, SEEK_SET) >= 0
|
||||
&& write (outfd, "", 1) == 1)
|
||||
lower = middle;
|
||||
else
|
||||
upper = middle;
|
||||
}
|
||||
TEST_VERIFY (lower + 1 == upper);
|
||||
maximum_offset = lower;
|
||||
printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n",
|
||||
lower, lower);
|
||||
|
||||
/* Check that writing at the valid offset actually works. */
|
||||
xftruncate (outfd, 0);
|
||||
xlseek (outfd, lower, SEEK_SET);
|
||||
TEST_COMPARE (write (outfd, "", 1), 1);
|
||||
|
||||
/* Cross the boundary with a two-byte write. This can either result
|
||||
in a short write, or a failure. */
|
||||
xlseek (outfd, lower, SEEK_SET);
|
||||
ssize_t ret = write (outfd, " ", 2);
|
||||
if (ret < 0)
|
||||
{
|
||||
maximum_offset_errno = errno;
|
||||
maximum_offset_hard_limit = true;
|
||||
}
|
||||
else
|
||||
maximum_offset_hard_limit = false;
|
||||
|
||||
/* Check that writing at the next offset actually fails. This also
|
||||
obtains the expected errno value. */
|
||||
xftruncate (outfd, 0);
|
||||
const char *action;
|
||||
if (lseek64 (outfd, lower + 1, SEEK_SET) != 0)
|
||||
{
|
||||
if (write (outfd, "", 1) != -1)
|
||||
FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded",
|
||||
lower + 1);
|
||||
action = "writing";
|
||||
int errno_copy = errno;
|
||||
if (maximum_offset_hard_limit)
|
||||
TEST_COMPARE (errno_copy, maximum_offset_errno);
|
||||
else
|
||||
maximum_offset_errno = errno_copy;
|
||||
}
|
||||
else
|
||||
{
|
||||
action = "seeking";
|
||||
maximum_offset_errno = errno;
|
||||
}
|
||||
printf ("info: %s out of range fails with %m (%d)\n",
|
||||
action, maximum_offset_errno);
|
||||
|
||||
xftruncate (outfd, 0);
|
||||
xlseek (outfd, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
/* Perform a copy of a file. */
|
||||
static void
|
||||
simple_file_copy (void)
|
||||
@@ -247,390 +138,6 @@ simple_file_copy (void)
|
||||
free (bytes);
|
||||
}
|
||||
|
||||
/* Test that reading from a pipe willfails. */
|
||||
static void
|
||||
pipe_as_source (void)
|
||||
{
|
||||
int pipefds[2];
|
||||
xpipe (pipefds);
|
||||
|
||||
for (int length = 0; length < 2; ++length)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: %s: length=%d\n", __func__, length);
|
||||
|
||||
/* Make sure that there is something to copy in the pipe. */
|
||||
xwrite (pipefds[1], "@", 1);
|
||||
|
||||
TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff,
|
||||
length, 0), -1);
|
||||
/* Linux 4.10 and later return EINVAL. Older kernels return
|
||||
EXDEV. */
|
||||
TEST_VERIFY (errno == EINVAL || errno == EXDEV);
|
||||
TEST_COMPARE (inoff, 0);
|
||||
TEST_COMPARE (outoff, 0);
|
||||
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0);
|
||||
|
||||
/* Make sure that nothing was read. */
|
||||
char buf = 'A';
|
||||
TEST_COMPARE (read (pipefds[0], &buf, 1), 1);
|
||||
TEST_COMPARE (buf, '@');
|
||||
}
|
||||
|
||||
xclose (pipefds[0]);
|
||||
xclose (pipefds[1]);
|
||||
}
|
||||
|
||||
/* Test that writing to a pipe fails. */
|
||||
static void
|
||||
pipe_as_destination (void)
|
||||
{
|
||||
/* Make sure that there is something to read in the input file. */
|
||||
xwrite (infd, "abc", 3);
|
||||
xlseek (infd, 0, SEEK_SET);
|
||||
|
||||
int pipefds[2];
|
||||
xpipe (pipefds);
|
||||
|
||||
for (int length = 0; length < 2; ++length)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: %s: length=%d\n", __func__, length);
|
||||
|
||||
TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff,
|
||||
length, 0), -1);
|
||||
/* Linux 4.10 and later return EINVAL. Older kernels return
|
||||
EXDEV. */
|
||||
TEST_VERIFY (errno == EINVAL || errno == EXDEV);
|
||||
TEST_COMPARE (inoff, 0);
|
||||
TEST_COMPARE (outoff, 0);
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
|
||||
|
||||
/* Make sure that nothing was written. */
|
||||
struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, };
|
||||
TEST_COMPARE (poll (&pollfd, 1, 0), 0);
|
||||
}
|
||||
|
||||
xclose (pipefds[0]);
|
||||
xclose (pipefds[1]);
|
||||
}
|
||||
|
||||
/* Test a write failure after (potentially) writing some bytes.
|
||||
Failure occurs near the start of the buffer. */
|
||||
static void
|
||||
delayed_write_failure_beginning (void)
|
||||
{
|
||||
/* We need to write something to provoke the error. */
|
||||
if (current_size == 0)
|
||||
return;
|
||||
xwrite (infd, random_data, sizeof (random_data));
|
||||
xlseek (infd, 0, SEEK_SET);
|
||||
|
||||
/* Write failure near the start. The actual error code varies among
|
||||
file systems. */
|
||||
find_maximum_offset ();
|
||||
off64_t where = maximum_offset;
|
||||
|
||||
if (current_size == 1)
|
||||
++where;
|
||||
outoff = where;
|
||||
if (do_outoff)
|
||||
xlseek (outfd, 1, SEEK_SET);
|
||||
else
|
||||
xlseek (outfd, where, SEEK_SET);
|
||||
if (maximum_offset_hard_limit || where > maximum_offset)
|
||||
{
|
||||
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
|
||||
sizeof (random_data), 0), -1);
|
||||
TEST_COMPARE (errno, maximum_offset_errno);
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
|
||||
TEST_COMPARE (inoff, 0);
|
||||
if (do_outoff)
|
||||
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
|
||||
else
|
||||
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where);
|
||||
TEST_COMPARE (outoff, where);
|
||||
struct stat64 st;
|
||||
xfstat (outfd, &st);
|
||||
TEST_COMPARE (st.st_size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The offset is not a hard limit. This means we write one
|
||||
byte. */
|
||||
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
|
||||
sizeof (random_data), 0), 1);
|
||||
if (do_inoff)
|
||||
{
|
||||
TEST_COMPARE (inoff, 1);
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1);
|
||||
TEST_COMPARE (inoff, 0);
|
||||
}
|
||||
if (do_outoff)
|
||||
{
|
||||
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
|
||||
TEST_COMPARE (outoff, where + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1);
|
||||
TEST_COMPARE (outoff, where);
|
||||
}
|
||||
struct stat64 st;
|
||||
xfstat (outfd, &st);
|
||||
TEST_COMPARE (st.st_size, where + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test a write failure after (potentially) writing some bytes.
|
||||
Failure occurs near the end of the buffer. */
|
||||
static void
|
||||
delayed_write_failure_end (void)
|
||||
{
|
||||
if (current_size <= 1)
|
||||
/* This would be same as the first test because there is not
|
||||
enough data to write to make a difference. */
|
||||
return;
|
||||
xwrite (infd, random_data, sizeof (random_data));
|
||||
xlseek (infd, 0, SEEK_SET);
|
||||
|
||||
find_maximum_offset ();
|
||||
off64_t where = maximum_offset - current_size + 1;
|
||||
if (current_size == sizeof (random_data))
|
||||
/* Otherwise we do not reach the non-writable byte. */
|
||||
++where;
|
||||
outoff = where;
|
||||
if (do_outoff)
|
||||
xlseek (outfd, 1, SEEK_SET);
|
||||
else
|
||||
xlseek (outfd, where, SEEK_SET);
|
||||
ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff,
|
||||
sizeof (random_data), 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
TEST_COMPARE (ret, -1);
|
||||
TEST_COMPARE (errno, maximum_offset_errno);
|
||||
struct stat64 st;
|
||||
xfstat (outfd, &st);
|
||||
TEST_COMPARE (st.st_size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The first copy succeeded. This happens in the emulation
|
||||
because the internal buffer of limited size does not
|
||||
necessarily cross the off64_t boundary on the first write
|
||||
operation. */
|
||||
if (test_verbose > 0)
|
||||
printf ("info: copy_file_range (%zu) returned %zd\n",
|
||||
sizeof (random_data), ret);
|
||||
TEST_VERIFY (ret > 0);
|
||||
TEST_VERIFY (ret < maximum_size);
|
||||
struct stat64 st;
|
||||
xfstat (outfd, &st);
|
||||
TEST_COMPARE (st.st_size, where + ret);
|
||||
if (do_inoff)
|
||||
{
|
||||
TEST_COMPARE (inoff, ret);
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
|
||||
}
|
||||
else
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret);
|
||||
|
||||
char *buffer = xmalloc (ret);
|
||||
TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret);
|
||||
TEST_VERIFY (memcmp (buffer, random_data, ret) == 0);
|
||||
free (buffer);
|
||||
|
||||
/* The second copy fails. */
|
||||
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
|
||||
sizeof (random_data), 0), -1);
|
||||
TEST_COMPARE (errno, maximum_offset_errno);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test a write failure across devices. */
|
||||
static void
|
||||
cross_device_failure (void)
|
||||
{
|
||||
if (xdevfile == NULL)
|
||||
/* Subtest not supported due to missing cross-device file. */
|
||||
return;
|
||||
|
||||
/* We need something to write. */
|
||||
xwrite (infd, random_data, sizeof (random_data));
|
||||
xlseek (infd, 0, SEEK_SET);
|
||||
|
||||
int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0);
|
||||
TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff,
|
||||
current_size, 0), -1);
|
||||
TEST_COMPARE (errno, EXDEV);
|
||||
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
|
||||
struct stat64 st;
|
||||
xfstat (xdevfd, &st);
|
||||
TEST_COMPARE (st.st_size, 0);
|
||||
|
||||
xclose (xdevfd);
|
||||
}
|
||||
|
||||
/* Try to exercise ENOSPC behavior with a tempfs file system (so that
|
||||
we do not have to fill up a regular file system to get the error).
|
||||
This function runs in a subprocess, so that we do not change the
|
||||
mount namespace of the actual test process. */
|
||||
static void
|
||||
enospc_failure_1 (void *closure)
|
||||
{
|
||||
#ifdef CLONE_NEWNS
|
||||
support_become_root ();
|
||||
|
||||
/* Make sure that we do not alter the file system mounts of the
|
||||
parents. */
|
||||
if (! support_enter_mount_namespace ())
|
||||
{
|
||||
printf ("warning: ENOSPC test skipped\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *mountpoint = closure;
|
||||
if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC,
|
||||
"size=500k") != 0)
|
||||
{
|
||||
printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The source file must reside on the same file system. */
|
||||
char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in");
|
||||
int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
|
||||
xwrite (intmpfsfd, random_data, sizeof (random_data));
|
||||
xlseek (intmpfsfd, 1, SEEK_SET);
|
||||
inoff = 1;
|
||||
|
||||
char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out");
|
||||
int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
|
||||
|
||||
/* Fill the file with data until ENOSPC is reached. */
|
||||
while (true)
|
||||
{
|
||||
ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data));
|
||||
if (ret < 0 && errno != ENOSPC)
|
||||
FAIL_EXIT1 ("write to %s: %m", outtmpfsfile);
|
||||
if (ret < sizeof (random_data))
|
||||
break;
|
||||
}
|
||||
TEST_COMPARE (write (outtmpfsfd, "", 1), -1);
|
||||
TEST_COMPARE (errno, ENOSPC);
|
||||
off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR);
|
||||
TEST_VERIFY_EXIT (maxsize > sizeof (random_data));
|
||||
|
||||
/* Constructed the expected file contents. */
|
||||
char *expected = xmalloc (maxsize);
|
||||
TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize);
|
||||
/* Go back a little, so some bytes can be written. */
|
||||
enum { offset = 20000 };
|
||||
TEST_VERIFY_EXIT (offset < maxsize);
|
||||
TEST_VERIFY_EXIT (offset < sizeof (random_data));
|
||||
memcpy (expected + maxsize - offset, random_data + 1, offset);
|
||||
|
||||
if (do_outoff)
|
||||
{
|
||||
outoff = maxsize - offset;
|
||||
xlseek (outtmpfsfd, 2, SEEK_SET);
|
||||
}
|
||||
else
|
||||
xlseek (outtmpfsfd, -offset, SEEK_CUR);
|
||||
|
||||
/* First call is expected to succeed because we made room for some
|
||||
bytes. */
|
||||
TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
|
||||
maximum_size, 0), offset);
|
||||
if (do_inoff)
|
||||
{
|
||||
TEST_COMPARE (inoff, 1 + offset);
|
||||
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
|
||||
}
|
||||
else
|
||||
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
|
||||
if (do_outoff)
|
||||
{
|
||||
TEST_COMPARE (outoff, maxsize);
|
||||
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
|
||||
}
|
||||
else
|
||||
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
|
||||
struct stat64 st;
|
||||
xfstat (outtmpfsfd, &st);
|
||||
TEST_COMPARE (st.st_size, maxsize);
|
||||
char *actual = xmalloc (st.st_size);
|
||||
TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size);
|
||||
TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
|
||||
|
||||
/* Second call should fail with ENOSPC. */
|
||||
TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
|
||||
maximum_size, 0), -1);
|
||||
TEST_COMPARE (errno, ENOSPC);
|
||||
|
||||
/* Offsets should be unchanged. */
|
||||
if (do_inoff)
|
||||
{
|
||||
TEST_COMPARE (inoff, 1 + offset);
|
||||
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
|
||||
}
|
||||
else
|
||||
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
|
||||
if (do_outoff)
|
||||
{
|
||||
TEST_COMPARE (outoff, maxsize);
|
||||
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
|
||||
}
|
||||
else
|
||||
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
|
||||
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize);
|
||||
TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize);
|
||||
TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
|
||||
|
||||
free (actual);
|
||||
free (expected);
|
||||
|
||||
xclose (intmpfsfd);
|
||||
xclose (outtmpfsfd);
|
||||
free (intmpfsfile);
|
||||
free (outtmpfsfile);
|
||||
|
||||
#else /* !CLONE_NEWNS */
|
||||
puts ("warning: ENOSPC test skipped (no mount namespaces)");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Call enospc_failure_1 in a subprocess. */
|
||||
static void
|
||||
enospc_failure (void)
|
||||
{
|
||||
char *mountpoint
|
||||
= support_create_temp_directory ("tst-copy_file_range-enospc-");
|
||||
support_isolate_in_subprocess (enospc_failure_1, mountpoint);
|
||||
free (mountpoint);
|
||||
}
|
||||
|
||||
/* The target file descriptor must have O_APPEND enabled. */
|
||||
static void
|
||||
oappend_failure (void)
|
||||
{
|
||||
/* Add data, to make sure we do not fail because there is
|
||||
insufficient input data. */
|
||||
xwrite (infd, random_data, current_size);
|
||||
xlseek (infd, 0, SEEK_SET);
|
||||
|
||||
xclose (outfd);
|
||||
outfd = xopen (outfile, O_RDWR | O_APPEND, 0);
|
||||
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
|
||||
current_size, 0), -1);
|
||||
TEST_COMPARE (errno, EBADF);
|
||||
}
|
||||
|
||||
/* Test that a short input file results in a shortened copy. */
|
||||
static void
|
||||
short_copy (void)
|
||||
@@ -721,14 +228,6 @@ struct test_case
|
||||
static struct test_case tests[] =
|
||||
{
|
||||
{ "simple_file_copy", simple_file_copy, .sizes = true },
|
||||
{ "pipe_as_source", pipe_as_source, },
|
||||
{ "pipe_as_destination", pipe_as_destination, },
|
||||
{ "delayed_write_failure_beginning", delayed_write_failure_beginning,
|
||||
.sizes = true },
|
||||
{ "delayed_write_failure_end", delayed_write_failure_end, .sizes = true },
|
||||
{ "cross_device_failure", cross_device_failure, .sizes = true },
|
||||
{ "enospc_failure", enospc_failure, },
|
||||
{ "oappend_failure", oappend_failure, .sizes = true },
|
||||
{ "short_copy", short_copy, .sizes = true },
|
||||
};
|
||||
|
||||
@@ -739,53 +238,18 @@ do_test (void)
|
||||
*p = rand () >> 24;
|
||||
|
||||
infd = create_temp_file ("tst-copy_file_range-in-", &infile);
|
||||
xclose (create_temp_file ("tst-copy_file_range-out-", &outfile));
|
||||
|
||||
/* Try to find a different directory from the default input/output
|
||||
file. */
|
||||
outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
|
||||
{
|
||||
struct stat64 instat;
|
||||
xfstat (infd, &instat);
|
||||
static const char *const candidates[] =
|
||||
{ NULL, "/var/tmp", "/dev/shm" };
|
||||
for (const char *const *c = candidates; c < array_end (candidates); ++c)
|
||||
ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
const char *path = *c;
|
||||
char *to_free = NULL;
|
||||
if (path == NULL)
|
||||
{
|
||||
to_free = xreadlink ("/proc/self/exe");
|
||||
path = dirname (to_free);
|
||||
}
|
||||
|
||||
struct stat64 cstat;
|
||||
xstat (path, &cstat);
|
||||
if (cstat.st_dev == instat.st_dev)
|
||||
{
|
||||
free (to_free);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf ("info: using alternate temporary files directory: %s\n", path);
|
||||
xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path);
|
||||
free (to_free);
|
||||
break;
|
||||
if (errno == ENOSYS)
|
||||
FAIL_UNSUPPORTED ("copy_file_range is not support on this system");
|
||||
FAIL_EXIT1 ("copy_file_range probing call: %m");
|
||||
}
|
||||
if (xdevfile != NULL)
|
||||
{
|
||||
int xdevfd = mkstemp (xdevfile);
|
||||
if (xdevfd < 0)
|
||||
FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile);
|
||||
struct stat64 xdevst;
|
||||
xfstat (xdevfd, &xdevst);
|
||||
TEST_VERIFY (xdevst.st_dev != instat.st_dev);
|
||||
add_temp_file (xdevfile);
|
||||
xclose (xdevfd);
|
||||
}
|
||||
else
|
||||
puts ("warning: no alternate directory on different file system found");
|
||||
}
|
||||
xclose (infd);
|
||||
xclose (outfd);
|
||||
|
||||
for (do_inoff = 0; do_inoff < 2; ++do_inoff)
|
||||
for (do_outoff = 0; do_outoff < 2; ++do_outoff)
|
||||
@@ -827,7 +291,6 @@ do_test (void)
|
||||
|
||||
free (infile);
|
||||
free (outfile);
|
||||
free (xdevfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+18
-2
@@ -63,11 +63,17 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
|
||||
bug-memstream1 bug-wmemstream1 \
|
||||
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
|
||||
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
|
||||
tst-ftell-append tst-fputws tst-bz22415
|
||||
tst-ftell-append tst-fputws tst-bz22415 tst-wfile-sync
|
||||
|
||||
tests-internal = tst-vtables tst-vtables-interposed
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
# Add test-fopenloc only if shared library is enabled since it depends on
|
||||
# shared localedata objects.
|
||||
tests += tst-fopenloc
|
||||
# Add tst-bz24228 only if shared library is enabled since it can never meet its
|
||||
# objective with static linking because the relevant code just is not there.
|
||||
tests += tst-bz24228
|
||||
endif
|
||||
test-srcs = test-freopen
|
||||
|
||||
@@ -148,11 +154,14 @@ CFLAGS-oldtmpfile.c += -fexceptions
|
||||
|
||||
CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
|
||||
|
||||
LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
|
||||
|
||||
tst_wprintf2-ARGS = "Some Text"
|
||||
|
||||
test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
|
||||
tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
|
||||
tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
|
||||
tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
|
||||
|
||||
generated += test-fmemopen.mtrace test-fmemopen.check
|
||||
generated += tst-fopenloc.mtrace tst-fopenloc.check
|
||||
@@ -161,6 +170,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check
|
||||
aux := fileops genops stdfiles stdio strops
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
generated += tst-bz24228.mtrace tst-bz24228.check
|
||||
aux += oldfileops oldstdfiles
|
||||
endif
|
||||
|
||||
@@ -175,7 +185,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \
|
||||
ifeq (yes,$(build-shared))
|
||||
# Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
|
||||
# library is enabled since they depend on tst-fopenloc.out.
|
||||
tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
|
||||
tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
|
||||
$(objpfx)tst-bz24228-mem.out
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -203,6 +214,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales)
|
||||
$(objpfx)tst-ungetwc2.out: $(gen-locales)
|
||||
$(objpfx)tst-widetext.out: $(gen-locales)
|
||||
$(objpfx)tst_wprintf2.out: $(gen-locales)
|
||||
$(objpfx)tst-wfile-sync.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
$(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
|
||||
@@ -226,3 +238,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out
|
||||
$(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
+12
-4
@@ -852,9 +852,16 @@ _IO_unbuffer_all (void)
|
||||
|
||||
for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
|
||||
{
|
||||
int legacy = 0;
|
||||
|
||||
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
|
||||
if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
|
||||
legacy = 1;
|
||||
#endif
|
||||
|
||||
if (! (fp->_flags & _IO_UNBUFFERED)
|
||||
/* Iff stream is un-orientated, it wasn't used. */
|
||||
&& fp->_mode != 0)
|
||||
&& (legacy || fp->_mode != 0))
|
||||
{
|
||||
#ifdef _IO_MTSAFE_IO
|
||||
int cnt;
|
||||
@@ -868,7 +875,7 @@ _IO_unbuffer_all (void)
|
||||
__sched_yield ();
|
||||
#endif
|
||||
|
||||
if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
|
||||
if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
|
||||
{
|
||||
fp->_flags |= _IO_USER_BUF;
|
||||
|
||||
@@ -879,7 +886,7 @@ _IO_unbuffer_all (void)
|
||||
|
||||
_IO_SETBUF (fp, NULL, 0);
|
||||
|
||||
if (fp->_mode > 0)
|
||||
if (! legacy && fp->_mode > 0)
|
||||
_IO_wsetb (fp, NULL, NULL, 0);
|
||||
|
||||
#ifdef _IO_MTSAFE_IO
|
||||
@@ -890,7 +897,8 @@ _IO_unbuffer_all (void)
|
||||
|
||||
/* Make sure that never again the wide char functions can be
|
||||
used. */
|
||||
fp->_mode = -1;
|
||||
if (! legacy)
|
||||
fp->_mode = -1;
|
||||
}
|
||||
|
||||
#ifdef _IO_MTSAFE_IO
|
||||
|
||||
+2
-2
@@ -90,8 +90,8 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc)
|
||||
_IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps;
|
||||
_IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
|
||||
new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
|
||||
new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
|
||||
new_f->fp._sf._s._free_buffer = (_IO_free_type) free;
|
||||
new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
|
||||
new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free;
|
||||
|
||||
new_f->fp.bufloc = bufloc;
|
||||
new_f->fp.sizeloc = sizeloc;
|
||||
|
||||
@@ -87,6 +87,11 @@ _IO_check_libio (void)
|
||||
stdout->_vtable_offset = 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -31,8 +31,11 @@ typedef void (*_IO_free_type) (void*);
|
||||
|
||||
struct _IO_str_fields
|
||||
{
|
||||
_IO_alloc_type _allocate_buffer;
|
||||
_IO_free_type _free_buffer;
|
||||
/* These members are preserved for ABI compatibility. The glibc
|
||||
implementation always calls malloc/free for user buffers if
|
||||
_IO_USER_BUF or _IO_FLAGS2_USER_WBUF are not set. */
|
||||
_IO_alloc_type _allocate_buffer_unused;
|
||||
_IO_free_type _free_buffer_unused;
|
||||
};
|
||||
|
||||
/* This is needed for the Irix6 N32 ABI, which has a 64 bit off_t type,
|
||||
@@ -52,10 +55,6 @@ typedef struct _IO_strfile_
|
||||
struct _IO_str_fields _s;
|
||||
} _IO_strfile;
|
||||
|
||||
/* dynamic: set when the array object is allocated (or reallocated) as
|
||||
necessary to hold a character sequence that can change in length. */
|
||||
#define _IO_STR_DYNAMIC(FP) ((FP)->_s._allocate_buffer != (_IO_alloc_type)0)
|
||||
|
||||
/* frozen: set when the program has requested that the array object not
|
||||
be altered, reallocated, or freed. */
|
||||
#define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF)
|
||||
|
||||
+6
-8
@@ -61,7 +61,7 @@ _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size,
|
||||
fp->_IO_read_end = end;
|
||||
}
|
||||
/* A null _allocate_buffer function flags the strfile as being static. */
|
||||
sf->_s._allocate_buffer = (_IO_alloc_type) 0;
|
||||
sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -103,8 +103,7 @@ _IO_str_overflow (_IO_FILE *fp, int c)
|
||||
_IO_size_t new_size = 2 * old_blen + 100;
|
||||
if (new_size < old_blen)
|
||||
return EOF;
|
||||
new_buf
|
||||
= (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
|
||||
new_buf = malloc (new_size);
|
||||
if (new_buf == NULL)
|
||||
{
|
||||
/* __ferror(fp) = 1; */
|
||||
@@ -113,7 +112,7 @@ _IO_str_overflow (_IO_FILE *fp, int c)
|
||||
if (old_buf)
|
||||
{
|
||||
memcpy (new_buf, old_buf, old_blen);
|
||||
(*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
|
||||
free (old_buf);
|
||||
/* Make sure _IO_setb won't try to delete _IO_buf_base. */
|
||||
fp->_IO_buf_base = NULL;
|
||||
}
|
||||
@@ -182,15 +181,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
|
||||
|
||||
_IO_size_t newsize = offset + 100;
|
||||
char *oldbuf = fp->_IO_buf_base;
|
||||
char *newbuf
|
||||
= (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize);
|
||||
char *newbuf = malloc (newsize);
|
||||
if (newbuf == NULL)
|
||||
return 1;
|
||||
|
||||
if (oldbuf != NULL)
|
||||
{
|
||||
memcpy (newbuf, oldbuf, _IO_blen (fp));
|
||||
(*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
|
||||
free (oldbuf);
|
||||
/* Make sure _IO_setb won't try to delete
|
||||
_IO_buf_base. */
|
||||
fp->_IO_buf_base = NULL;
|
||||
@@ -346,7 +344,7 @@ void
|
||||
_IO_str_finish (_IO_FILE *fp, int dummy)
|
||||
{
|
||||
if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
|
||||
(((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
|
||||
free (fp->_IO_buf_base);
|
||||
fp->_IO_buf_base = NULL;
|
||||
|
||||
_IO_default_finish (fp, 0);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* BZ #24228 check for memory corruption in legacy libio
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <mcheck.h>
|
||||
#include <support/test-driver.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
mtrace ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,5 @@
|
||||
# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c
|
||||
# implementation when it is available for the architecture.
|
||||
{
|
||||
local: _IO_stdin_used;
|
||||
};
|
||||
@@ -0,0 +1,511 @@
|
||||
/* Test for libio vtables and their validation. Common code.
|
||||
Copyright (C) 2018 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 provides some coverage for how various stdio functions
|
||||
use the vtables in FILE * objects. The focus is mostly on which
|
||||
functions call which methods, not so much on validating data
|
||||
processing. An initial series of tests check that custom vtables
|
||||
do not work without activation through _IO_init.
|
||||
|
||||
Note: libio vtables are deprecated feature. Do not use this test
|
||||
as a documentation source for writing custom vtables. See
|
||||
fopencookie for a different way of creating custom stdio
|
||||
streams. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
/* Data shared between the test subprocess and the test driver in the
|
||||
parent. Note that *shared is reset at the start of the check_call
|
||||
function. */
|
||||
struct shared
|
||||
{
|
||||
/* Expected file pointer for method calls. */
|
||||
FILE *fp;
|
||||
|
||||
/* If true, assume that a call to _IO_init is needed to enable
|
||||
custom vtables. */
|
||||
bool initially_disabled;
|
||||
|
||||
/* Requested return value for the methods which have one. */
|
||||
int return_value;
|
||||
|
||||
/* A value (usually a character) recorded by some of the methods
|
||||
below. */
|
||||
int value;
|
||||
|
||||
/* Likewise, for some data. */
|
||||
char buffer[16];
|
||||
size_t buffer_length;
|
||||
|
||||
/* Total number of method calls. */
|
||||
unsigned int calls;
|
||||
|
||||
/* Individual method call counts. */
|
||||
unsigned int calls_finish;
|
||||
unsigned int calls_overflow;
|
||||
unsigned int calls_underflow;
|
||||
unsigned int calls_uflow;
|
||||
unsigned int calls_pbackfail;
|
||||
unsigned int calls_xsputn;
|
||||
unsigned int calls_xsgetn;
|
||||
unsigned int calls_seekoff;
|
||||
unsigned int calls_seekpos;
|
||||
unsigned int calls_setbuf;
|
||||
unsigned int calls_sync;
|
||||
unsigned int calls_doallocate;
|
||||
unsigned int calls_read;
|
||||
unsigned int calls_write;
|
||||
unsigned int calls_seek;
|
||||
unsigned int calls_close;
|
||||
unsigned int calls_stat;
|
||||
unsigned int calls_showmanyc;
|
||||
unsigned int calls_imbue;
|
||||
} *shared;
|
||||
|
||||
/* Method implementations which increment the counters in *shared. */
|
||||
|
||||
static void
|
||||
log_method (FILE *fp, const char *name)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: %s (%p) called\n", name, fp);
|
||||
}
|
||||
|
||||
static void
|
||||
method_finish (FILE *fp, int dummy)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_finish;
|
||||
}
|
||||
|
||||
static int
|
||||
method_overflow (FILE *fp, int ch)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_overflow;
|
||||
shared->value = ch;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_underflow (FILE *fp)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_underflow;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_uflow (FILE *fp)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_uflow;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_pbackfail (FILE *fp, int ch)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_pbackfail;
|
||||
shared->value = ch;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static size_t
|
||||
method_xsputn (FILE *fp, const void *data, size_t n)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_xsputn;
|
||||
|
||||
size_t to_copy = n;
|
||||
if (n > sizeof (shared->buffer))
|
||||
to_copy = sizeof (shared->buffer);
|
||||
memcpy (shared->buffer, data, to_copy);
|
||||
shared->buffer_length = to_copy;
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
static size_t
|
||||
method_xsgetn (FILE *fp, void *data, size_t n)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_xsgetn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off64_t
|
||||
method_seekoff (FILE *fp, off64_t offset, int dir, int mode)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_seekoff;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static off64_t
|
||||
method_seekpos (FILE *fp, off64_t offset, int mode)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_seekpos;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
method_setbuf (FILE *fp, char *buffer, ssize_t length)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_setbuf;
|
||||
return fp;
|
||||
}
|
||||
|
||||
static int
|
||||
method_sync (FILE *fp)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_sync;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_doallocate (FILE *fp)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_doallocate;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
method_read (FILE *fp, void *data, ssize_t length)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_read;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
method_write (FILE *fp, const void *data, ssize_t length)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_write;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static off64_t
|
||||
method_seek (FILE *fp, off64_t offset, int mode)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_seek;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_close (FILE *fp)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_close;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_stat (FILE *fp, void *buffer)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_stat;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static int
|
||||
method_showmanyc (FILE *fp)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_showmanyc;
|
||||
return shared->return_value;
|
||||
}
|
||||
|
||||
static void
|
||||
method_imbue (FILE *fp, void *locale)
|
||||
{
|
||||
log_method (fp, __func__);
|
||||
TEST_VERIFY (fp == shared->fp);
|
||||
++shared->calls;
|
||||
++shared->calls_imbue;
|
||||
}
|
||||
|
||||
/* Our custom vtable. */
|
||||
|
||||
static const struct _IO_jump_t jumps =
|
||||
{
|
||||
JUMP_INIT_DUMMY,
|
||||
JUMP_INIT (finish, method_finish),
|
||||
JUMP_INIT (overflow, method_overflow),
|
||||
JUMP_INIT (underflow, method_underflow),
|
||||
JUMP_INIT (uflow, method_uflow),
|
||||
JUMP_INIT (pbackfail, method_pbackfail),
|
||||
JUMP_INIT (xsputn, method_xsputn),
|
||||
JUMP_INIT (xsgetn, method_xsgetn),
|
||||
JUMP_INIT (seekoff, method_seekoff),
|
||||
JUMP_INIT (seekpos, method_seekpos),
|
||||
JUMP_INIT (setbuf, method_setbuf),
|
||||
JUMP_INIT (sync, method_sync),
|
||||
JUMP_INIT (doallocate, method_doallocate),
|
||||
JUMP_INIT (read, method_read),
|
||||
JUMP_INIT (write, method_write),
|
||||
JUMP_INIT (seek, method_seek),
|
||||
JUMP_INIT (close, method_close),
|
||||
JUMP_INIT (stat, method_stat),
|
||||
JUMP_INIT (showmanyc, method_showmanyc),
|
||||
JUMP_INIT (imbue, method_imbue)
|
||||
};
|
||||
|
||||
/* Our file implementation. */
|
||||
|
||||
struct my_file
|
||||
{
|
||||
FILE f;
|
||||
const struct _IO_jump_t *vtable;
|
||||
};
|
||||
|
||||
struct my_file
|
||||
my_file_create (void)
|
||||
{
|
||||
return (struct my_file)
|
||||
{
|
||||
/* Disable locking, so that we do not have to set up a lock
|
||||
pointer. */
|
||||
.f._flags = _IO_USER_LOCK,
|
||||
|
||||
/* Copy the offset from the an initialized handle, instead of
|
||||
figuring it out from scratch. */
|
||||
.f._vtable_offset = stdin->_vtable_offset,
|
||||
|
||||
.vtable = &jumps,
|
||||
};
|
||||
}
|
||||
|
||||
/* Initial tests which do not enable vtable compatibility. */
|
||||
|
||||
/* Inhibit GCC optimization of fprintf. */
|
||||
typedef int (*fprintf_type) (FILE *, const char *, ...);
|
||||
static const volatile fprintf_type fprintf_ptr = &fprintf;
|
||||
|
||||
static void
|
||||
without_compatibility_fprintf (void *closure)
|
||||
{
|
||||
/* This call should abort. */
|
||||
fprintf_ptr (shared->fp, " ");
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
static void
|
||||
without_compatibility_fputc (void *closure)
|
||||
{
|
||||
/* This call should abort. */
|
||||
fputc (' ', shared->fp);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
static void
|
||||
without_compatibility_fgetc (void *closure)
|
||||
{
|
||||
/* This call should abort. */
|
||||
fgetc (shared->fp);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
static void
|
||||
without_compatibility_fflush (void *closure)
|
||||
{
|
||||
/* This call should abort. */
|
||||
fflush (shared->fp);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
/* Exit status after abnormal termination. */
|
||||
static int termination_status;
|
||||
|
||||
static void
|
||||
init_termination_status (void)
|
||||
{
|
||||
pid_t pid = xfork ();
|
||||
if (pid == 0)
|
||||
abort ();
|
||||
xwaitpid (pid, &termination_status, 0);
|
||||
|
||||
TEST_VERIFY (WIFSIGNALED (termination_status));
|
||||
TEST_COMPARE (WTERMSIG (termination_status), SIGABRT);
|
||||
}
|
||||
|
||||
static void
|
||||
check_for_termination (const char *name, void (*callback) (void *))
|
||||
{
|
||||
struct my_file file = my_file_create ();
|
||||
shared->fp = &file.f;
|
||||
shared->return_value = -1;
|
||||
shared->calls = 0;
|
||||
struct support_capture_subprocess proc
|
||||
= support_capture_subprocess (callback, NULL);
|
||||
support_capture_subprocess_check (&proc, name, termination_status,
|
||||
sc_allow_stderr);
|
||||
const char *message
|
||||
= "Fatal error: glibc detected an invalid stdio handle\n";
|
||||
TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length,
|
||||
message, strlen (message));
|
||||
TEST_COMPARE (shared->calls, 0);
|
||||
support_capture_subprocess_free (&proc);
|
||||
}
|
||||
|
||||
/* The test with vtable validation disabled. */
|
||||
|
||||
/* This function does not have a prototype in libioP.h to prevent
|
||||
accidental use from within the library (which would disable vtable
|
||||
verification). */
|
||||
void _IO_init (FILE *fp, int flags);
|
||||
|
||||
static void
|
||||
with_compatibility_fprintf (void *closure)
|
||||
{
|
||||
TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4);
|
||||
TEST_COMPARE (shared->calls, 3);
|
||||
TEST_COMPARE (shared->calls_xsputn, 3);
|
||||
TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length,
|
||||
"CD", 2);
|
||||
}
|
||||
|
||||
static void
|
||||
with_compatibility_fputc (void *closure)
|
||||
{
|
||||
shared->return_value = '@';
|
||||
TEST_COMPARE (fputc ('@', shared->fp), '@');
|
||||
TEST_COMPARE (shared->calls, 1);
|
||||
TEST_COMPARE (shared->calls_overflow, 1);
|
||||
TEST_COMPARE (shared->value, '@');
|
||||
}
|
||||
|
||||
static void
|
||||
with_compatibility_fgetc (void *closure)
|
||||
{
|
||||
shared->return_value = 'X';
|
||||
TEST_COMPARE (fgetc (shared->fp), 'X');
|
||||
TEST_COMPARE (shared->calls, 1);
|
||||
TEST_COMPARE (shared->calls_uflow, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
with_compatibility_fflush (void *closure)
|
||||
{
|
||||
TEST_COMPARE (fflush (shared->fp), 0);
|
||||
TEST_COMPARE (shared->calls, 1);
|
||||
TEST_COMPARE (shared->calls_sync, 1);
|
||||
}
|
||||
|
||||
/* Call CALLBACK in a subprocess, after setting up a custom file
|
||||
object and updating shared->fp. */
|
||||
static void
|
||||
check_call (const char *name, void (*callback) (void *),
|
||||
bool initially_disabled)
|
||||
{
|
||||
*shared = (struct shared)
|
||||
{
|
||||
.initially_disabled = initially_disabled,
|
||||
};
|
||||
|
||||
/* Set up a custom file object. */
|
||||
struct my_file file = my_file_create ();
|
||||
shared->fp = &file.f;
|
||||
if (shared->initially_disabled)
|
||||
_IO_init (shared->fp, file.f._flags);
|
||||
|
||||
if (test_verbose > 0)
|
||||
printf ("info: calling test %s\n", name);
|
||||
support_isolate_in_subprocess (callback, NULL);
|
||||
}
|
||||
|
||||
/* Run the tests. INITIALLY_DISABLED indicates whether custom vtables
|
||||
are disabled when the test starts. */
|
||||
static int
|
||||
run_tests (bool initially_disabled)
|
||||
{
|
||||
/* The test relies on fatal error messages being printed to standard
|
||||
error. */
|
||||
setenv ("LIBC_FATAL_STDERR_", "1", 1);
|
||||
|
||||
shared = support_shared_allocate (sizeof (*shared));
|
||||
shared->initially_disabled = initially_disabled;
|
||||
init_termination_status ();
|
||||
|
||||
if (initially_disabled)
|
||||
{
|
||||
check_for_termination ("fprintf", without_compatibility_fprintf);
|
||||
check_for_termination ("fputc", without_compatibility_fputc);
|
||||
check_for_termination ("fgetc", without_compatibility_fgetc);
|
||||
check_for_termination ("fflush", without_compatibility_fflush);
|
||||
}
|
||||
|
||||
check_call ("fprintf", with_compatibility_fprintf, initially_disabled);
|
||||
check_call ("fputc", with_compatibility_fputc, initially_disabled);
|
||||
check_call ("fgetc", with_compatibility_fgetc, initially_disabled);
|
||||
check_call ("fflush", with_compatibility_fflush, initially_disabled);
|
||||
|
||||
support_shared_free (shared);
|
||||
shared = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Test for libio vtables and their validation. Enabled through interposition.
|
||||
Copyright (C) 2018 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/>. */
|
||||
|
||||
/* Provide an interposed definition of the standard file handles with
|
||||
our own vtable. stdout/stdin/stderr will not work as a result, but
|
||||
a succesful test does not print anything, so this is fine. */
|
||||
static const struct _IO_jump_t jumps;
|
||||
#define _IO_file_jumps jumps
|
||||
#include "stdfiles.c"
|
||||
|
||||
#include "tst-vtables-common.c"
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
return run_tests (false);
|
||||
}
|
||||
|
||||
/* Calling setvbuf in the test driver is not supported with our
|
||||
interposed file handles. */
|
||||
#define TEST_NO_SETVBUF
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Test for libio vtables and their validation. Initially disabled case.
|
||||
Copyright (C) 2018 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/>. */
|
||||
|
||||
#include "libioP.h"
|
||||
|
||||
#include "tst-vtables-common.c"
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
return run_tests (true);
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Test that _IO_wfile_sync does not crash (bug 20568).
|
||||
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/>. */
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
|
||||
/* Fill the stdio buffer and advance the read pointer. */
|
||||
TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF);
|
||||
/* This calls _IO_wfile_sync, it should not crash. */
|
||||
TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
|
||||
/* Verify that the external file offset has been synchronized. */
|
||||
TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1 @@
|
||||
This is a test of _IO_wfile_sync.
|
||||
+2
-2
@@ -54,8 +54,8 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_va_list args)
|
||||
_IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
|
||||
_IO_str_init_static_internal (&sf, string, init_string_size, string);
|
||||
sf._sbf._f._flags &= ~_IO_USER_BUF;
|
||||
sf._s._allocate_buffer = (_IO_alloc_type) malloc;
|
||||
sf._s._free_buffer = (_IO_free_type) free;
|
||||
sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
|
||||
sf._s._free_buffer_unused = (_IO_free_type) free;
|
||||
ret = _IO_vfprintf (&sf._sbf._f, format, args);
|
||||
if (ret < 0)
|
||||
{
|
||||
|
||||
@@ -71,3 +71,19 @@ _IO_vtable_check (void)
|
||||
|
||||
__libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n");
|
||||
}
|
||||
|
||||
/* Some variants of libstdc++ interpose _IO_2_1_stdin_ etc. and
|
||||
install their own vtables directly, without calling _IO_init or
|
||||
other functions. Detect this by looking at the vtables values
|
||||
during startup, and disable vtable validation in this case. */
|
||||
#ifdef SHARED
|
||||
__attribute__ ((constructor))
|
||||
static void
|
||||
check_stdfiles_vtables (void)
|
||||
{
|
||||
if (_IO_2_1_stdin_.vtable != &_IO_file_jumps
|
||||
|| _IO_2_1_stdout_.vtable != &_IO_file_jumps
|
||||
|| _IO_2_1_stderr_.vtable != &_IO_file_jumps)
|
||||
IO_set_accept_foreign_vtables (&_IO_vtable_check);
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-2
@@ -509,11 +509,12 @@ _IO_wfile_sync (_IO_FILE *fp)
|
||||
generate the wide characters up to the current reading
|
||||
position. */
|
||||
int nread;
|
||||
|
||||
size_t wnread = (fp->_wide_data->_IO_read_ptr
|
||||
- fp->_wide_data->_IO_read_base);
|
||||
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
|
||||
nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
|
||||
fp->_IO_read_base,
|
||||
fp->_IO_read_end, delta);
|
||||
fp->_IO_read_end, wnread);
|
||||
fp->_IO_read_ptr = fp->_IO_read_base + nread;
|
||||
delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
|
||||
}
|
||||
|
||||
+2
-2
@@ -92,8 +92,8 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc)
|
||||
_IO_wstr_init_static (&new_f->fp._sf._sbf._f, buf,
|
||||
_IO_BUFSIZ / sizeof (wchar_t), buf);
|
||||
new_f->fp._sf._sbf._f._flags2 &= ~_IO_FLAGS2_USER_WBUF;
|
||||
new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
|
||||
new_f->fp._sf._s._free_buffer = (_IO_free_type) free;
|
||||
new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
|
||||
new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free;
|
||||
|
||||
new_f->fp.bufloc = bufloc;
|
||||
new_f->fp.sizeloc = sizeloc;
|
||||
|
||||
+6
-10
@@ -63,7 +63,7 @@ _IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size,
|
||||
fp->_wide_data->_IO_read_end = end;
|
||||
}
|
||||
/* A null _allocate_buffer function flags the strfile as being static. */
|
||||
(((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0;
|
||||
(((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0;
|
||||
}
|
||||
|
||||
_IO_wint_t
|
||||
@@ -95,9 +95,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
|
||||
|| __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
|
||||
return EOF;
|
||||
|
||||
new_buf
|
||||
= (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
|
||||
* sizeof (wchar_t));
|
||||
new_buf = malloc (new_size * sizeof (wchar_t));
|
||||
if (new_buf == NULL)
|
||||
{
|
||||
/* __ferror(fp) = 1; */
|
||||
@@ -106,7 +104,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
|
||||
if (old_buf)
|
||||
{
|
||||
__wmemcpy (new_buf, old_buf, old_wblen);
|
||||
(*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
|
||||
free (old_buf);
|
||||
/* Make sure _IO_setb won't try to delete _IO_buf_base. */
|
||||
fp->_wide_data->_IO_buf_base = NULL;
|
||||
}
|
||||
@@ -186,16 +184,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
|
||||
return 1;
|
||||
|
||||
wchar_t *oldbuf = wd->_IO_buf_base;
|
||||
wchar_t *newbuf
|
||||
= (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
|
||||
* sizeof (wchar_t));
|
||||
wchar_t *newbuf = malloc (newsize * sizeof (wchar_t));
|
||||
if (newbuf == NULL)
|
||||
return 1;
|
||||
|
||||
if (oldbuf != NULL)
|
||||
{
|
||||
__wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
|
||||
(*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
|
||||
free (oldbuf);
|
||||
/* Make sure _IO_setb won't try to delete
|
||||
_IO_buf_base. */
|
||||
wd->_IO_buf_base = NULL;
|
||||
@@ -357,7 +353,7 @@ void
|
||||
_IO_wstr_finish (_IO_FILE *fp, int dummy)
|
||||
{
|
||||
if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
|
||||
(((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
|
||||
free (fp->_wide_data->_IO_buf_base);
|
||||
fp->_wide_data->_IO_buf_base = NULL;
|
||||
|
||||
_IO_wdefault_finish (fp, 0);
|
||||
|
||||
+3
-1
@@ -78,7 +78,7 @@ tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
|
||||
tst-leaks tst-mbswcs1 tst-mbswcs2 tst-mbswcs3 tst-mbswcs4 tst-mbswcs5 \
|
||||
tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \
|
||||
tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2 tst-setlocale3 \
|
||||
tst-wctype
|
||||
tst-wctype tst-iconv-math-trans
|
||||
tests-static = bug-setlocale1-static
|
||||
tests += $(tests-static)
|
||||
ifeq (yes,$(build-shared))
|
||||
@@ -113,6 +113,8 @@ LOCALES := de_DE.ISO-8859-1 de_DE.UTF-8 en_US.ANSI_X3.4-1968 \
|
||||
pl_PL.UTF-8 fr_CA.UTF-8 hr_HR.UTF-8 bs_BA.UTF-8 sr_RS.UTF-8 \
|
||||
is_IS.UTF-8 et_EE.UTF-8 hsb_DE.UTF-8 lt_LT.UTF-8
|
||||
include ../gen-locales.mk
|
||||
|
||||
$(objpfx)tst-iconv-math-trans.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
+71
-40
@@ -106,36 +106,67 @@ grouping 0;0
|
||||
END LC_NUMERIC
|
||||
|
||||
LC_TIME
|
||||
abday "dg";"dl";"dt";"dc";"dj";"dv";"ds"
|
||||
day "diumenge";/
|
||||
"dilluns";/
|
||||
"dimarts";/
|
||||
"dimecres";/
|
||||
"dijous";/
|
||||
"divendres";/
|
||||
"dissabte"
|
||||
abmon "gen";"feb";/
|
||||
"mar";"abr";/
|
||||
"mai";"jun";/
|
||||
"jul";"ago";/
|
||||
"set";"oct";/
|
||||
"nov";"des"
|
||||
mon "gener";/
|
||||
"febrer";/
|
||||
"mar<U00E7>";/
|
||||
"abril";/
|
||||
"maig";/
|
||||
"juny";/
|
||||
"juliol";/
|
||||
"agost";/
|
||||
"setembre";/
|
||||
"octubre";/
|
||||
"novembre";/
|
||||
"desembre"
|
||||
d_t_fmt "%a %d %b %Y %T %Z"
|
||||
d_fmt "%d//%m//%y"
|
||||
t_fmt "%T"
|
||||
am_pm "";""
|
||||
abday "dg.";"dl.";"dt.";"dc.";"dj.";"dv.";"ds."
|
||||
day "diumenge";/
|
||||
"dilluns";/
|
||||
"dimarts";/
|
||||
"dimecres";/
|
||||
"dijous";/
|
||||
"divendres";/
|
||||
"dissabte"
|
||||
ab_alt_mon "gen.";/
|
||||
"febr.";/
|
||||
"mar<U00E7>";/
|
||||
"abr.";/
|
||||
"maig";/
|
||||
"juny";/
|
||||
"jul.";/
|
||||
"ag.";/
|
||||
"set.";/
|
||||
"oct.";/
|
||||
"nov.";/
|
||||
"des."
|
||||
abmon "de gen.";/
|
||||
"de febr.";/
|
||||
"de mar<U00E7>";/
|
||||
"d<U2019>abr.";/
|
||||
"de maig";/
|
||||
"de juny";/
|
||||
"de jul.";/
|
||||
"d<U2019>ag.";/
|
||||
"de set.";/
|
||||
"d<U2019>oct.";/
|
||||
"de nov.";/
|
||||
"de des."
|
||||
alt_mon "gener";/
|
||||
"febrer";/
|
||||
"mar<U00E7>";/
|
||||
"abril";/
|
||||
"maig";/
|
||||
"juny";/
|
||||
"juliol";/
|
||||
"agost";/
|
||||
"setembre";/
|
||||
"octubre";/
|
||||
"novembre";/
|
||||
"desembre"
|
||||
mon "de gener";/
|
||||
"de febrer";/
|
||||
"de mar<U00E7>";/
|
||||
"d<U2019>abril";/
|
||||
"de maig";/
|
||||
"de juny";/
|
||||
"de juliol";/
|
||||
"d<U2019>agost";/
|
||||
"de setembre";/
|
||||
"d<U2019>octubre";/
|
||||
"de novembre";/
|
||||
"de desembre"
|
||||
d_t_fmt "%A, %-d %B de %Y, %T %Z"
|
||||
d_fmt "%-d//%-m//%y"
|
||||
t_fmt "%T"
|
||||
am_pm "a. m.";/
|
||||
"p. m."
|
||||
t_fmt_ampm ""
|
||||
week 7;19971130;4
|
||||
first_weekday 2
|
||||
@@ -146,9 +177,9 @@ copy "i18n"
|
||||
END LC_PAPER
|
||||
|
||||
LC_TELEPHONE
|
||||
tel_int_fmt "+%c %a %l"
|
||||
int_prefix "34"
|
||||
int_select "00"
|
||||
tel_int_fmt "+%c %a %l"
|
||||
int_prefix "34"
|
||||
int_select "00"
|
||||
END LC_TELEPHONE
|
||||
|
||||
LC_MEASUREMENT
|
||||
@@ -156,19 +187,19 @@ copy "i18n"
|
||||
END LC_MEASUREMENT
|
||||
|
||||
LC_NAME
|
||||
name_fmt "%d%t%g%t%m%t%f"
|
||||
name_fmt "%d%t%g%t%m%t%f"
|
||||
END LC_NAME
|
||||
|
||||
LC_ADDRESS
|
||||
postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N"
|
||||
postal_fmt "%f%N%a%N%d%N%b%N%s %h %e %r%N%z %T%N%c%N"
|
||||
country_name "Espanya"
|
||||
country_ab2 "ES"
|
||||
country_ab3 "ESP"
|
||||
country_num 724
|
||||
country_car "E"
|
||||
country_ab2 "ES"
|
||||
country_ab3 "ESP"
|
||||
country_num 724
|
||||
country_car "E"
|
||||
% català
|
||||
lang_name "catal<U00E0>"
|
||||
lang_ab "ca"
|
||||
lang_term "cat"
|
||||
lang_lib "cat"
|
||||
lang_lib "cat"
|
||||
END LC_ADDRESS
|
||||
|
||||
@@ -272,7 +272,7 @@ day "Ned<U011B>le";/
|
||||
"P<U00E1>tek";/
|
||||
"Sobota"
|
||||
|
||||
mon "leden";/
|
||||
alt_mon "leden";/
|
||||
"<U00FA>nor";/
|
||||
"b<U0159>ezen";/
|
||||
"duben";/
|
||||
@@ -334,6 +334,19 @@ abmon "led";/
|
||||
% "Nov";/
|
||||
% "Dec"
|
||||
|
||||
mon "ledna";/
|
||||
"<U00FA>nora";/
|
||||
"b<U0159>ezna";/
|
||||
"dubna";/
|
||||
"kv<U011B>tna";/
|
||||
"<U010D>ervna";/
|
||||
"<U010D>ervence";/
|
||||
"srpna";/
|
||||
"z<U00E1><U0159><U00ED>";/
|
||||
"<U0159><U00ED>jna";/
|
||||
"listopadu";/
|
||||
"prosince"
|
||||
|
||||
week 7;19971130;4
|
||||
first_weekday 2
|
||||
|
||||
|
||||
@@ -72,12 +72,18 @@ day "<U039A><U03C5><U03C1><U03B9><U03B1><U03BA><U03AE>";/
|
||||
"<U03A0><U03AD><U03BC><U03C0><U03C4><U03B7>";/
|
||||
"<U03A0><U03B1><U03C1><U03B1><U03C3><U03BA><U03B5><U03C5><U03AE>";/
|
||||
"<U03A3><U03AC><U03B2><U03B2><U03B1><U03C4><U03BF>"
|
||||
abmon "<U0399><U03B1><U03BD>";"<U03A6><U03B5><U03B2>";/
|
||||
ab_alt_mon "<U0399><U03B1><U03BD>";"<U03A6><U03B5><U03B2>";/
|
||||
"<U039C><U03AC><U03C1>";"<U0391><U03C0><U03C1>";/
|
||||
"<U039C><U03AC><U03B9>";"<U0399><U03BF><U03CD><U03BD>";/
|
||||
"<U0399><U03BF><U03CD><U03BB>";"<U0391><U03CD><U03B3>";/
|
||||
"<U03A3><U03B5><U03C0>";"<U039F><U03BA><U03C4>";/
|
||||
"<U039D><U03BF><U03AD>";"<U0394><U03B5><U03BA>"
|
||||
abmon "<U0399><U03B1><U03BD>";"<U03A6><U03B5><U03B2>";/
|
||||
"<U039C><U03B1><U03C1>";"<U0391><U03C0><U03C1>";/
|
||||
"<U039C><U03B1><U0390>";"<U0399><U03BF><U03C5><U03BD>";/
|
||||
"<U0399><U03BF><U03C5><U03BB>";"<U0391><U03C5><U03B3>";/
|
||||
"<U03A3><U03B5><U03C0>";"<U039F><U03BA><U03C4>";/
|
||||
"<U039D><U03BF><U03B5>";"<U0394><U03B5><U03BA>"
|
||||
alt_mon "<U0399><U03B1><U03BD><U03BF><U03C5><U03AC><U03C1><U03B9><U03BF><U03C2>";/
|
||||
"<U03A6><U03B5><U03B2><U03C1><U03BF><U03C5><U03AC><U03C1><U03B9><U03BF><U03C2>";/
|
||||
"<U039C><U03AC><U03C1><U03C4><U03B9><U03BF><U03C2>";/
|
||||
|
||||
@@ -104,12 +104,18 @@ day "<U039A><U03C5><U03C1><U03B9><U03B1><U03BA><U03AE>";/
|
||||
"<U03A0><U03AD><U03BC><U03C0><U03C4><U03B7>";/
|
||||
"<U03A0><U03B1><U03C1><U03B1><U03C3><U03BA><U03B5><U03C5><U03AE>";/
|
||||
"<U03A3><U03AC><U03B2><U03B2><U03B1><U03C4><U03BF>"
|
||||
abmon "<U0399><U03B1><U03BD>";"<U03A6><U03B5><U03B2>";/
|
||||
ab_alt_mon "<U0399><U03B1><U03BD>";"<U03A6><U03B5><U03B2>";/
|
||||
"<U039C><U03AC><U03C1>";"<U0391><U03C0><U03C1>";/
|
||||
"<U039C><U03AC><U03B9>";"<U0399><U03BF><U03CD><U03BD>";/
|
||||
"<U0399><U03BF><U03CD><U03BB>";"<U0391><U03CD><U03B3>";/
|
||||
"<U03A3><U03B5><U03C0>";"<U039F><U03BA><U03C4>";/
|
||||
"<U039D><U03BF><U03AD>";"<U0394><U03B5><U03BA>"
|
||||
abmon "<U0399><U03B1><U03BD>";"<U03A6><U03B5><U03B2>";/
|
||||
"<U039C><U03B1><U03C1>";"<U0391><U03C0><U03C1>";/
|
||||
"<U039C><U03B1><U0390>";"<U0399><U03BF><U03C5><U03BD>";/
|
||||
"<U0399><U03BF><U03C5><U03BB>";"<U0391><U03C5><U03B3>";/
|
||||
"<U03A3><U03B5><U03C0>";"<U039F><U03BA><U03C4>";/
|
||||
"<U039D><U03BF><U03B5>";"<U0394><U03B5><U03BA>"
|
||||
alt_mon "<U0399><U03B1><U03BD><U03BF><U03C5><U03AC><U03C1><U03B9><U03BF><U03C2>";/
|
||||
"<U03A6><U03B5><U03B2><U03C1><U03BF><U03C5><U03AC><U03C1><U03B9><U03BF><U03C2>";/
|
||||
"<U039C><U03AC><U03C1><U03C4><U03B9><U03BF><U03C2>";/
|
||||
|
||||
@@ -124,7 +124,7 @@ first_weekday 2
|
||||
END LC_TIME
|
||||
|
||||
LC_PAPER
|
||||
copy "i18n"
|
||||
copy "en_US"
|
||||
END LC_PAPER
|
||||
|
||||
LC_TELEPHONE
|
||||
|
||||
@@ -103,6 +103,8 @@ reorder-after <w>
|
||||
<U00FC> <u-diaresis>;<BAS>;<MIN>;IGNORE % ü
|
||||
<U00DC> <u-diaresis>;<BAS>;<CAP>;IGNORE % Ü
|
||||
|
||||
reorder-end
|
||||
|
||||
END LC_COLLATE
|
||||
|
||||
LC_CTYPE
|
||||
|
||||
@@ -66,12 +66,12 @@ mon "Am Faoilleach";/
|
||||
"An D<U00E0>mhair";/
|
||||
"An t-Samhain";/
|
||||
"An D<U00F9>bhlachd"
|
||||
% Faoi, Gearr, Màrt, Gibl, Mhàrt, Ògmh, Iuch, Lùna, Sult, Dàmh, Samh, Dùbh
|
||||
% Faoi, Gearr, Màrt, Gibl, Cèit, Ògmh, Iuch, Lùna, Sult, Dàmh, Samh, Dùbh
|
||||
abmon "Faoi";/
|
||||
"Gearr";/
|
||||
"M<U00E0>rt";/
|
||||
"Gibl";/
|
||||
"Mh<U00E0>rt";/
|
||||
"C<U00E8>it";/
|
||||
"<U00D2>gmh";/
|
||||
"Iuch";/
|
||||
"L<U00F9>na";/
|
||||
|
||||
@@ -14946,7 +14946,9 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>"
|
||||
|
||||
t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
|
||||
|
||||
era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
|
||||
era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
|
||||
"+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
|
||||
"+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
|
||||
"+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
|
||||
"+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
|
||||
"+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
|
||||
|
||||
@@ -201,12 +201,12 @@ day "Sekmadienis";/
|
||||
"Ketvirtadienis";/
|
||||
"Penktadienis";/
|
||||
"<U0160>e<U0161>tadienis"
|
||||
abmon "Sau";"Vas";/
|
||||
"Kov";"Bal";/
|
||||
"Geg";"Bir";/
|
||||
"Lie";"Rgp";/
|
||||
"Rgs";"Spa";/
|
||||
"Lap";"Grd"
|
||||
abmon "saus.";"vas.";/
|
||||
"kov.";"bal.";/
|
||||
"geg.";"bir<U017E>.";/
|
||||
"liep.";"rugp.";/
|
||||
"rugs.";"spal.";/
|
||||
"lapkr.";"gruod."
|
||||
alt_mon "sausis";/
|
||||
"vasaris";/
|
||||
"kovas";/
|
||||
|
||||
@@ -743,10 +743,22 @@ include "translit_wide";""
|
||||
<U263A> "<U003A><U0029>"
|
||||
% BLACK SMILING FACE
|
||||
<U263B> "<U003A><U0029>"
|
||||
% MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET⟫
|
||||
<U27EB> "<U003E><U003E>"
|
||||
% MATHEMATICAL LEFT WHITE SQUARE BRACKET
|
||||
<U27E6> "<U005B><U007C>"
|
||||
% MATHEMATICAL RIGHT WHITE SQUARE BRACKET
|
||||
<U27E7> "<U007C><U005D>"
|
||||
% MATHEMATICAL LEFT ANGLE BRACKET
|
||||
<U27E8> <U003C>
|
||||
% MATHEMATICAL RIGHT ANGLE BRACKET
|
||||
<U27E9> <U003E>
|
||||
% MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
|
||||
<U27EA> "<U003C><U003C>"
|
||||
% MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
|
||||
<U27EB> "<U003E><U003E>"
|
||||
% MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
|
||||
<U27EC> "<U0028><U0028>"
|
||||
% MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
|
||||
<U27ED> "<U0029><U0029>"
|
||||
% MATHEMATICAL LEFT FLATTENED PARENTHESIS
|
||||
<U27EE> <U0028>
|
||||
% MATHEMATICAL RIGHT FLATTENED PARENTHESIS
|
||||
@@ -755,6 +767,42 @@ include "translit_wide";""
|
||||
<U27CB> <U002F>
|
||||
% MATHEMATICAL FALLING DIAGONAL
|
||||
<U27CD> <U005C>
|
||||
% TRIPLE VERTICAL BAR DELIMITER
|
||||
<U2980> "<U007C><U007C><U007C>"
|
||||
% LEFT WHITE CURLY BRACKET
|
||||
<U2983> "<U007B><U007C>"
|
||||
% RIGHT WHITE CURLY BRACKET
|
||||
<U2984> "<U007C><U007D>"
|
||||
% LEFT WHITE PARENTHESIS
|
||||
<U2985> "<U0028><U0028>"
|
||||
% RIGHT WHITE PARENTHESIS
|
||||
<U2986> "<U0029><U0029>"
|
||||
% Z NOTATION LEFT IMAGE BRACKET
|
||||
<U2987> "<U0028><U007C>"
|
||||
% Z NOTATION RIGHT IMAGE BRACKET
|
||||
<U2988> "<U007C><U0029>"
|
||||
% Z NOTATION LEFT BINDING BRACKET
|
||||
<U2989> "<U003C><U007C>"
|
||||
% Z NOTATION RIGHT BINDING BRACKET
|
||||
<U298A> "<U007C><U003E>"
|
||||
% EQUALS SIGN AND SLANTED PARALLEL
|
||||
<U29E3> <U0023>
|
||||
% IDENTICAL TO AND SLANTED PARALLEL
|
||||
<U29E5> <U0023>
|
||||
% REVERSE SOLIDUS OPERATOR
|
||||
<U29F5> <U005C>
|
||||
% BIG SOLIDUS
|
||||
<U29F8> <U002F>
|
||||
% BIG REVERSE SOLIDUS
|
||||
<U29F9> <U005C>
|
||||
% LEFT-POINTING CURVED ANGLE BRACKET
|
||||
<U29FC> <U003C>
|
||||
% RIGHT-POINTING CURVED ANGLE BRACKET
|
||||
<U29FD> <U003E>
|
||||
% TINY
|
||||
<U29FE> <U002B>
|
||||
% MINY
|
||||
<U29FF> <U002D>
|
||||
% LEFT ANGLE BRACKET
|
||||
<U3008> <U003C>
|
||||
% RIGHT ANGLE BRACKET
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Test some mathematical operator transliterations (BZ #23132)
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <iconv.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
iconv_t cd;
|
||||
|
||||
/* str[] = "⟦ ⟧ ⟨ ⟩"
|
||||
" ⟬ ⟭ ⦀"
|
||||
" ⦃ ⦄ ⦅ ⦆"
|
||||
" ⦇ ⦈ ⦉ ⦊"
|
||||
" ⧣ ⧥ ⧵ ⧸ ⧹"
|
||||
" ⧼ ⧽ ⧾ ⧿"; */
|
||||
|
||||
const char str[] = "\u27E6 \u27E7 \u27E8 \u27E9"
|
||||
" \u27EC \u27ED \u2980"
|
||||
" \u2983 \u2984 \u2985 \u2986"
|
||||
" \u2987 \u2988 \u2989 \u298A"
|
||||
" \u29E3 \u29E5 \u29F5 \u29F8 \u29F9"
|
||||
" \u29FC \u29FD \u29FE \u29FF";
|
||||
|
||||
const char expected[] = "[| |] < >"
|
||||
" (( )) |||"
|
||||
" {| |} (( ))"
|
||||
" (| |) <| |>"
|
||||
" # # \\ / \\"
|
||||
" < > + -";
|
||||
|
||||
char *inptr = (char *) str;
|
||||
size_t inlen = strlen (str) + 1;
|
||||
char outbuf[500];
|
||||
char *outptr = outbuf;
|
||||
size_t outlen = sizeof (outbuf);
|
||||
int result = 0;
|
||||
size_t n;
|
||||
|
||||
if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
|
||||
FAIL_EXIT1 ("setlocale failed");
|
||||
|
||||
cd = iconv_open ("ASCII//TRANSLIT", "UTF-8");
|
||||
if (cd == (iconv_t) -1)
|
||||
FAIL_EXIT1 ("iconv_open failed");
|
||||
|
||||
n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
|
||||
if (n != 24)
|
||||
{
|
||||
if (n == (size_t) -1)
|
||||
printf ("iconv() returned error: %m\n");
|
||||
else
|
||||
printf ("iconv() returned %Zd, expected 24\n", n);
|
||||
result = 1;
|
||||
}
|
||||
if (inlen != 0)
|
||||
{
|
||||
puts ("not all input consumed");
|
||||
result = 1;
|
||||
}
|
||||
else if (inptr - str != strlen (str) + 1)
|
||||
{
|
||||
printf ("inptr wrong, advanced by %td\n", inptr - str);
|
||||
result = 1;
|
||||
}
|
||||
if (memcmp (outbuf, expected, sizeof (expected)) != 0)
|
||||
{
|
||||
printf ("result wrong: \"%.*s\", expected: \"%s\"\n",
|
||||
(int) (sizeof (outbuf) - outlen), outbuf, expected);
|
||||
result = 1;
|
||||
}
|
||||
else if (outlen != sizeof (outbuf) - sizeof (expected))
|
||||
{
|
||||
printf ("outlen wrong: %Zd, expected %Zd\n", outlen,
|
||||
sizeof (outbuf) - 15);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
printf ("output is \"%s\" which is OK\n", outbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -37,6 +37,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-malloc-tcache-leak \
|
||||
tst-malloc_info \
|
||||
tst-malloc-too-large \
|
||||
tst-tcfree1 tst-tcfree2 tst-tcfree3 \
|
||||
|
||||
tests-static := \
|
||||
tst-interpose-static-nothread \
|
||||
|
||||
+42
-50
@@ -2904,6 +2904,8 @@ mremap_chunk (mchunkptr p, size_t new_size)
|
||||
typedef struct tcache_entry
|
||||
{
|
||||
struct tcache_entry *next;
|
||||
/* This field exists to detect double frees. */
|
||||
struct tcache_perthread_struct *key;
|
||||
} tcache_entry;
|
||||
|
||||
/* There is one of these for each thread, which contains the
|
||||
@@ -2917,6 +2919,8 @@ typedef struct tcache_perthread_struct
|
||||
tcache_entry *entries[TCACHE_MAX_BINS];
|
||||
} tcache_perthread_struct;
|
||||
|
||||
#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */
|
||||
|
||||
static __thread bool tcache_shutting_down = false;
|
||||
static __thread tcache_perthread_struct *tcache = NULL;
|
||||
|
||||
@@ -2927,6 +2931,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
|
||||
{
|
||||
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
|
||||
assert (tc_idx < TCACHE_MAX_BINS);
|
||||
|
||||
/* Mark this chunk as "in the tcache" so the test in _int_free will
|
||||
detect a double free. */
|
||||
e->key = tcache;
|
||||
|
||||
e->next = tcache->entries[tc_idx];
|
||||
tcache->entries[tc_idx] = e;
|
||||
++(tcache->counts[tc_idx]);
|
||||
@@ -2942,6 +2951,7 @@ tcache_get (size_t tc_idx)
|
||||
assert (tcache->entries[tc_idx] > 0);
|
||||
tcache->entries[tc_idx] = e->next;
|
||||
--(tcache->counts[tc_idx]);
|
||||
e->key = NULL;
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
@@ -4165,13 +4175,33 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
#if USE_TCACHE
|
||||
{
|
||||
size_t tc_idx = csize2tidx (size);
|
||||
|
||||
if (tcache
|
||||
&& tc_idx < mp_.tcache_bins
|
||||
&& tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
if (tcache != NULL && tc_idx < mp_.tcache_bins)
|
||||
{
|
||||
tcache_put (p, tc_idx);
|
||||
return;
|
||||
/* Check to see if it's already in the tcache. */
|
||||
tcache_entry *e = (tcache_entry *) chunk2mem (p);
|
||||
|
||||
/* This test succeeds on double free. However, we don't 100%
|
||||
trust it (it also matches random payload data at a 1 in
|
||||
2^<size_t> chance), so verify it's not an unlikely
|
||||
coincidence before aborting. */
|
||||
if (__glibc_unlikely (e->key == tcache))
|
||||
{
|
||||
tcache_entry *tmp;
|
||||
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
|
||||
for (tmp = tcache->entries[tc_idx];
|
||||
tmp;
|
||||
tmp = tmp->next)
|
||||
if (tmp == e)
|
||||
malloc_printerr ("free(): double free detected in tcache 2");
|
||||
/* If we get here, it was a coincidence. We've wasted a
|
||||
few cycles, but don't abort. */
|
||||
}
|
||||
|
||||
if (tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
{
|
||||
tcache_put (p, tc_idx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -4512,11 +4542,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
|
||||
mchunkptr bck; /* misc temp for linking */
|
||||
mchunkptr fwd; /* misc temp for linking */
|
||||
|
||||
unsigned long copysize; /* bytes to copy */
|
||||
unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */
|
||||
INTERNAL_SIZE_T* s; /* copy source */
|
||||
INTERNAL_SIZE_T* d; /* copy destination */
|
||||
|
||||
/* oldmem size */
|
||||
if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0)
|
||||
|| __builtin_expect (oldsize >= av->system_mem, 0))
|
||||
@@ -4584,43 +4609,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Unroll copy of <= 36 bytes (72 if 8byte sizes)
|
||||
We know that contents have an odd number of
|
||||
INTERNAL_SIZE_T-sized words; minimally 3.
|
||||
*/
|
||||
|
||||
copysize = oldsize - SIZE_SZ;
|
||||
s = (INTERNAL_SIZE_T *) (chunk2mem (oldp));
|
||||
d = (INTERNAL_SIZE_T *) (newmem);
|
||||
ncopies = copysize / sizeof (INTERNAL_SIZE_T);
|
||||
assert (ncopies >= 3);
|
||||
|
||||
if (ncopies > 9)
|
||||
memcpy (d, s, copysize);
|
||||
|
||||
else
|
||||
{
|
||||
*(d + 0) = *(s + 0);
|
||||
*(d + 1) = *(s + 1);
|
||||
*(d + 2) = *(s + 2);
|
||||
if (ncopies > 4)
|
||||
{
|
||||
*(d + 3) = *(s + 3);
|
||||
*(d + 4) = *(s + 4);
|
||||
if (ncopies > 6)
|
||||
{
|
||||
*(d + 5) = *(s + 5);
|
||||
*(d + 6) = *(s + 6);
|
||||
if (ncopies > 8)
|
||||
{
|
||||
*(d + 7) = *(s + 7);
|
||||
*(d + 8) = *(s + 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (newmem, chunk2mem (oldp), oldsize - SIZE_SZ);
|
||||
_int_free (av, oldp, 1);
|
||||
check_inuse_chunk (av, newp);
|
||||
return chunk2mem (newp);
|
||||
@@ -5118,8 +5107,11 @@ static inline int
|
||||
__always_inline
|
||||
do_set_tcache_count (size_t value)
|
||||
{
|
||||
LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
|
||||
mp_.tcache_count = value;
|
||||
if (value <= MAX_TCACHE_COUNT)
|
||||
{
|
||||
LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
|
||||
mp_.tcache_count = value;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Test that malloc tcache catches double free.
|
||||
Copyright (C) 2018 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/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <limits.h>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Do one allocation of any size that fits in tcache. */
|
||||
char * volatile x = malloc (32);
|
||||
|
||||
free (x); // puts in tcache
|
||||
free (x); // should abort
|
||||
|
||||
printf("FAIL: tcache double free not detected\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test
|
||||
#define EXPECTED_SIGNAL SIGABRT
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Test that malloc tcache catches double free.
|
||||
Copyright (C) 2018 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/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <limits.h>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char * volatile ptrs[20];
|
||||
int i;
|
||||
|
||||
/* Allocate enough small chunks so that when we free them all, the tcache
|
||||
is full, and the first one we freed is at the end of its linked list. */
|
||||
#define COUNT 20
|
||||
for (i=0; i<COUNT; i++)
|
||||
ptrs[i] = malloc (20);
|
||||
for (i=0; i<COUNT; i++)
|
||||
free (ptrs[i]);
|
||||
free (ptrs[0]);
|
||||
|
||||
printf("FAIL: tcache double free\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test
|
||||
#define EXPECTED_SIGNAL SIGABRT
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Test that malloc tcache catches double free.
|
||||
Copyright (C) 2018 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/>. */
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Prevent GCC from optimizing away any malloc/free pairs. */
|
||||
#pragma GCC optimize ("O0")
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Do two allocation of any size that fit in tcache, and one that
|
||||
doesn't. */
|
||||
int ** volatile a = malloc (32);
|
||||
int ** volatile b = malloc (32);
|
||||
/* This is just under the mmap threshold. */
|
||||
int ** volatile c = malloc (127 * 1024);
|
||||
|
||||
/* The invalid "tcache bucket" we might dereference will likely end
|
||||
up somewhere within this memory block, so make all the accidental
|
||||
"next" pointers cause segfaults. BZ #23907. */
|
||||
memset (c, 0xff, 127 * 1024);
|
||||
|
||||
free (a); // puts in tcache
|
||||
|
||||
/* A is now free and contains the key we use to detect in-tcache.
|
||||
Copy the key to the other chunks. */
|
||||
memcpy (b, a, 32);
|
||||
memcpy (c, a, 32);
|
||||
|
||||
/* This free tests the "are we in the tcache already" loop with a
|
||||
VALID bin but "coincidental" matching key. */
|
||||
free (b); // should NOT abort
|
||||
/* This free tests the "is it a valid tcache bin" test. */
|
||||
free (c); // should NOT abort
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+40
-52
@@ -643,8 +643,8 @@ and they also do not require it to be in the initial state.
|
||||
@cindex stateful
|
||||
The @code{mbrtowc} function (``multibyte restartable to wide
|
||||
character'') converts the next multibyte character in the string pointed
|
||||
to by @var{s} into a wide character and stores it in the wide character
|
||||
string pointed to by @var{pwc}. The conversion is performed according
|
||||
to by @var{s} into a wide character and stores it in the location
|
||||
pointed to by @var{pwc}. The conversion is performed according
|
||||
to the locale currently selected for the @code{LC_CTYPE} category. If
|
||||
the conversion for the character set used in the locale requires a state,
|
||||
the multibyte string is interpreted in the state represented by the
|
||||
@@ -652,7 +652,7 @@ object pointed to by @var{ps}. If @var{ps} is a null pointer, a static,
|
||||
internal state variable used only by the @code{mbrtowc} function is
|
||||
used.
|
||||
|
||||
If the next multibyte character corresponds to the NUL wide character,
|
||||
If the next multibyte character corresponds to the null wide character,
|
||||
the return value of the function is @math{0} and the state object is
|
||||
afterwards in the initial state. If the next @var{n} or fewer bytes
|
||||
form a correct multibyte character, the return value is the number of
|
||||
@@ -665,71 +665,59 @@ by @var{pwc} if @var{pwc} is not null.
|
||||
If the first @var{n} bytes of the multibyte string possibly form a valid
|
||||
multibyte character but there are more than @var{n} bytes needed to
|
||||
complete it, the return value of the function is @code{(size_t) -2} and
|
||||
no value is stored. Please note that this can happen even if @var{n}
|
||||
has a value greater than or equal to @code{MB_CUR_MAX} since the input
|
||||
might contain redundant shift sequences.
|
||||
no value is stored in @code{*@var{pwc}}. The conversion state is
|
||||
updated and all @var{n} input bytes are consumed and should not be
|
||||
submitted again. Please note that this can happen even if @var{n} has a
|
||||
value greater than or equal to @code{MB_CUR_MAX} since the input might
|
||||
contain redundant shift sequences.
|
||||
|
||||
If the first @code{n} bytes of the multibyte string cannot possibly form
|
||||
a valid multibyte character, no value is stored, the global variable
|
||||
@code{errno} is set to the value @code{EILSEQ}, and the function returns
|
||||
@code{(size_t) -1}. The conversion state is afterwards undefined.
|
||||
|
||||
As specified, the @code{mbrtowc} function could deal with multibyte
|
||||
sequences which contain embedded null bytes (which happens in Unicode
|
||||
encodings such as UTF-16), but @theglibc{} does not support such
|
||||
multibyte encodings. When encountering a null input byte, the function
|
||||
will either return zero, or return @code{(size_t) -1)} and report a
|
||||
@code{EILSEQ} error. The @code{iconv} function can be used for
|
||||
converting between arbitrary encodings. @xref{Generic Conversion
|
||||
Interface}.
|
||||
|
||||
@pindex wchar.h
|
||||
@code{mbrtowc} was introduced in @w{Amendment 1} to @w{ISO C90} and
|
||||
is declared in @file{wchar.h}.
|
||||
@end deftypefun
|
||||
|
||||
Use of @code{mbrtowc} is straightforward. A function that copies a
|
||||
multibyte string into a wide character string while at the same time
|
||||
converting all lowercase characters into uppercase could look like this
|
||||
(this is not the final version, just an example; it has no error
|
||||
checking, and sometimes leaks memory):
|
||||
A function that copies a multibyte string into a wide character string
|
||||
while at the same time converting all lowercase characters into
|
||||
uppercase could look like this:
|
||||
|
||||
@smallexample
|
||||
wchar_t *
|
||||
mbstouwcs (const char *s)
|
||||
@{
|
||||
size_t len = strlen (s);
|
||||
wchar_t *result = malloc ((len + 1) * sizeof (wchar_t));
|
||||
wchar_t *wcp = result;
|
||||
wchar_t tmp[1];
|
||||
mbstate_t state;
|
||||
size_t nbytes;
|
||||
|
||||
memset (&state, '\0', sizeof (state));
|
||||
while ((nbytes = mbrtowc (tmp, s, len, &state)) > 0)
|
||||
@{
|
||||
if (nbytes >= (size_t) -2)
|
||||
/* Invalid input string. */
|
||||
return NULL;
|
||||
*wcp++ = towupper (tmp[0]);
|
||||
len -= nbytes;
|
||||
s += nbytes;
|
||||
@}
|
||||
return result;
|
||||
@}
|
||||
@include mbstouwcs.c.texi
|
||||
@end smallexample
|
||||
|
||||
The use of @code{mbrtowc} should be clear. A single wide character is
|
||||
stored in @code{@var{tmp}[0]}, and the number of consumed bytes is stored
|
||||
in the variable @var{nbytes}. If the conversion is successful, the
|
||||
uppercase variant of the wide character is stored in the @var{result}
|
||||
array and the pointer to the input string and the number of available
|
||||
bytes is adjusted.
|
||||
In the inner loop, a single wide character is stored in @code{wc}, and
|
||||
the number of consumed bytes is stored in the variable @code{nbytes}.
|
||||
If the conversion is successful, the uppercase variant of the wide
|
||||
character is stored in the @code{result} array and the pointer to the
|
||||
input string and the number of available bytes is adjusted. If the
|
||||
@code{mbrtowc} function returns zero, the null input byte has not been
|
||||
converted, so it must be stored explicitly in the result.
|
||||
|
||||
The only non-obvious thing about @code{mbrtowc} might be the way memory
|
||||
is allocated for the result. The above code uses the fact that there
|
||||
can never be more wide characters in the converted result than there are
|
||||
bytes in the multibyte input string. This method yields a pessimistic
|
||||
guess about the size of the result, and if many wide character strings
|
||||
have to be constructed this way or if the strings are long, the extra
|
||||
memory required to be allocated because the input string contains
|
||||
multibyte characters might be significant. The allocated memory block can
|
||||
be resized to the correct size before returning it, but a better solution
|
||||
might be to allocate just the right amount of space for the result right
|
||||
away. Unfortunately there is no function to compute the length of the wide
|
||||
character string directly from the multibyte string. There is, however, a
|
||||
function that does part of the work.
|
||||
The above code uses the fact that there can never be more wide
|
||||
characters in the converted result than there are bytes in the multibyte
|
||||
input string. This method yields a pessimistic guess about the size of
|
||||
the result, and if many wide character strings have to be constructed
|
||||
this way or if the strings are long, the extra memory required to be
|
||||
allocated because the input string contains multibyte characters might
|
||||
be significant. The allocated memory block can be resized to the
|
||||
correct size before returning it, but a better solution might be to
|
||||
allocate just the right amount of space for the result right away.
|
||||
Unfortunately there is no function to compute the length of the wide
|
||||
character string directly from the multibyte string. There is, however,
|
||||
a function that does part of the work.
|
||||
|
||||
@deftypefun size_t mbrlen (const char *restrict @var{s}, size_t @var{n}, mbstate_t *@var{ps})
|
||||
@standards{ISO, wchar.h}
|
||||
|
||||
+41
-7
@@ -8,7 +8,7 @@ is controlled by which @dfn{feature test macros} you define.
|
||||
If you compile your programs using @samp{gcc -ansi}, you get only the
|
||||
@w{ISO C} library features, unless you explicitly request additional
|
||||
features by defining one or more of the feature macros.
|
||||
@xref{Invoking GCC,, GNU CC Command Options, gcc.info, The GNU CC Manual},
|
||||
@xref{Invoking GCC,, GNU CC Command Options, gcc, The GNU CC Manual},
|
||||
for more information about GCC options.@refill
|
||||
|
||||
You should define these macros by using @samp{#define} preprocessor
|
||||
@@ -61,13 +61,27 @@ If you define this macro to a value greater than or equal to @code{199309L},
|
||||
then the functionality from the 1993 edition of the POSIX.1b standard
|
||||
(IEEE Standard 1003.1b-1993) is made available.
|
||||
|
||||
If you define this macro to a value greater than or equal to
|
||||
@code{199506L}, then the functionality from the 1995 edition of the
|
||||
POSIX.1c standard (IEEE Standard 1003.1c-1995) is made available.
|
||||
|
||||
If you define this macro to a value greater than or equal to
|
||||
@code{200112L}, then the functionality from the 2001 edition of the
|
||||
POSIX standard (IEEE Standard 1003.1-2001) is made available.
|
||||
|
||||
If you define this macro to a value greater than or equal to
|
||||
@code{200809L}, then the functionality from the 2008 edition of the
|
||||
POSIX standard (IEEE Standard 1003.1-2008) is made available.
|
||||
|
||||
Greater values for @code{_POSIX_C_SOURCE} will enable future extensions.
|
||||
The POSIX standards process will define these values as necessary, and
|
||||
@theglibc{} should support them some time after they become standardized.
|
||||
The 1996 edition of POSIX.1 (ISO/IEC 9945-1: 1996) states that
|
||||
if you define @code{_POSIX_C_SOURCE} to a value greater than
|
||||
or equal to @code{199506L}, then the functionality from the 1996
|
||||
edition is made available.
|
||||
edition is made available. In general, in @theglibc{}, bugfixes to
|
||||
the standards are included when specifying the base version; e.g.,
|
||||
POSIX.1-2004 will always be included with a value of @code{200112L}.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro _XOPEN_SOURCE
|
||||
@@ -87,7 +101,10 @@ available which are necessary for the X/Open Unix brand.
|
||||
|
||||
If the macro @code{_XOPEN_SOURCE} has the value @math{500} this includes
|
||||
all functionality described so far plus some new definitions from the
|
||||
Single Unix Specification, @w{version 2}.
|
||||
Single Unix Specification, @w{version 2}. The value @math{600}
|
||||
(corresponding to the sixth revision) includes definitions from SUSv3,
|
||||
and using @math{700} (the seventh revision) includes definitions from
|
||||
SUSv4.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro _LARGEFILE_SOURCE
|
||||
@@ -150,10 +167,14 @@ This macro was introduced as part of the Large File Support extension
|
||||
|
||||
@defvr Macro _ISOC99_SOURCE
|
||||
@standards{GNU, (none)}
|
||||
Until the revised @w{ISO C} standard is widely adopted the new features
|
||||
are not automatically enabled. @Theglibc{} nevertheless has a complete
|
||||
implementation of the new standard and to enable the new features the
|
||||
macro @code{_ISOC99_SOURCE} should be defined.
|
||||
If this macro is defined, features from ISO C99 are included. Since
|
||||
these features are included by default, this macro is mostly relevant
|
||||
when the compiler uses an earlier language version.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro _ISOC11_SOURCE
|
||||
@standards{C11, (none)}
|
||||
If this macro is defined, ISO C11 extensions to ISO C99 are included.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro __STDC_WANT_LIB_EXT2__
|
||||
@@ -209,6 +230,19 @@ enables those features even when the other options would otherwise
|
||||
cause them to be disabled.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro _ATFILE_SOURCE
|
||||
@standards{GNU, (none)}
|
||||
If this macro is defined, additional @code{*at} interfaces are
|
||||
included.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro _FORTIFY_SOURCE
|
||||
@standards{GNU, (none)}
|
||||
If this macro is defined to @math{1}, security hardening is added to
|
||||
various library functions. If defined to @math{2}, even stricter
|
||||
checks are applied.
|
||||
@end defvr
|
||||
|
||||
@defvr Macro _REENTRANT
|
||||
@defvrx Macro _THREAD_SAFE
|
||||
@standards{Obsolete, (none)}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
/* Do not include the above headers in the example.
|
||||
*/
|
||||
wchar_t *
|
||||
mbstouwcs (const char *s)
|
||||
{
|
||||
/* Include the null terminator in the conversion. */
|
||||
size_t len = strlen (s) + 1;
|
||||
wchar_t *result = reallocarray (NULL, len, sizeof (wchar_t));
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
wchar_t *wcp = result;
|
||||
mbstate_t state;
|
||||
memset (&state, '\0', sizeof (state));
|
||||
|
||||
while (true)
|
||||
{
|
||||
wchar_t wc;
|
||||
size_t nbytes = mbrtowc (&wc, s, len, &state);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
/* Terminate the result string. */
|
||||
*wcp = L'\0';
|
||||
break;
|
||||
}
|
||||
else if (nbytes == (size_t) -2)
|
||||
{
|
||||
/* Truncated input string. */
|
||||
errno = EILSEQ;
|
||||
free (result);
|
||||
return NULL;
|
||||
}
|
||||
else if (nbytes == (size_t) -1)
|
||||
{
|
||||
/* Some other error (including EILSEQ). */
|
||||
free (result);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A character was converted. */
|
||||
*wcp++ = towupper (wc);
|
||||
len -= nbytes;
|
||||
s += nbytes;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
+9
-8
@@ -147,19 +147,20 @@ necessarily enough space to contain the directory name. That is why
|
||||
this function is deprecated.
|
||||
@end deftypefn
|
||||
|
||||
@vindex PWD
|
||||
@deftypefun {char *} get_current_dir_name (void)
|
||||
@standards{GNU, unistd.h}
|
||||
@safety{@prelim{}@mtsafe{@mtsenv{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{} @acsfd{}}}
|
||||
@c Besides getcwd, which this function calls as a fallback, it calls
|
||||
@c getenv, with the potential thread-safety issues that brings about.
|
||||
@vindex PWD
|
||||
This @code{get_current_dir_name} function is basically equivalent to
|
||||
@w{@code{getcwd (NULL, 0)}}. The only difference is that the value of
|
||||
the @code{PWD} variable is returned if this value is correct. This is a
|
||||
subtle difference which is visible if the path described by the
|
||||
@code{PWD} value is using one or more symbol links in which case the
|
||||
value returned by @code{getcwd} can resolve the symbol links and
|
||||
therefore yield a different result.
|
||||
The @code{get_current_dir_name} function is basically equivalent to
|
||||
@w{@code{getcwd (NULL, 0)}}, except the value of the @env{PWD}
|
||||
environment variable is first examined, and if it does in fact
|
||||
correspond to the current directory, that value is returned. This is
|
||||
a subtle difference which is visible if the path described by the
|
||||
value in @env{PWD} is using one or more symbolic links, in which case
|
||||
the value returned by @code{getcwd} would resolve the symbolic links
|
||||
and therefore yield a different result.
|
||||
|
||||
This function is a GNU extension.
|
||||
@end deftypefun
|
||||
|
||||
+22
-12
@@ -1251,9 +1251,13 @@ When the source file is compiled using @code{_FILE_OFFSET_BITS == 64} on a
|
||||
@c This is a syscall for Linux v4.6. The sysdeps/posix fallback emulation
|
||||
@c is also MT-Safe since it calls preadv.
|
||||
|
||||
This function is similar to the @code{preadv} function, with the difference
|
||||
it adds an extra @var{flags} parameter of type @code{int}. The supported
|
||||
@var{flags} are dependent of the underlying system. For Linux it supports:
|
||||
This function is similar to the @code{preadv} function, with the
|
||||
difference it adds an extra @var{flags} parameter of type @code{int}.
|
||||
Additionally, if @var{offset} is @math{-1}, the current file position
|
||||
is used and updated (like the @code{readv} function).
|
||||
|
||||
The supported @var{flags} are dependent of the underlying system. For
|
||||
Linux it supports:
|
||||
|
||||
@vtable @code
|
||||
@item RWF_HIPRI
|
||||
@@ -1271,6 +1275,9 @@ Per-IO synchronization as if the file was opened with @code{O_SYNC} flag.
|
||||
@item RWF_NOWAIT
|
||||
Use nonblocking mode for this operation; that is, this call to @code{preadv2}
|
||||
will fail and set @code{errno} to @code{EAGAIN} if the operation would block.
|
||||
|
||||
@item RWF_APPEND
|
||||
Per-IO synchronization as if the file was opened with @code{O_APPEND} flag.
|
||||
@end vtable
|
||||
|
||||
When the source file is compiled with @code{_FILE_OFFSET_BITS == 64} the
|
||||
@@ -1320,10 +1327,13 @@ When the source file is compiled using @code{_FILE_OFFSET_BITS == 64} on a
|
||||
@c This is a syscall for Linux v4.6. The sysdeps/posix fallback emulation
|
||||
@c is also MT-Safe since it calls pwritev.
|
||||
|
||||
This function is similar to the @code{pwritev} function, with the difference
|
||||
it adds an extra @var{flags} parameter of type @code{int}. The supported
|
||||
@var{flags} are dependent of the underlying system and for Linux it supports
|
||||
the same ones as for @code{preadv2}.
|
||||
This function is similar to the @code{pwritev} function, with the
|
||||
difference it adds an extra @var{flags} parameter of type @code{int}.
|
||||
Additionally, if @var{offset} is @math{-1}, the current file position
|
||||
should is used and updated (like the @code{writev} function).
|
||||
|
||||
The supported @var{flags} are dependent of the underlying system. For
|
||||
Linux, the supported flags are the same as those for @code{preadv2}.
|
||||
|
||||
When the source file is compiled with @code{_FILE_OFFSET_BITS == 64} the
|
||||
@code{pwritev2} function is in fact @code{pwritev64v2} and the type
|
||||
@@ -1394,10 +1404,13 @@ failure occurs. The return value is zero if the end of the input file
|
||||
is encountered immediately.
|
||||
|
||||
If no bytes can be copied, to report an error, @code{copy_file_range}
|
||||
returns the value @math{-1} and sets @code{errno}. The following
|
||||
@code{errno} error conditions are specific to this function:
|
||||
returns the value @math{-1} and sets @code{errno}. The table below
|
||||
lists some of the error conditions for this function.
|
||||
|
||||
@table @code
|
||||
@item ENOSYS
|
||||
The kernel does not implement the required functionality.
|
||||
|
||||
@item EISDIR
|
||||
At least one of the descriptors @var{inputfd} or @var{outputfd} refers
|
||||
to a directory.
|
||||
@@ -1427,9 +1440,6 @@ reading.
|
||||
|
||||
The argument @var{outputfd} is not a valid file descriptor open for
|
||||
writing, or @var{outputfd} has been opened with @code{O_APPEND}.
|
||||
|
||||
@item EXDEV
|
||||
The input and output files reside on different file systems.
|
||||
@end table
|
||||
|
||||
In addition, @code{copy_file_range} can fail with the error codes
|
||||
|
||||
@@ -123,7 +123,7 @@ when it is not allowed, the priority is set to medium.
|
||||
Cache management facilities specific to RISC-V systems that implement the Linux
|
||||
ABI are declared in @file{sys/cachectl.h}.
|
||||
|
||||
@deftypefun {void} __riscv_flush_icache(void *@var{start}, void *@var{end}, unsigned long int @var{flags})
|
||||
@deftypefun {void} __riscv_flush_icache (void *@var{start}, void *@var{end}, unsigned long int @var{flags})
|
||||
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||
Enforce ordering between stores and instruction cache fetches. The range of
|
||||
addresses over which ordering is enforced is specified by @var{start} and
|
||||
|
||||
@@ -243,6 +243,18 @@ This probe is triggered when the
|
||||
value of this tunable.
|
||||
@end deftp
|
||||
|
||||
@deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2})
|
||||
This probe is triggered when @code{free} determines that the memory
|
||||
being freed has probably already been freed, and resides in the
|
||||
per-thread cache. Note that there is an extremely unlikely chance
|
||||
that this probe will trigger due to random payload data remaining in
|
||||
the allocated memory matching the key used to detect double frees.
|
||||
This probe actually indicates that an expensive linear search of the
|
||||
tcache, looking for a double free, has happened. Argument @var{$arg1}
|
||||
is the memory location as passed to @code{free}, Argument @var{$arg2}
|
||||
is the tcache bin it resides in.
|
||||
@end deftp
|
||||
|
||||
@node Mathematical Function Probes
|
||||
@section Mathematical Function Probes
|
||||
|
||||
|
||||
+4
-4
@@ -1808,7 +1808,7 @@ verifies that the correct number and types of arguments are supplied.
|
||||
There is also a GNU C syntax to tell the compiler that a function you
|
||||
write uses a @code{printf}-style format string.
|
||||
@xref{Function Attributes, , Declaring Attributes of Functions,
|
||||
gcc.info, Using GNU CC}, for more information.
|
||||
gcc, Using GNU CC}, for more information.
|
||||
|
||||
@node Table of Output Conversions
|
||||
@subsection Table of Output Conversions
|
||||
@@ -2730,7 +2730,7 @@ This tells the compiler that @code{eprintf} uses a format string like
|
||||
the format string appears as the first argument;
|
||||
and the arguments to satisfy the format begin with the second.
|
||||
@xref{Function Attributes, , Declaring Attributes of Functions,
|
||||
gcc.info, Using GNU CC}, for more information.
|
||||
gcc, Using GNU CC}, for more information.
|
||||
|
||||
@node Parsing a Template String
|
||||
@subsection Parsing a Template String
|
||||
@@ -3478,7 +3478,7 @@ verifies that the correct number and types of arguments are supplied.
|
||||
There is also a GNU C syntax to tell the compiler that a function you
|
||||
write uses a @code{scanf}-style format string.
|
||||
@xref{Function Attributes, , Declaring Attributes of Functions,
|
||||
gcc.info, Using GNU CC}, for more information.
|
||||
gcc, Using GNU CC}, for more information.
|
||||
|
||||
@node Table of Input Conversions
|
||||
@subsection Table of Input Conversions
|
||||
@@ -4033,7 +4033,7 @@ know that a function uses a @code{scanf}-style format string. Then it
|
||||
can check the number and types of arguments in each call to the
|
||||
function, and warn you when they do not match the format string.
|
||||
For details, see @ref{Function Attributes, , Declaring Attributes of Functions,
|
||||
gcc.info, Using GNU CC}.
|
||||
gcc, Using GNU CC}.
|
||||
|
||||
@node EOF and Errors
|
||||
@section End-Of-File and Errors
|
||||
|
||||
+1
-1
@@ -1087,7 +1087,7 @@ are often easier and safer automatic techniques that cause buffer
|
||||
overruns to reliably terminate a program, such as GCC's
|
||||
@option{-fcheck-pointer-bounds} and @option{-fsanitize=address}
|
||||
options. @xref{Debugging Options,, Options for Debugging Your Program
|
||||
or GCC, gcc.info, Using GCC}. Because truncation functions can mask
|
||||
or GCC, gcc, Using GCC}. Because truncation functions can mask
|
||||
application bugs that would otherwise be caught by the automatic
|
||||
techniques, these functions should be used only when the application's
|
||||
underlying logic requires truncation.
|
||||
|
||||
@@ -188,8 +188,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on
|
||||
|
||||
@deftp Tunable glibc.malloc.tcache_count
|
||||
The maximum number of chunks of each size to cache. The default is 7.
|
||||
There is no upper limit, other than available system memory. If set
|
||||
to zero, the per-thread cache is effectively disabled.
|
||||
The upper limit is 127. If set to zero, the per-thread cache is effectively
|
||||
disabled.
|
||||
|
||||
The approximate maximum overhead of the per-thread cache is thus equal
|
||||
to the number of bins times the chunk count in each bin times the size
|
||||
@@ -333,7 +333,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le.
|
||||
The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to
|
||||
assume that the CPU is @code{xxx} where xxx may have one of these values:
|
||||
@code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99},
|
||||
@code{thunderx2t99p1}.
|
||||
@code{thunderx2t99p1}, @code{ares}.
|
||||
|
||||
This tunable is specific to aarch64.
|
||||
@end deftp
|
||||
|
||||
+1
-1
@@ -1223,7 +1223,7 @@ template<> struct __iseqsig_type<double>
|
||||
|
||||
template<> struct __iseqsig_type<long double>
|
||||
{
|
||||
static int __call (double __x, double __y) throw ()
|
||||
static int __call (long double __x, long double __y) throw ()
|
||||
{
|
||||
# ifndef __NO_LONG_DOUBLE_MATH
|
||||
return __iseqsigl (__x, __y);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <array_length.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
static char *temp_filename;
|
||||
static int temp_fd;
|
||||
@@ -50,6 +52,42 @@ do_prepare (int argc, char **argv)
|
||||
pwritev (__fd, __iov, __iovcnt, __offset)
|
||||
#endif
|
||||
|
||||
static __attribute__ ((unused)) void
|
||||
do_test_without_offset (void)
|
||||
{
|
||||
xftruncate (temp_fd, 0);
|
||||
|
||||
xwrite (temp_fd, "123", 3);
|
||||
xlseek (temp_fd, 2, SEEK_SET);
|
||||
{
|
||||
struct iovec iov[] =
|
||||
{
|
||||
{ (void *) "abc", 3 },
|
||||
{ (void *) "xyzt", 4 },
|
||||
};
|
||||
TEST_COMPARE (PWRITEV (temp_fd, iov, array_length (iov), -1), 7);
|
||||
}
|
||||
TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 9);
|
||||
|
||||
xlseek (temp_fd, 1, SEEK_SET);
|
||||
char buf1[3];
|
||||
char buf2[2];
|
||||
{
|
||||
struct iovec iov[] =
|
||||
{
|
||||
{ buf1, sizeof (buf1) },
|
||||
{ buf2, sizeof (buf2) },
|
||||
};
|
||||
TEST_COMPARE (PREADV (temp_fd, iov, array_length (iov), -1),
|
||||
sizeof (buf1) + sizeof (buf2));
|
||||
TEST_COMPARE (memcmp ("2ab", buf1, sizeof (buf1)), 0);
|
||||
TEST_COMPARE (memcmp ("cx", buf2, sizeof (buf2)), 0);
|
||||
TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 6);
|
||||
}
|
||||
|
||||
xftruncate (temp_fd, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test_with_offset (off_t offset)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user