mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 11:58:23 +08:00
Compare commits
101
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9277192e15 | ||
|
|
353f79819c | ||
|
|
e1c67173bf | ||
|
|
d701c3a0a5 | ||
|
|
19d0f70b08 | ||
|
|
b95393ecb5 | ||
|
|
79ab0fcfda | ||
|
|
882f407875 | ||
|
|
a998069c80 | ||
|
|
85ea40f66d | ||
|
|
b6099fb5b2 | ||
|
|
929275c193 | ||
|
|
ad9d6e1dbe | ||
|
|
74b27c48cb | ||
|
|
f01f990def | ||
|
|
c0872d83ef | ||
|
|
30bb510293 | ||
|
|
bdf9cbb2db | ||
|
|
a39e9f7a23 | ||
|
|
a48e32ee70 | ||
|
|
c93632edca | ||
|
|
000f2cf415 | ||
|
|
409bde58fe | ||
|
|
74df977401 | ||
|
|
bab244a006 | ||
|
|
fa9a6cbaea | ||
|
|
587c53b344 | ||
|
|
f495bb0484 | ||
|
|
0428bae673 | ||
|
|
2387d2fc7c | ||
|
|
497c190870 | ||
|
|
14cfc78089 | ||
|
|
bbffc56aa5 | ||
|
|
107aed9f2b | ||
|
|
b1342139cd | ||
|
|
db2523b0da | ||
|
|
5ccef4d197 | ||
|
|
4be23b8484 | ||
|
|
e52611a110 | ||
|
|
b2b6bfcde6 | ||
|
|
3532d2e2bc | ||
|
|
d1c2791a63 | ||
|
|
1153d5eaf4 | ||
|
|
10d353539f | ||
|
|
e19fc0ea57 | ||
|
|
2963bd873f | ||
|
|
d37331c9ef | ||
|
|
daee27e94c | ||
|
|
1d1e0535b6 | ||
|
|
13e6e91707 | ||
|
|
cc586e77cf | ||
|
|
c4273619e1 | ||
|
|
98337c55db | ||
|
|
69f4e2a55d | ||
|
|
a0db2d6209 | ||
|
|
4ddf6cb7a6 | ||
|
|
007f8306a3 | ||
|
|
95d48c5aea | ||
|
|
c88182c608 | ||
|
|
85a9363da4 | ||
|
|
5025db781e | ||
|
|
b0da5c6e78 | ||
|
|
7241b75ecc | ||
|
|
fa5cf22b84 | ||
|
|
ed6d472ee9 | ||
|
|
ecce267984 | ||
|
|
e5e5c541b5 | ||
|
|
1ecb690ee6 | ||
|
|
ae4d5ce7de | ||
|
|
e2172e072d | ||
|
|
17c46147bc | ||
|
|
05fc85cb17 | ||
|
|
b24016d7ef | ||
|
|
3a16b5db47 | ||
|
|
4e6b7daedf | ||
|
|
9fc67c6aa6 | ||
|
|
a17c57fab6 | ||
|
|
c6679b5e43 | ||
|
|
ad06b0b3fb | ||
|
|
33838f184a | ||
|
|
bd853af031 | ||
|
|
630cc91e1b | ||
|
|
f5f58a704c | ||
|
|
63473c3676 | ||
|
|
283b5c7b39 | ||
|
|
4e73acc04a | ||
|
|
3fae2a38f8 | ||
|
|
cdaac281f2 | ||
|
|
2fc36ac70a | ||
|
|
7da5656bd2 | ||
|
|
ada1223ac9 | ||
|
|
ae1a407796 | ||
|
|
8623844f33 | ||
|
|
dc8069787a | ||
|
|
3ba0025a84 | ||
|
|
019516567f | ||
|
|
7839c2120f | ||
|
|
b117857fe2 | ||
|
|
9949268a53 | ||
|
|
949ad730d5 | ||
|
|
09ac904b12 |
@@ -458,8 +458,8 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
|
||||
$(LINK.o) -shared -Wl,-O1 \
|
||||
-nostdlib -nostartfiles \
|
||||
$(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \
|
||||
-Wl,--verbose 2>&1 | \
|
||||
sed > $@T \
|
||||
-Wl,--verbose 2>&1 >$@-tmp
|
||||
sed $@-tmp > $@T \
|
||||
-e '/^=========/,/^=========/!d;/^=========/d' \
|
||||
$(if $(filter yes,$(have-hash-style)), \
|
||||
-e 's/^.*\.gnu\.hash[ ]*:.*$$/ .note.ABI-tag : { *(.note.ABI-tag) } &/' \
|
||||
@@ -958,9 +958,9 @@ $(inst_libdir)/libc.so: $(common-objpfx)format.lds \
|
||||
echo ' Use the shared library, but some functions are only in';\
|
||||
echo ' the static library, so try that secondarily. */';\
|
||||
cat $<; \
|
||||
echo 'GROUP ( $(slibdir)/libc.so$(libc.so-version)' \
|
||||
'$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)$(libc-name))'\
|
||||
' AS_NEEDED (' $(rtlddir)/$(rtld-installed-name) ') )' \
|
||||
echo 'GROUP ( libc.so$(libc.so-version)' \
|
||||
'$(patsubst %,$(libtype.oS),$(libprefix)$(libc-name))'\
|
||||
' AS_NEEDED (' $(rtld-installed-name) ') )' \
|
||||
) > $@.new
|
||||
mv -f $@.new $@
|
||||
|
||||
@@ -1256,7 +1256,8 @@ endif
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
ifdef subdir
|
||||
tests: check-abi
|
||||
# Temporarily disable check-abi: http://b/13350520
|
||||
# tests: check-abi
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
+703
@@ -0,0 +1,703 @@
|
||||
Patches applied to glibc-2.19
|
||||
|
||||
Please include a change to this file with each patch, *and* each
|
||||
subsequent modification of the patch. Do NOT combine patch
|
||||
checkins, keep them separate.
|
||||
|
||||
Append new entries to the end of this file. Each entry shall include:
|
||||
* The list of files modified by the patch,
|
||||
* The status of the patch. Should be one of:
|
||||
- already upstream (indicate upstream revision),
|
||||
- not yet upstream, or
|
||||
- google-local (not applicable upstream).
|
||||
* The local 'owner' responsible for the patch, and
|
||||
* A description of the patch (preferably including bug numbers).
|
||||
|
||||
Please include entries for both local patches and for patches which
|
||||
have been checked in to (or back-ported from) the upstream sources.
|
||||
When checking in changes made upstream, add an entry to this file but
|
||||
DO NOT add entries to the GNU ChangeLog files.
|
||||
|
||||
elf/Versions
|
||||
elf/dl-misc.c
|
||||
elf/dl-open.c
|
||||
elf/dl-reloc.c
|
||||
elf/dl-tls.c
|
||||
nptl/Makefile
|
||||
nptl/allocatestack.c
|
||||
nptl/tst-tls7.c
|
||||
nptl/tst-tls7mod.c
|
||||
sysdeps/generic/ldsodefs.h
|
||||
Revert upstream removal of async-safe TLS patches. These patches were
|
||||
removed at the last minute from the glibc 2.19 release, as follows:
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=8b6785f0836011cace9a77f3c24e51a7379238a0
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=dd654bf9ba1848bf9ed250f8ebaa5097c383dcf8
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=73d61e4f6c65da714c0f8a3a233725322553ceba
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bf06bcee84d4c19a99925c0f58026a8cbd87a688
|
||||
(ahh, not yet upstream)
|
||||
|
||||
google-nsl-stub/Makefile
|
||||
google-nsl-stub/configure
|
||||
google-nsl-stub/shlib-versions
|
||||
google-nsl-stub/ypclnt.c
|
||||
For b/2832143 and b/10385480, add a stub libnsl library as an add-on, to
|
||||
replace the libnsl removed in the previous change. Although we do not use
|
||||
libnsl normally, we have precompiled third-party binaries that need to
|
||||
dynamically link to it, and this stub satisfies that need.
|
||||
(bmoses, google-local)
|
||||
|
||||
Versions.def
|
||||
shlib-versions
|
||||
include/grp.h
|
||||
include/pwd.h
|
||||
include/shadow.h
|
||||
nss/Makefile
|
||||
nss/Versions
|
||||
nss/function.def
|
||||
nss/nss_borg/borg-pwd.c
|
||||
nss/nss_cache/nss_cache.c
|
||||
nss/nss_cache/nss_cache.h
|
||||
Forward-port nss_borg and nss_cache from glibc-2.18
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
nis/Makefile
|
||||
nss/Makefile
|
||||
For b/2476399, disable libnss_db (not used in google).
|
||||
Likewise ibnsl and related libnss_* libraries.
|
||||
Forward-ported from cl/52538169 and cl/52538711.
|
||||
(ppluzhnikov, bmoses, google-local)
|
||||
|
||||
hesiod/Makefile
|
||||
For b/2476399, disable Hesiod (not used in google).
|
||||
Forward-ported from cl/52537558.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
Makerules
|
||||
nptl/Makefile
|
||||
Don't put absolute pathnames into libc.so and libpthread.so linker
|
||||
scripts -- absolute pathnames interfere with --sysroot.
|
||||
cl/51074128 from eglibc-2.18
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
csu/Makefile
|
||||
For bit-identical rebuilds, remove `date` invocations.
|
||||
Forward-ported from cl/51218346 (from cl/37734-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/Versions
|
||||
elf/dl-init.c
|
||||
sysdeps/i386/elf/start.S
|
||||
sysdeps/x86_64/elf/start.S
|
||||
Add __google_auxv.
|
||||
Forward-ported from cl/51271693 (from cl/38027-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
dlfcn/dlmopen.c
|
||||
dlfcn/dlopen.c
|
||||
sysdeps/gnu/errlist-compat.awk
|
||||
Disable static linking warning for dlopen and dlmopen, and disable linking
|
||||
warning for sys_errlist and sys_nerr.
|
||||
Forward-ported from cl/51276043 (from part of cl/38025-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
include/features.h
|
||||
Add __GOOGLE_GRTE_VERSION__ for GRTEv4 usage.
|
||||
Forward-ported with date and comment changed from cl/51277131.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/Versions
|
||||
elf/dl-debug.c
|
||||
Add _google_dl_debug_state_hook. This is used by libunwind; see comment
|
||||
in //google3/third_party/grte/google_glibc_extensions.h.
|
||||
Forward-ported from cl/51330448 (from cl/38429-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
include/alloca.h
|
||||
Set __MAX_ALLOCA_CUTOFF to 8kb to avoid stack overflow, as described in
|
||||
b/2425017. The stack protection in //google3/thread/thread.cc creates a
|
||||
large stack with only 64kb of remaining space, which the upstream alloca
|
||||
heuristic is ill-equipped to deal with.
|
||||
Forward-ported from cl/51331379 (from cl/38559-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
locale/programs/locarchive.c
|
||||
Reduce starting table sizes for locale-archive file, since we use only a
|
||||
small fraction of the entries.
|
||||
Forward-ported from cl/51331729 (from cl/39296-p2).
|
||||
(cgd, google-local)
|
||||
|
||||
sysdeps/unix/grantpt.c
|
||||
For b/2723095, allow grantpt() to succeed even if it can't chgrp
|
||||
the slave pty to the "tty" group.
|
||||
Forward-ported from cl/51332316 (from cl/41538-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/rtld.c
|
||||
For b/4268901, disable "/etc/ld.so.preload", but allow other builds to
|
||||
re-enable it by setting -DENABLE_ETC_LD_SO_PRELOAD in CFLAGS.
|
||||
Forward-ported from cl/51332859 (from cl/51576-p2 and cl/51620-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
misc/sys/cdefs.h
|
||||
g/grte-team/browse_thread/thread/d08601e9f5542d94
|
||||
Disable gcc's __warn_unused_result__ attribute in glibc headers when
|
||||
_GOOGLE_FORTIFY_SOURCE_NO_WARN_UNUSED_RESULT is specified, even if
|
||||
_FORTIFY_SOURCE is set. Some google3 code does not compile when this
|
||||
attribute is set on some glibc functions.
|
||||
Forward-ported from cl/51334004 (from cl/53404-p2).
|
||||
(swiecki, google-local)
|
||||
|
||||
stdio-common/print_fp.c
|
||||
stdio-common/print_fphex.c
|
||||
stdio-common/tstdiomisc.c
|
||||
Effectively revert an upstream patch to print signs on NaN values. This
|
||||
change causes many google3 test failures, and the signs are meaningless.
|
||||
Forward-ported from cl/51376114 (from cl/41709-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
posix/glob.c
|
||||
sysdeps/unix/readdir.c
|
||||
sysdeps/unix/readdir_r.c
|
||||
For b/3162458, don't skip files with d_ino==0 -- our tmpfs systems
|
||||
sometimes create them due to inode wraparound.
|
||||
Forward-ported from cl/51430993 (from cl/45000-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/Makefile
|
||||
elf/dl-cache.c
|
||||
elf/dl-support.c
|
||||
elf/rtld.c
|
||||
sysdeps/generic/ldsodefs.h
|
||||
sysdeps/generic/unsecvars.h
|
||||
For b/2471323, implement multi-level cache search for shared libraries.
|
||||
Currently, two-level: $prefix/etc/ld.so.conf and /etc/ld.so.conf.
|
||||
Allow build-time configuration override via GOOGLE_LD_SO_CACHE_LIST.
|
||||
Allow run-time override via LD_GOOGLE_LD_SO_CACHE_LIST environment
|
||||
variable.
|
||||
Forward-ported from cl/51433387 (from cl/38694-p2, cl/38725-p2, and
|
||||
cl/38741-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/dl-cache.c
|
||||
elf/dl-load.c
|
||||
include/dlfcn.h
|
||||
sysdeps/generic/ldsodefs.h
|
||||
For b/3133396, ignore system ld.so.cache when looking for
|
||||
nss and iconv modules.
|
||||
Forward-ported from cl/51433604 (from cl/44863-p2).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
nptl/sysdeps/pthread/unwind-forcedunwind.c
|
||||
For b/5836136, do dlsym(0, "_Unwind..."), i.e. ignore libgcc_s.so.1
|
||||
dlopen failure.
|
||||
Forward-ported from cl/51438157.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
nptl/Makefile
|
||||
For b/5013921, build pthread_join.c and pthread_timedjoin.c with
|
||||
frame pointers.
|
||||
Forward-ported from cl/51440285 (from cl//54512-p2).
|
||||
Note: this is redundant with http://cr/62476718 that builds entire glibc
|
||||
with -fno-omit-frame-pointer, but I am forward-porting it anyway in case
|
||||
we decide to revert cr/62476718 later.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/dl-close.h
|
||||
elf/dl-load.c
|
||||
elf/dl-lookup.c
|
||||
elf/dl-support.c
|
||||
elf/dl-version.c
|
||||
elf/rtld.c
|
||||
sysdeps/generic/ldsodefs.h
|
||||
Add "fastload" support. This reduces the linear search for symbols when
|
||||
loading dynamic libraries to a hash-table lookup, dramatically reducing
|
||||
the startup time of Google3 binaries with large numbers of dynamic-library
|
||||
dependencies.
|
||||
Forward-ported from cl/56574617.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
|
||||
sysdeps/unix/sysv/linux/i386/nptl/libnsl.abilist
|
||||
sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist
|
||||
sysdeps/unix/sysv/linux/x86_64/64/nptl/libnsl.abilist
|
||||
Adjust the size value on _nl_default_dirname to match the directory
|
||||
name that we use in GRTE builds so that "make check-abi" will pass, as
|
||||
described in the glibc wiki:
|
||||
http://sourceware.org/glibc/wiki/Testing/Testsuite#Known_testsuite_failures
|
||||
Also adjust list of exported symbols for google-nsl-stub.
|
||||
Similar to cr/51166205
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
Makerules
|
||||
For b/13350520, disable check-abi
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/Versions
|
||||
Export __signal_safe* functions from ld.so so we can use a different
|
||||
implementation.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/dl-dst.h
|
||||
elf/dl-load.c
|
||||
elf/dl-support.c
|
||||
elf/rtld.c
|
||||
sysdeps/generic/ldsodefs.h
|
||||
For b/4074041, add EXEC_ORIGIN support.
|
||||
Forward-ported from cl/56955623 and cl/59961863.
|
||||
(bmoses, google-local)
|
||||
|
||||
nptl/Versions
|
||||
nptl/pthread_key_create.c
|
||||
nptl/sysdeps/pthread/pthread.h
|
||||
nptl/sysdeps/unix/sysv/linux/bits/local_lim.h
|
||||
nptl/sysdeps/unix/sysv/linux/powerpc/bits/local_lim.h
|
||||
nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h
|
||||
nptl/tst-key1.c
|
||||
nptl/tst-key4.c
|
||||
ports/sysdeps/unix/sysv/linux/aarch64/nptl/bits/local_lim.h
|
||||
ports/sysdeps/unix/sysv/linux/alpha/nptl/bits/local_lim.h
|
||||
ports/sysdeps/unix/sysv/linux/mips/nptl/bits/local_lim.h
|
||||
ports/sysdeps/unix/sysv/linux/tile/bits/local_lim.h
|
||||
Add pthread_signal_safe_key_create.
|
||||
Forward ported from cl/59612021, cl/59817832, and cl/59176280.
|
||||
(ahh, google-local)
|
||||
|
||||
Versions.def
|
||||
dlfcn/Versions
|
||||
dlfcn/dlfcn.h
|
||||
dlfcn/dlmopen.c
|
||||
dlfcn/dlopen.c
|
||||
dlfcn/dlopenold.c
|
||||
elf/dl-deps.c
|
||||
elf/dl-libc.c
|
||||
elf/dl-load.c
|
||||
elf/dl-open.c
|
||||
elf/rtld.c
|
||||
include/dlfcn.h
|
||||
sysdeps/generic/ldsodefs.h
|
||||
For Google b/8315591, experimental implementation of dlopen_with_offset.
|
||||
Forward-ported from cl/59286541, cl/59438930
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
malloc/malloc.c
|
||||
ports/sysdeps/unix/sysv/linux/aarch64/nptl/localplt.data
|
||||
sysdeps/generic/localplt.data
|
||||
sysdeps/unix/sysv/linux/i386/nptl/localplt.data
|
||||
sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/localplt.data
|
||||
For b/5732800, expose calls from malloc to mmap, munmap, and sbrk.
|
||||
Forward ported from cl/42670015, with changes.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/rtld.c
|
||||
For b/12342355, remove inappropriate assert in EXEC_ORIGIN support.
|
||||
(bmoses, google-local)
|
||||
|
||||
sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c
|
||||
sysdeps/powerpc/powerpc32/power4/multiarch/bzero-ppc32.S
|
||||
sysdeps/powerpc/powerpc64/multiarch/memset-ppc64.S
|
||||
For b/14302447, backport upstream patches for __bzero_ppc:
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=16683
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=4facea473059914983b7da8dd654c06b8e3dcc41
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=dd3946c615184e1957a0cb09352cac72be5d6d5b
|
||||
(bmoses, already upstream)
|
||||
|
||||
sysdeps/unix/sysv/linux/sys/ptrace.h
|
||||
For b/13432624, add PTRACE_EVENT_STOP to __ptrace_eventcodes enum.
|
||||
(bmoses, not yet upstream)
|
||||
|
||||
nptl/Makefile
|
||||
For b/14616463, add -fno-function-sections to events.c compilation.
|
||||
(bmoses, google-local)
|
||||
|
||||
libio/Makefile
|
||||
libio/fileops.c
|
||||
libio/iofdopen.c
|
||||
libio/iofwide.c
|
||||
libio/libioP.h
|
||||
libio/tst-ftell-active-handler.c
|
||||
libio/wfileops.c
|
||||
For b/15017950, backport upstream patches for PR16532 (separate
|
||||
ftell, fseek logic) and subsequent optimization and cleanup:
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=000232b9bcbf194f1e5fd0ff380000f341505405
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=fa3cd24827d34a49e0a3a5cac56abbf8df74d8ac
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=091eff71a5edacb5a321c6e573f09a5358540675
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=d4b17258bba38f206079fbae1e7255779db1b74c
|
||||
(bmoses, already upstream)
|
||||
|
||||
sysdeps/powerpc/powerpc64/fpu/s_copysign.S
|
||||
For b/13737066, backport upstream patches for PR16786 (s_copysign
|
||||
stack temp bugfix on PPC ELFv2):
|
||||
https://sourceware.org/ml/libc-alpha/2014-04/msg00000.html
|
||||
(bmoses, already upstream)
|
||||
|
||||
elf/rtld.c
|
||||
For b/13901604, set correct __google_auxv before unsetting insecure
|
||||
environment variables.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
posix/spawn_faction_addopen.c
|
||||
posix/spawn_faction_destroy.c
|
||||
posix/spawn_int.h
|
||||
tst-spawn.c
|
||||
For b/15568332, backport patch to copy path argument to
|
||||
posix_spawn_file_actions_addopen.
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=17048
|
||||
(bmoses, backport)
|
||||
|
||||
libio/Makefile
|
||||
libio/iofdopen.c
|
||||
libio/fileops.c
|
||||
libio/tst-ftell-active-handler.c
|
||||
libio/tst-ftell-append.c
|
||||
libio/wfileops.c
|
||||
For b/15017950, backport patch to fix offset computation for append+
|
||||
mode on switching from read, and preceeding patches to fix another
|
||||
issue with append files and ftell, and to adjust test environments.
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=ea33158c96c53a64402a772186956c1f5cb556ae
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=003e49ed5d2034d73bfcf5324c461785687b7e88
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=2482ae433a4249495859343ae1fba408300f2c2e
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=16724
|
||||
(bmoses, backport)
|
||||
|
||||
misc/mktemp.c
|
||||
stdio-common/tempnam.c
|
||||
stdio-common/tmpnam.c
|
||||
For Crosstool v18 disable link-time warning about mktemp,tempnam and tmpnam.
|
||||
b/6115789
|
||||
TODO(ppluzhnikov): revert this after cleanup.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
csu/elf-init.c
|
||||
sysdeps/i386/start.S
|
||||
sysdeps/x86_64/start.S
|
||||
For b/13901604, revert local changes to sysdeps/{i386,x86_64}/elf/start.S,
|
||||
and initialize __google_auxv in __libc_csu_init instead.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
csu/elf-init.c
|
||||
elf/dl-support.c
|
||||
For b/15780211, revert local change to csu/elf-init.c and move
|
||||
initialization of __google_auxv earlier (in the fully-static link).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/ldd.bash.in
|
||||
Import ldd patches from Ubuntu source package. This fixes the ability
|
||||
of ldd to trace dependencies in non-executable dynamic libraries.
|
||||
(bmoses, google-local)
|
||||
|
||||
stdlib/secure-getenv.c
|
||||
Export a __secure_getenv weak symbol for backwards compatibility at link
|
||||
time.
|
||||
(bmoses, google-local)
|
||||
|
||||
elf/dl-load.c
|
||||
include/link.h
|
||||
For b/18243822, fix dlopen_with_offset to not reuse the same link_map
|
||||
entry when called on the same file with different offsets.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
dlfcn/dlopen.c
|
||||
elf/dl-load.c
|
||||
To fix AARCH64 build, make code added to dl-load.c in previous CL
|
||||
conditional on SHARED. Disable dlopen_with_offet in fully-static links.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
wordexp.c
|
||||
posix/wordexp-test.c
|
||||
For b/18473397 and CVE-2014-7817, properly handle the WRDE_NOCMD
|
||||
flag when processing certain arithmetic inputs.
|
||||
(backport)
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a39208bd7fb76c1b01c127b4c61f9bfd915bfe7c
|
||||
|
||||
sysdeps/x86_64/start.S
|
||||
For b/18331558, use ENTRY and END macros to get a .size directive.
|
||||
(backport)
|
||||
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=467fec0bb47464ff49e7075194342b028c75c72f
|
||||
|
||||
dlfcn/dlopen.c
|
||||
Re-fix b/18243822 which got broken by cr/80600560 (AARCH64 build fix).
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
resolv/res_libc.c
|
||||
For b/18473393, port r9102, r11566, and r14311 from eglibc sources.
|
||||
|
||||
resolv/nss_dns/dns-resolve.c
|
||||
For b/18752432, backport infinite loop fix in getnetbyname (PR17630)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=11e3417af6e354f1942c68a271ae51e892b2814d
|
||||
|
||||
stdio-common/tst-sscanf.c
|
||||
stdio-common/vfscanf.c
|
||||
For b/19289207, backport memory allocation fix for wscanf (PR16618)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=5bd80bfe9ca0d955bfbbc002781bc7b01b6bcb06
|
||||
|
||||
socket/sys/un.h
|
||||
Replace null dereference in the SUN_LEN macro with offsetof.
|
||||
(nlewycky, not yet upstream)
|
||||
|
||||
elf/dl-load.c
|
||||
For b/8315591, b/20141439 correct off-by-one error that resulted in last
|
||||
byte of l_name being random garbage.
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
libio/fmemopen.c
|
||||
libio/test-fmemopen.c
|
||||
For b/22167761, backport fix buffer overflow for writes to memory buffer stream (PR18549)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=7c2ce714d4e853aadbec13b920576fdfada520f1
|
||||
(stanshebs, backport)
|
||||
|
||||
string/string.h
|
||||
math/bits/mathcalls.h
|
||||
misc/sys/cdefs.h
|
||||
Re-declare hot libc functions with "noplt" attribute available GCC 4.9
|
||||
onwards. This attribute allows calls to these functions to avoid the
|
||||
PLT and improves the performance of some of our code via better icache
|
||||
and iTLB performance.
|
||||
(tmsriram, google-local)
|
||||
|
||||
elf/dl-tls.c
|
||||
nptl/Makefile
|
||||
nptl/tst-tls77.c
|
||||
nptl/tst-tls77mod.c
|
||||
Fix b/19824366 with tweaks to TLS dynamic loading, and add a test. Note that
|
||||
upstream commit
|
||||
https://sourceware.org/git/?p=glibc.git&a=commit&h=f8aeae347377f3dfa8cbadde057adf1827fb1d44
|
||||
fixes this problem in a different way, so this patch is not needed upstream.
|
||||
(stanshebs, google-local)
|
||||
|
||||
elf/link.h
|
||||
socket/sys/un.h
|
||||
Correct locations of __BEGIN_DECLS and #includes, as neeeded for C++
|
||||
module compatibility.
|
||||
(chandlerc, google-local)
|
||||
|
||||
resolv/nss_dns/dns-host.c
|
||||
For b/21023324, backport buffer overflow in getanswer_r (PR18287, CVE-2015-1781)
|
||||
https://sourceware.org/git/?p=glibc.git;a=commit;h=2959eda9272a03386
|
||||
(stanshebs, backport)
|
||||
|
||||
nss/nss_borg/borg-pwd.c
|
||||
Improve documentation, remove dead code.
|
||||
(stanshebs, google-local)
|
||||
|
||||
posix/fnmatch_loop.c
|
||||
posix/Makefile
|
||||
posix/tst-fnmatch3.c
|
||||
For b/19524869 and b/19533947, backport buffer overflow fixes in fnmatch.
|
||||
(PR18032, PR18036)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=4a28f4d55a6cc33474c0792fe93b5942d81bf185
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c2c6d39fab901c97c18fa3a3a3658d9dc3f7df61
|
||||
(stanshebs, backport)
|
||||
|
||||
nss/nss_files/files-XXX.c
|
||||
nss/Makefile
|
||||
nss/tst-nss-getpwent.c
|
||||
For b/19498319, backport fix for nss_files file management (PR18007, CVE-2014-8121)
|
||||
https://sourceware.org/git/?p=glibc.git;a=commit;h=03d2730b44cc2236318fd978afa2651753666c55
|
||||
(stanshebs, backport)
|
||||
|
||||
elf/dl-load.c
|
||||
For b/20141439, don't add "foo.so" as alternate name for already loaded foo.so/@0x<offset>
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
elf/dl-load.c
|
||||
For b/22641205, #include _itoa.h
|
||||
(ppluzhnikov, google-local)
|
||||
|
||||
nptl/pthread_getspecific.c
|
||||
nptl/tst-key5.c
|
||||
Fix for b/18722637 : make pthread_getspecific signal safe.
|
||||
(ahh, google-local, proposed upstream)
|
||||
|
||||
include/resolv.h
|
||||
resolv/gethnamaddr.c
|
||||
resolv/res_query.c
|
||||
resolv/res_send.c
|
||||
resolv/nss_dns/dns-canon.c
|
||||
resolv/nss_dns/dns-host.c
|
||||
resolv/nss_dns/dns-network.c
|
||||
For b/24580666, backport fix for memory leak in getaddrinfo() (PR16574)
|
||||
https://sourceware.org/git/?p=glibc.git;a=commit;h=d668061994a7486a3ba9c7d5e7882d85a2883707
|
||||
https://sourceware.org/git/?p=glibc.git;a=commit;h=ab7ac0f2cf8731fe4c3f3aea6088a7c0127b5725
|
||||
https://sourceware.org/git/?p=glibc.git;a=commit;h=ab09bf616ad527b249aca5f2a4956fd526f0712f
|
||||
(stanshebs, backport)
|
||||
|
||||
include/features.h
|
||||
Allow suppressing the definition of __USE_FILE_OFFSET64 by defining
|
||||
SUPPRESS_USE_FILE_OFFSET64. As large file types match the default
|
||||
types, this is irrelevant in Google's depot, but leads to different type
|
||||
signatures for functions that are problematic with C++ modules.
|
||||
(klimek, google-local)
|
||||
|
||||
math/auto-libm-test-in
|
||||
math/auto-libm-test-out
|
||||
sysdeps/ieee754/dbl-64/s_sin.c
|
||||
sysdeps/x86_64/fpu/libm-test-ulps
|
||||
For b/25873705, backport fix for broken trig functions (PR16623)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=1cadc85813d736f7682fa2eeadae639ab6b66c65
|
||||
(stanshebs, backport)
|
||||
|
||||
iconv/gconv_trans.c
|
||||
For b/25977570, backport removal of __gconv_translit_find (PR17187)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=a1a6a401ab0a3c9f15fb7eaebbdcee24192254e8
|
||||
(stanshebs, backport)
|
||||
|
||||
resolv/res_send.c
|
||||
For b/25900273, adjust allocations to avoid segfault.
|
||||
(bmoses, google-local)
|
||||
|
||||
nptl/allocatestack.c
|
||||
nptl/Makefile
|
||||
nptl/tst-basic8.c
|
||||
For b/24399992 unlock guard pages to avoid wasting memory.
|
||||
|
||||
nptl/Makefile
|
||||
Unbreak building of tst-key5
|
||||
(stanshebs, google-local)
|
||||
|
||||
elf/elf.h
|
||||
math/libm-test.inc
|
||||
string/*
|
||||
sysdeps/ieee754/*
|
||||
sysdeps/powerpc/*
|
||||
For b/18010034, backport IBM optimizations for Power8.
|
||||
https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/ibm/2.19/master
|
||||
(stanshebs, backport)
|
||||
|
||||
sysdeps/powerpc/bits/fenvinline.h
|
||||
For b/27191207, remove use of %s modifier in inline asm.
|
||||
(stanshebs, google-local)
|
||||
|
||||
nptl/sysdeps/unix/sysv/linux/register-atfork.c
|
||||
For b/28011264, detect and work around loop in fork handler list.
|
||||
(stanshebs, google-local)
|
||||
|
||||
resolv/nss_dns/dns-network.c
|
||||
For b/27917753, fix stack overflow in _nss_dns_getnetbyname_r (BZ19879)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=317b199b4aff8cfa27f2302ab404d2bb5032b9a4
|
||||
(stanshebs, backport)
|
||||
|
||||
resolv/res_send.c
|
||||
For b/28166767, fix where getaddrinfo() writes DNS queries to random file descriptors
|
||||
under high load (BZ15946, CVE-2013-7423)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=f9d2d03254a58d92635a311a42253eeed5a40a47
|
||||
(stanshebs, backport)
|
||||
|
||||
locale/findlocale.c
|
||||
locale/setlocale.c
|
||||
For b/29130905, fix locale vulnerabilities (BZ1737, CVE-2014-0475)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=4e8f95a0df7c2300b830ec12c0ae1e161bc8a8a3
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=d183645616b0533b3acee28f1a95570bffbdf50f
|
||||
(stanshebs, backport)
|
||||
|
||||
nss/nss_cache/nss_cache.h
|
||||
nss/nss_cache/nss_cache.c
|
||||
For b/29944535, import current nss_cache.c and nss_cache.h from upstream.
|
||||
This fixes a performance issue in getgrgid_r on corp machines.
|
||||
https://github.com/google/libnss-cache/blob/74a14a1dcc669ebe95e90d6d0e0ca36dd8c63b43/nss_cache.c
|
||||
https://github.com/google/libnss-cache/blob/74a14a1dcc669ebe95e90d6d0e0ca36dd8c63b43/nss_cache.h
|
||||
(mkanat, google-local)
|
||||
|
||||
sysdeps/posix/getaddrinfo.c
|
||||
For b/30090956, fix stack overflow in hostent conversion (BZ20010, CVE-2016-3706)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=4ab2ab03d4351914ee53248dc5aef4a8c88ff8b9
|
||||
(stanshebs, backport)
|
||||
|
||||
sysdeps/posix/getaddrinfo.c
|
||||
posix/Makefile
|
||||
posix/tst-getaddrinfo6.c
|
||||
For b/29615899, fix error handling in getaddrinfo.
|
||||
(stanshebs, google-local)
|
||||
|
||||
elf/elf.h
|
||||
For b/31273149, revert the value of DT_PPC64_NUM from 4 to 3.
|
||||
(stanshebs, google-local)
|
||||
|
||||
nss/nss_borg/borg-pwd.c
|
||||
Add /etc/passwd.borg.base as fallback passwd file. (b/30413914, b/32608777)
|
||||
(mrothwell/stanshebs, google-local)
|
||||
|
||||
nss/nss_files/files-XXX.c
|
||||
For b/26276654, don't ignore too long lines in nss_files (BZ17079, CVE-2015-5277)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commit;h=3fd498242948b1fa944c56646ec9b156387dd310
|
||||
(stanshebs, backport)
|
||||
|
||||
posix/fnmatch_loop.c
|
||||
Don't read past end of pattern in fnmatch (BZ17062)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commit;h=b3a9f56ba59c3d8eadd3135a1c25c37a63151450
|
||||
(stanshebs, backport)
|
||||
|
||||
nss/tst-nss-getpwent.c
|
||||
Work around b/34251679 by restricting to nss_files module
|
||||
(stanshebs, google-local)
|
||||
|
||||
time/strftime_l.c
|
||||
time/tst-strftime.c
|
||||
Fix where out of range data to strftime() causes a segfault (BZ18985, CVE-2015-8776)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=d36c75fc0d44deec29635dd239b0fbd206ca49b7
|
||||
(stanshebs, backport)
|
||||
|
||||
elf/rtld.c
|
||||
sysdeps/generic/ldsodefs.h
|
||||
Always enable pointer guard (BZ18928, CVE-2015-8777)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=a014cecd82b71b70a6a843e250e06b541ad524f7
|
||||
(stanshebs, backport)
|
||||
|
||||
misc/Makefile
|
||||
misc/bug18240.c
|
||||
misc/hsearch_r.c
|
||||
hcreate, hcreate_r should fail with ENOMEM if element count is too large (BZ18240, CVE-2015-8778)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=b5cba5cff937e5336ff23380785da80cab09146c
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=3c9e8d9477aba0f514171bb4706670052544479b
|
||||
(stanshebs, backport)
|
||||
|
||||
catgets/Makefile
|
||||
catgets/catgets.c
|
||||
catgets/open_catalog.c
|
||||
catgets/tst-catgets.c
|
||||
Fix catopen() Multiple unbounded stack allocations (BZ17905, CVE-2015-8779)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=0f58539030e436449f79189b6edab17d7479796e
|
||||
(stanshebs, backport)
|
||||
|
||||
ports/sysdeps/unix/sysv/linux/arm/setcontext.S
|
||||
Missing unwind info in __startcontext causes infinite loop (BZ20435, CVE-2016-6323)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=9e2ff6c9cc54c0b4402b8d49e4abe7000fde7617
|
||||
(stanshebs, backport)
|
||||
|
||||
include/stdlib.h
|
||||
include/wchar.h
|
||||
math/Makefile
|
||||
math/s_nan.c
|
||||
math/s_nanf.c
|
||||
math/s_nanl.c
|
||||
math/test-nan-overflow.c
|
||||
math/test-nan-payload.c
|
||||
stdlib/Makefile
|
||||
stdlib/Versions
|
||||
stdlib/strtod_l.c
|
||||
stdlib/strtod_nan.c
|
||||
stdlib/strtod_nan_double.h
|
||||
stdlib/strtod_nan_float.h
|
||||
stdlib/strtod_nan_main.c
|
||||
stdlib/strtod_nan_narrow.h
|
||||
stdlib/strtod_nan_wide.h
|
||||
stdlib/strtof_l.c
|
||||
stdlib/strtof_nan.c
|
||||
stdlib/strtold_nan.c
|
||||
sysdeps/ieee754/ldbl-128/strtod_nan_ldouble.h
|
||||
sysdeps/ieee754/ldbl-128/strtold_l.c
|
||||
sysdeps/ieee754/ldbl-128ibm/strtod_nan_ldouble.h
|
||||
sysdeps/ieee754/ldbl-128ibm/strtold_l.c
|
||||
sysdeps/ieee754/ldbl-64-128/strtold_l.c
|
||||
sysdeps/ieee754/ldbl-96/strtod_nan_ldouble.h
|
||||
sysdeps/ieee754/ldbl-96/strtold_l.c
|
||||
wcsmbs/Makefile
|
||||
wcsmbs/wcstod_l.c
|
||||
wcsmbs/wcstod_nan.c
|
||||
wcsmbs/wcstof_l.c
|
||||
wcsmbs/wcstof_nan.c
|
||||
wcsmbs/wcstold_l.c
|
||||
wcsmbs/wcstold_nan.c
|
||||
Fix nan functions handling of payload strings (BZ16962, CVE-2014-9761)
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=e02cabecf0d025ec4f4ddee290bdf7aadb873bb3
|
||||
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=8f5e8b01a1da2a207228f2072c934fa5918554b8
|
||||
(stanshebs, backport)
|
||||
@@ -50,6 +50,7 @@ libdl {
|
||||
GLIBC_2.1
|
||||
GLIBC_2.3.3
|
||||
GLIBC_2.3.4
|
||||
GLIBC_2.15
|
||||
}
|
||||
libm {
|
||||
GLIBC_2.0
|
||||
@@ -80,6 +81,12 @@ libnss_db {
|
||||
libnss_files {
|
||||
GLIBC_PRIVATE
|
||||
}
|
||||
libnss_borg {
|
||||
GLIBC_PRIVATE
|
||||
}
|
||||
libnss_cache {
|
||||
GLIBC_PRIVATE
|
||||
}
|
||||
libnss_hesiod {
|
||||
GLIBC_PRIVATE
|
||||
}
|
||||
|
||||
+6
-2
@@ -46,13 +46,14 @@ CPPFLAGS-gencat = -DNOT_IN_libc
|
||||
|
||||
generated = de.msg test1.cat test1.h test2.cat test2.h sample.SJIS.cat \
|
||||
test-gencat.h
|
||||
generated += tst-catgets.mtrace tst-catgets-mem.out
|
||||
generated-dirs = de
|
||||
|
||||
tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de
|
||||
tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de MALLOC_TRACE=$(objpfx)tst-catgets.mtrace
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests: $(objpfx)de/libc.cat $(objpfx)test1.cat $(objpfx)test2.cat \
|
||||
$(objpfx)test-gencat.out
|
||||
$(objpfx)test-gencat.out $(objpfx)tst-catgets-mem.out
|
||||
# This test just checks whether the program produces any error or not.
|
||||
# The result is not tested.
|
||||
$(objpfx)test1.cat: test1.msg $(objpfx)gencat
|
||||
@@ -80,4 +81,7 @@ $(objpfx)test-gencat.out: test-gencat.sh $(objpfx)test-gencat \
|
||||
$(objpfx)sample.SJIS.cat: sample.SJIS $(objpfx)gencat
|
||||
GCONV_PATH=$(common-objpfx)iconvdata LC_ALL=C \
|
||||
$(built-program-cmd) -H $(objpfx)test-gencat.h < $(word 1,$^) > $@
|
||||
|
||||
$(objpfx)tst-catgets-mem.out: $(objpfx)tst-catgets.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-catgets.mtrace > $@
|
||||
endif
|
||||
|
||||
+12
-7
@@ -16,7 +16,6 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <nl_types.h>
|
||||
@@ -35,6 +34,7 @@ catopen (const char *cat_name, int flag)
|
||||
__nl_catd result;
|
||||
const char *env_var = NULL;
|
||||
const char *nlspath = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (strchr (cat_name, '/') == NULL)
|
||||
{
|
||||
@@ -54,7 +54,10 @@ catopen (const char *cat_name, int flag)
|
||||
{
|
||||
/* Append the system dependent directory. */
|
||||
size_t len = strlen (nlspath) + 1 + sizeof NLSPATH;
|
||||
char *tmp = alloca (len);
|
||||
tmp = malloc (len);
|
||||
|
||||
if (__glibc_unlikely (tmp == NULL))
|
||||
return (nl_catd) -1;
|
||||
|
||||
__stpcpy (__stpcpy (__stpcpy (tmp, nlspath), ":"), NLSPATH);
|
||||
nlspath = tmp;
|
||||
@@ -65,16 +68,18 @@ catopen (const char *cat_name, int flag)
|
||||
|
||||
result = (__nl_catd) malloc (sizeof (*result));
|
||||
if (result == NULL)
|
||||
/* We cannot get enough memory. */
|
||||
return (nl_catd) -1;
|
||||
|
||||
if (__open_catalog (cat_name, nlspath, env_var, result) != 0)
|
||||
{
|
||||
/* We cannot get enough memory. */
|
||||
result = (nl_catd) -1;
|
||||
}
|
||||
else if (__open_catalog (cat_name, nlspath, env_var, result) != 0)
|
||||
{
|
||||
/* Couldn't open the file. */
|
||||
free ((void *) result);
|
||||
return (nl_catd) -1;
|
||||
result = (nl_catd) -1;
|
||||
}
|
||||
|
||||
free (tmp);
|
||||
return (nl_catd) result;
|
||||
}
|
||||
|
||||
|
||||
+14
-9
@@ -47,6 +47,7 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
size_t tab_size;
|
||||
const char *lastp;
|
||||
int result = -1;
|
||||
char *buf = NULL;
|
||||
|
||||
if (strchr (cat_name, '/') != NULL || nlspath == NULL)
|
||||
fd = open_not_cancel_2 (cat_name, O_RDONLY);
|
||||
@@ -57,23 +58,23 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
if (__builtin_expect (bufact + (n) >= bufmax, 0)) \
|
||||
{ \
|
||||
char *old_buf = buf; \
|
||||
bufmax += 256 + (n); \
|
||||
buf = (char *) alloca (bufmax); \
|
||||
memcpy (buf, old_buf, bufact); \
|
||||
bufmax += (bufmax < 256 + (n)) ? 256 + (n) : bufmax; \
|
||||
buf = realloc (buf, bufmax); \
|
||||
if (__glibc_unlikely (buf == NULL)) \
|
||||
{ \
|
||||
free (old_buf); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* The RUN_NLSPATH variable contains a colon separated list of
|
||||
descriptions where we expect to find catalogs. We have to
|
||||
recognize certain % substitutions and stop when we found the
|
||||
first existing file. */
|
||||
char *buf;
|
||||
size_t bufact;
|
||||
size_t bufmax;
|
||||
size_t bufmax = 0;
|
||||
size_t len;
|
||||
|
||||
buf = NULL;
|
||||
bufmax = 0;
|
||||
|
||||
fd = -1;
|
||||
while (*run_nlspath != '\0')
|
||||
{
|
||||
@@ -188,7 +189,10 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
|
||||
/* Avoid dealing with directories and block devices */
|
||||
if (__builtin_expect (fd, 0) < 0)
|
||||
return -1;
|
||||
{
|
||||
free (buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
|
||||
goto close_unlock_return;
|
||||
@@ -325,6 +329,7 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
/* Release the lock again. */
|
||||
close_unlock_return:
|
||||
close_not_cancel_no_status (fd);
|
||||
free (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <assert.h>
|
||||
#include <mcheck.h>
|
||||
#include <nl_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
|
||||
static const char *msgs[] =
|
||||
@@ -12,6 +15,33 @@ static const char *msgs[] =
|
||||
};
|
||||
#define nmsgs (sizeof (msgs) / sizeof (msgs[0]))
|
||||
|
||||
|
||||
/* Test for unbounded alloca. */
|
||||
static int
|
||||
do_bz17905 (void)
|
||||
{
|
||||
char *buf;
|
||||
struct rlimit rl;
|
||||
nl_catd result;
|
||||
|
||||
const int sz = 1024 * 1024;
|
||||
|
||||
getrlimit (RLIMIT_STACK, &rl);
|
||||
rl.rlim_cur = sz;
|
||||
setrlimit (RLIMIT_STACK, &rl);
|
||||
|
||||
buf = malloc (sz + 1);
|
||||
memset (buf, 'A', sz);
|
||||
buf[sz] = '\0';
|
||||
setenv ("NLSPATH", buf, 1);
|
||||
|
||||
result = catopen (buf, NL_CAT_LOCALE);
|
||||
assert (result == (nl_catd) -1);
|
||||
|
||||
free (buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ROUNDS 5
|
||||
|
||||
int
|
||||
@@ -62,5 +92,6 @@ main (void)
|
||||
}
|
||||
}
|
||||
|
||||
result += do_bz17905 ();
|
||||
return result;
|
||||
}
|
||||
|
||||
+4
-2
@@ -162,8 +162,10 @@ $(objpfx)version-info.h: $(common-objpfx)config.make $(all-Banner-files)
|
||||
if [ -z "$$os" ]; then \
|
||||
os=Linux; \
|
||||
fi; \
|
||||
printf '"Compiled on a %s %s system on %s.\\n"\n' \
|
||||
"$$os" "$$version" "`date +%Y-%m-%d`";; \
|
||||
# GOOGLE LOCAL: removed 'on %s' and '"`date +%Y-%m-%d`"' \
|
||||
# to enable bit-identical rebuilds \
|
||||
printf '"Compiled on a %s %s system.\\n"\n' \
|
||||
"$$os" "$$version";; \
|
||||
*) ;; \
|
||||
esac; \
|
||||
files="$(all-Banner-files)"; \
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
# include <link.h> // For ElfW.
|
||||
|
||||
|
||||
/* These magic symbols are provided by the linker. */
|
||||
extern void (*__preinit_array_start []) (int, char **, char **)
|
||||
|
||||
@@ -11,6 +11,9 @@ libdl {
|
||||
GLIBC_2.3.4 {
|
||||
dlmopen;
|
||||
}
|
||||
GLIBC_2.15 {
|
||||
__google_dlopen_with_offset; __google_dlmopen_with_offset;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
_dlfcn_hook;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <features.h>
|
||||
#define __need_size_t
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Collect various system dependent definitions and declarations. */
|
||||
#include <bits/dlfcn.h>
|
||||
@@ -55,6 +56,11 @@ __BEGIN_DECLS
|
||||
passed to `dlsym' to get symbol values from it. */
|
||||
extern void *dlopen (const char *__file, int __mode) __THROWNL;
|
||||
|
||||
/* Same as above, but ELF header is at OFF from the start of file. */
|
||||
extern void *__google_dlopen_with_offset (__const char *__file,
|
||||
off_t offset,
|
||||
int __mode) __THROW;
|
||||
|
||||
/* Unmap and close a shared object opened by `dlopen'.
|
||||
The handle cannot be used again after calling `dlclose'. */
|
||||
extern int dlclose (void *__handle) __THROWNL __nonnull ((1));
|
||||
@@ -68,6 +74,12 @@ extern void *dlsym (void *__restrict __handle,
|
||||
/* Like `dlopen', but request object to be allocated in a new namespace. */
|
||||
extern void *dlmopen (Lmid_t __nsid, const char *__file, int __mode) __THROWNL;
|
||||
|
||||
/* Same as above, but ELF header is at OFF from the start of file. */
|
||||
extern void *__google_dlmopen_with_offset (Lmid_t __nsid,
|
||||
__const char *__file,
|
||||
off_t offset,
|
||||
int __mode) __THROW;
|
||||
|
||||
/* Find the run-time address in the shared object HANDLE refers to
|
||||
of the symbol called NAME with VERSION. */
|
||||
extern void *dlvsym (void *__restrict __handle,
|
||||
|
||||
+49
-12
@@ -30,7 +30,9 @@ dlmopen (Lmid_t nsid, const char *file, int mode)
|
||||
{
|
||||
return __dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
|
||||
}
|
||||
#if 0 // Google-local
|
||||
static_link_warning (dlmopen)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@@ -38,6 +40,8 @@ struct dlmopen_args
|
||||
{
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
/* ELF header at offset in file. */
|
||||
off_t offset;
|
||||
/* The arguments for dlopen_doit. */
|
||||
const char *file;
|
||||
int mode;
|
||||
@@ -68,13 +72,55 @@ dlmopen_doit (void *a)
|
||||
GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid mode"));
|
||||
}
|
||||
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->new = GLRO(dl_open) (args->file ?: "",
|
||||
args->offset,
|
||||
args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->nsid, __dlfcn_argc, __dlfcn_argv,
|
||||
__environ);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
__dlmopen_common (struct dlmopen_args *args)
|
||||
{
|
||||
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlmopen_doit, args) ? NULL : args->new;
|
||||
# else
|
||||
if (_dlerror_run (dlmopen_doit, args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args->new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args->new);
|
||||
|
||||
return args->new;
|
||||
# endif
|
||||
}
|
||||
|
||||
void *
|
||||
__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset,
|
||||
int mode DL_CALLER_DECL)
|
||||
{
|
||||
# ifdef SHARED
|
||||
if (__builtin_expect (_dlfcn_hook != NULL, 0))
|
||||
return _dlfcn_hook->dlmopen_with_offset (nsid, file, offset,
|
||||
mode, RETURN_ADDRESS (0));
|
||||
# endif
|
||||
|
||||
struct dlmopen_args args;
|
||||
args.nsid = nsid;
|
||||
args.file = file;
|
||||
args.offset = offset;
|
||||
args.mode = mode;
|
||||
args.caller = DL_CALLER;
|
||||
|
||||
return __dlmopen_common (&args);
|
||||
}
|
||||
# ifdef SHARED
|
||||
strong_alias (__dlmopen_with_offset, __google_dlmopen_with_offset)
|
||||
# endif
|
||||
|
||||
void *
|
||||
__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
|
||||
{
|
||||
@@ -86,20 +132,11 @@ __dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
|
||||
struct dlmopen_args args;
|
||||
args.nsid = nsid;
|
||||
args.file = file;
|
||||
args.offset = 0;
|
||||
args.mode = mode;
|
||||
args.caller = DL_CALLER;
|
||||
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new;
|
||||
# else
|
||||
if (_dlerror_run (dlmopen_doit, &args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args.new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args.new);
|
||||
|
||||
return args.new;
|
||||
# endif
|
||||
return __dlmopen_common (&args);
|
||||
}
|
||||
# ifdef SHARED
|
||||
strong_alias (__dlmopen, dlmopen)
|
||||
|
||||
+43
-12
@@ -29,7 +29,9 @@ dlopen (const char *file, int mode)
|
||||
{
|
||||
return __dlopen (file, mode, RETURN_ADDRESS (0));
|
||||
}
|
||||
#if 0 // Google-local
|
||||
static_link_warning (dlopen)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@@ -37,6 +39,8 @@ struct dlopen_args
|
||||
{
|
||||
/* The arguments for dlopen_doit. */
|
||||
const char *file;
|
||||
/* ELF header at offset in file. */
|
||||
off_t offset;
|
||||
int mode;
|
||||
/* The return value of dlopen_doit. */
|
||||
void *new;
|
||||
@@ -63,13 +67,49 @@ dlopen_doit (void *a)
|
||||
| __RTLD_SPROF))
|
||||
GLRO(dl_signal_error) (0, NULL, NULL, _("invalid mode parameter"));
|
||||
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->new = GLRO(dl_open) (args->file ?: "",
|
||||
args->offset,
|
||||
args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->file == NULL ? LM_ID_BASE : NS,
|
||||
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
__dlopen_common (struct dlopen_args *args)
|
||||
{
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlopen_doit, args) ? NULL : args->new;
|
||||
# else
|
||||
if (_dlerror_run (dlopen_doit, args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args->new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args->new);
|
||||
|
||||
return args->new;
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef SHARED
|
||||
void *
|
||||
__dlopen_with_offset (const char *file, off_t offset, int mode DL_CALLER_DECL)
|
||||
{
|
||||
if (__builtin_expect (_dlfcn_hook != NULL, 0))
|
||||
return _dlfcn_hook->dlopen_with_offset (file, offset, mode, DL_CALLER);
|
||||
|
||||
struct dlopen_args args;
|
||||
args.file = file;
|
||||
args.offset = offset;
|
||||
args.mode = mode;
|
||||
args.caller = DL_CALLER;
|
||||
|
||||
return __dlopen_common (&args);
|
||||
}
|
||||
strong_alias (__dlopen_with_offset, __google_dlopen_with_offset)
|
||||
# endif
|
||||
|
||||
void *
|
||||
__dlopen (const char *file, int mode DL_CALLER_DECL)
|
||||
{
|
||||
@@ -80,20 +120,11 @@ __dlopen (const char *file, int mode DL_CALLER_DECL)
|
||||
|
||||
struct dlopen_args args;
|
||||
args.file = file;
|
||||
args.offset = 0;
|
||||
args.mode = mode;
|
||||
args.caller = DL_CALLER;
|
||||
|
||||
# ifdef SHARED
|
||||
return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
|
||||
# else
|
||||
if (_dlerror_run (dlopen_doit, &args))
|
||||
return NULL;
|
||||
|
||||
__libc_register_dl_open_hook ((struct link_map *) args.new);
|
||||
__libc_register_dlfcn_hook ((struct link_map *) args.new);
|
||||
|
||||
return args.new;
|
||||
# endif
|
||||
return __dlopen_common (&args);
|
||||
}
|
||||
# ifdef SHARED
|
||||
# include <shlib-compat.h>
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ dlopen_doit (void *a)
|
||||
{
|
||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->new = GLRO(dl_open) (args->file ?: "", 0, args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->file == NULL ? LM_ID_BASE : NS,
|
||||
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||
|
||||
@@ -422,6 +422,7 @@ CFLAGS-ldconfig.c = $(SYSCONF-FLAGS) -D'LIBDIR="$(libdir)"' \
|
||||
CFLAGS-dl-cache.c = $(SYSCONF-FLAGS)
|
||||
CFLAGS-cache.c = $(SYSCONF-FLAGS)
|
||||
CFLAGS-rtld.c = $(SYSCONF-FLAGS)
|
||||
CFLAGS-dl-support.c = $(SYSCONF-FLAGS)
|
||||
|
||||
CPPFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\
|
||||
-DNOT_IN_libc=1 -DIS_IN_rtld=1 -DIN_LIB=rtld)
|
||||
|
||||
@@ -53,6 +53,7 @@ ld {
|
||||
_dl_allocate_tls; _dl_allocate_tls_init;
|
||||
_dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
|
||||
_dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory;
|
||||
_dl_clear_dtv;
|
||||
_dl_rtld_di_serinfo; _dl_starting_up; _dl_tls_setup;
|
||||
_rtld_global; _rtld_global_ro;
|
||||
|
||||
@@ -61,5 +62,17 @@ ld {
|
||||
|
||||
# Pointer protection.
|
||||
__pointer_chk_guard;
|
||||
|
||||
# Google-local
|
||||
_google_dl_debug_state_hook;
|
||||
__google_auxv;
|
||||
|
||||
# Expose __signal_safe* functions so we can use a different
|
||||
# implementation (Google-local)
|
||||
__signal_safe_calloc;
|
||||
__signal_safe_free;
|
||||
__signal_safe_malloc;
|
||||
__signal_safe_memalign;
|
||||
__signal_safe_realloc;
|
||||
}
|
||||
}
|
||||
|
||||
+148
-41
@@ -29,10 +29,19 @@
|
||||
# define _DL_PLATFORMS_COUNT 0
|
||||
#endif
|
||||
|
||||
/* This is the starting address and the size of the mmap()ed file. */
|
||||
static struct cache_file *cache;
|
||||
static struct cache_file_new *cache_new;
|
||||
static size_t cachesize;
|
||||
/* This struct describes a single ld.so.cache (there could be several,
|
||||
as we want to look in $prefix/etc/ld.so.cache and in the system default
|
||||
/etc/ld.so.cache). See b/2471323. */
|
||||
struct cache_info {
|
||||
const char *ld_so_cache;
|
||||
/* This is the starting address and the size of the mmap()ed file. */
|
||||
struct cache_file *cache;
|
||||
struct cache_file_new *cache_new;
|
||||
size_t cachesize;
|
||||
};
|
||||
|
||||
/* Dynamically allocated; last entry is sentinel with ld_so_cache == NULL. */
|
||||
static struct cache_info *cache_info;
|
||||
|
||||
/* 1 if cache_data + PTR points into the cache. */
|
||||
#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size)
|
||||
@@ -172,13 +181,14 @@ _dl_cache_libcmp (const char *p1, const char *p2)
|
||||
}
|
||||
|
||||
|
||||
/* Look up NAME in ld.so.cache and return the file name stored there, or null
|
||||
if none is found. The cache is loaded if it was not already. If loading
|
||||
the cache previously failed there will be no more attempts to load it. */
|
||||
|
||||
/* Look up NAME in ld.so.cache described by INFO and return the file name
|
||||
stored there, or null if none is found. The cache is loaded if it was not
|
||||
already. If loading the cache previously failed there will be no more
|
||||
attempts to load it. */
|
||||
static
|
||||
const char *
|
||||
internal_function
|
||||
_dl_load_cache_lookup (const char *name)
|
||||
_dl_load_cache_lookup_2 (const char *name, struct cache_info *info)
|
||||
{
|
||||
int left, right, middle;
|
||||
int cmpres;
|
||||
@@ -188,12 +198,13 @@ _dl_load_cache_lookup (const char *name)
|
||||
|
||||
/* Print a message if the loading of libs is traced. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
||||
_dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
|
||||
_dl_debug_printf (" search cache=%s\n", info->ld_so_cache);
|
||||
|
||||
if (cache == NULL)
|
||||
if (info->cache == NULL)
|
||||
{
|
||||
/* Read the contents of the file. */
|
||||
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
|
||||
void *file = _dl_sysdep_read_whole_file (info->ld_so_cache,
|
||||
&info->cachesize,
|
||||
PROT_READ);
|
||||
|
||||
/* We can handle three different cache file formats here:
|
||||
@@ -201,55 +212,58 @@ _dl_load_cache_lookup (const char *name)
|
||||
- the old format with the new format in it
|
||||
- only the new format
|
||||
The following checks if the cache contains any of these formats. */
|
||||
if (file != MAP_FAILED && cachesize > sizeof *cache
|
||||
if (file != MAP_FAILED && info->cachesize > sizeof *info->cache
|
||||
&& memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
|
||||
{
|
||||
size_t offset;
|
||||
/* Looks ok. */
|
||||
cache = file;
|
||||
info->cache = file;
|
||||
|
||||
/* Check for new version. */
|
||||
offset = ALIGN_CACHE (sizeof (struct cache_file)
|
||||
+ cache->nlibs * sizeof (struct file_entry));
|
||||
offset =
|
||||
ALIGN_CACHE (sizeof (struct cache_file)
|
||||
+ info->cache->nlibs * sizeof (struct file_entry));
|
||||
|
||||
cache_new = (struct cache_file_new *) ((void *) cache + offset);
|
||||
if (cachesize < (offset + sizeof (struct cache_file_new))
|
||||
|| memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
|
||||
info->cache_new =
|
||||
(struct cache_file_new *) ((void *) info->cache + offset);
|
||||
if (info->cachesize < (offset + sizeof (struct cache_file_new))
|
||||
|| memcmp (info->cache_new->magic, CACHEMAGIC_VERSION_NEW,
|
||||
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
|
||||
cache_new = (void *) -1;
|
||||
info->cache_new = (void *) -1;
|
||||
}
|
||||
else if (file != MAP_FAILED && cachesize > sizeof *cache_new
|
||||
else if (file != MAP_FAILED && info->cachesize > sizeof *info->cache_new
|
||||
&& memcmp (file, CACHEMAGIC_VERSION_NEW,
|
||||
sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
|
||||
{
|
||||
cache_new = file;
|
||||
cache = file;
|
||||
info->cache_new = file;
|
||||
info->cache = file;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file != MAP_FAILED)
|
||||
__munmap (file, cachesize);
|
||||
cache = (void *) -1;
|
||||
__munmap (file, info->cachesize);
|
||||
info->cache = (void *) -1;
|
||||
}
|
||||
|
||||
assert (cache != NULL);
|
||||
assert (info->cache != NULL);
|
||||
}
|
||||
|
||||
if (cache == (void *) -1)
|
||||
if (info->cache == (void *) -1)
|
||||
/* Previously looked for the cache file and didn't find it. */
|
||||
return NULL;
|
||||
|
||||
best = NULL;
|
||||
|
||||
if (cache_new != (void *) -1)
|
||||
if (info->cache_new != (void *) -1)
|
||||
{
|
||||
uint64_t platform;
|
||||
|
||||
/* This is where the strings start. */
|
||||
cache_data = (const char *) cache_new;
|
||||
cache_data = (const char *) info->cache_new;
|
||||
|
||||
/* Now we can compute how large the string table is. */
|
||||
cache_data_size = (const char *) cache + cachesize - cache_data;
|
||||
cache_data_size =
|
||||
(const char *) info->cache + info->cachesize - cache_data;
|
||||
|
||||
platform = _dl_string_platform (GLRO(dl_platform));
|
||||
if (platform != (uint64_t) -1)
|
||||
@@ -269,19 +283,20 @@ _dl_load_cache_lookup (const char *name)
|
||||
&& (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \
|
||||
&& (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \
|
||||
continue
|
||||
SEARCH_CACHE (cache_new);
|
||||
SEARCH_CACHE (info->cache_new);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is where the strings start. */
|
||||
cache_data = (const char *) &cache->libs[cache->nlibs];
|
||||
cache_data = (const char *) &info->cache->libs[info->cache->nlibs];
|
||||
|
||||
/* Now we can compute how large the string table is. */
|
||||
cache_data_size = (const char *) cache + cachesize - cache_data;
|
||||
cache_data_size =
|
||||
(const char *) info->cache + info->cachesize - cache_data;
|
||||
|
||||
#undef HWCAP_CHECK
|
||||
#define HWCAP_CHECK do {} while (0)
|
||||
SEARCH_CACHE (cache);
|
||||
SEARCH_CACHE (info->cache);
|
||||
}
|
||||
|
||||
/* Print our result if wanted. */
|
||||
@@ -292,18 +307,110 @@ _dl_load_cache_lookup (const char *name)
|
||||
return best;
|
||||
}
|
||||
|
||||
/* Parse CACHE_LIST, and build cache_info array. */
|
||||
static
|
||||
struct cache_info *
|
||||
_dl_alloc_cache_info (const char *const cache_list)
|
||||
{
|
||||
struct cache_info *info;
|
||||
const char *begin;
|
||||
int num_caches, i;
|
||||
|
||||
begin = cache_list;
|
||||
num_caches = 0;
|
||||
|
||||
/* cache_list is a colon-separated list of absolute pathnames of
|
||||
ld.so.cache files. We stop at first non-absolute path (if any). */
|
||||
while (begin[0] == '/')
|
||||
{
|
||||
++num_caches;
|
||||
begin = strchr (begin, ':');
|
||||
if (begin == NULL)
|
||||
break;
|
||||
++begin;
|
||||
}
|
||||
|
||||
/* Allocate one extra for the sentinel. */
|
||||
info = (struct cache_info *) calloc (num_caches + 1, sizeof (*cache_info));
|
||||
|
||||
begin = cache_list;
|
||||
for (i = 0; i < num_caches; ++i)
|
||||
{
|
||||
const char *const end = strchr(begin, ':');
|
||||
|
||||
if (end == NULL)
|
||||
info[i].ld_so_cache = strdup (begin);
|
||||
else
|
||||
{
|
||||
info[i].ld_so_cache = strndup (begin, end - begin);
|
||||
begin = end + 1;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/* Look up NAME in each of ld.so.cache caches in turn, and return the
|
||||
file name stored there, or null if none is found. */
|
||||
const char *
|
||||
internal_function
|
||||
_dl_load_cache_lookup (const char *name, int mode)
|
||||
{
|
||||
struct cache_info *info;
|
||||
|
||||
/* This runs at startup, or during dlopen with loader lock held. */
|
||||
if (cache_info == NULL)
|
||||
/* Caches have not been initialized yet. */
|
||||
cache_info = _dl_alloc_cache_info (GLRO(google_ld_so_cache_list));
|
||||
|
||||
if (mode & __RTLD_GOOGLE_IGNORE_HOST_LD_SO_CACHE)
|
||||
{
|
||||
/* We are loading a component of glibc itself (e.g. nss or iconv).
|
||||
Such components must not be loaded from host, only from this
|
||||
glibc compilation (which must always be the first component of
|
||||
the cache list). See b/3133396 */
|
||||
|
||||
return _dl_load_cache_lookup_2 (name, cache_info);
|
||||
}
|
||||
|
||||
for (info = cache_info; info->ld_so_cache != NULL; ++info)
|
||||
{
|
||||
const char *result;
|
||||
|
||||
result = _dl_load_cache_lookup_2 (name, info);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef MAP_COPY
|
||||
/* If the system does not support MAP_COPY we cannot leave the file open
|
||||
all the time since this would create problems when the file is replaced.
|
||||
Therefore we provide this function to close the file and open it again
|
||||
once needed. */
|
||||
Therefore we provide this function to close the file described by INFO
|
||||
and open it again once needed. */
|
||||
static
|
||||
void
|
||||
_dl_unload_cache_2 (struct cache_info *info)
|
||||
{
|
||||
if (info->cache != NULL && info->cache != (struct cache_file *) -1)
|
||||
{
|
||||
__munmap (info->cache, info->cachesize);
|
||||
info->cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unload all loaded ld.so.cache caches. */
|
||||
void
|
||||
_dl_unload_cache (void)
|
||||
{
|
||||
if (cache != NULL && cache != (struct cache_file *) -1)
|
||||
{
|
||||
__munmap (cache, cachesize);
|
||||
cache = NULL;
|
||||
}
|
||||
struct cache_info *info;
|
||||
|
||||
if (cache_info == NULL)
|
||||
/* No caches loaded yet. */
|
||||
return;
|
||||
|
||||
for (info = cache_info; info->ld_so_cache != NULL; ++info)
|
||||
_dl_unload_cache_2 (info);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -133,6 +133,12 @@ _dl_close_worker (struct link_map *map)
|
||||
Lmid_t nsid = map->l_ns;
|
||||
struct link_namespaces *ns = &GL(dl_ns)[nsid];
|
||||
|
||||
/* Recompute _ns_last next time we need it.
|
||||
It is tempting to set _ns_last to map->l_prev, but map->l_prev might also
|
||||
be going away as part of current dlclose, and using it may cause _ns_last
|
||||
to become dangling. */
|
||||
ns->_ns_last = NULL;
|
||||
|
||||
retry:
|
||||
dl_close_state = pending;
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
}
|
||||
|
||||
|
||||
void (*_google_dl_debug_state_hook)(const struct r_debug *);
|
||||
|
||||
/* This function exists solely to have a breakpoint set on it by the
|
||||
debugger. The debugger is supposed to find this function's address by
|
||||
examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
|
||||
@@ -72,5 +74,7 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
void
|
||||
_dl_debug_state (void)
|
||||
{
|
||||
if (_google_dl_debug_state_hook)
|
||||
_google_dl_debug_state_hook(&_r_debug);
|
||||
}
|
||||
rtld_hidden_def (_dl_debug_state)
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ openaux (void *a)
|
||||
{
|
||||
struct openaux_args *args = (struct openaux_args *) a;
|
||||
|
||||
args->aux = _dl_map_object (args->map, args->name,
|
||||
args->aux = _dl_map_object (args->map, args->name, 0,
|
||||
(args->map->l_type == lt_executable
|
||||
? lt_library : args->map->l_type),
|
||||
args->trace_mode, args->open_mode,
|
||||
|
||||
+7
-2
@@ -65,8 +65,13 @@
|
||||
else \
|
||||
dst_len = (l)->l_origin == (char *) -1 \
|
||||
? 0 : strlen ((l)->l_origin); \
|
||||
dst_len = MAX (MAX (dst_len, GLRO(dl_platformlen)), \
|
||||
strlen (DL_DST_LIB)); \
|
||||
\
|
||||
char *exec_origin = GLRO(google_exec_origin_dir); \
|
||||
size_t exec_origin_len = \
|
||||
(exec_origin == NULL) ? 0 : strlen (exec_origin); \
|
||||
\
|
||||
dst_len = MAX (MAX (MAX (dst_len, GLRO(dl_platformlen)), \
|
||||
strlen (DL_DST_LIB)), exec_origin_len); \
|
||||
if (dst_len > 4) \
|
||||
__len += __cnt * (dst_len - 4); \
|
||||
} \
|
||||
|
||||
@@ -80,6 +80,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
|
||||
}
|
||||
|
||||
|
||||
ElfW(auxv_t) *__google_auxv;
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
@@ -88,6 +90,17 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
|
||||
unsigned int i;
|
||||
|
||||
/* _dl_init is called from _dl_start_user during loader startup.
|
||||
It is also called from dl_open_worker.
|
||||
Prevent multiple initialization of __google_auxv. */
|
||||
if (__google_auxv == NULL)
|
||||
{
|
||||
char **e;
|
||||
|
||||
for (e = env; *e; ++e) /* Skip. */;
|
||||
__google_auxv = (ElfW(auxv_t) *) ++e;
|
||||
}
|
||||
|
||||
if (__builtin_expect (GL(dl_initfirst) != NULL, 0))
|
||||
{
|
||||
call_init (GL(dl_initfirst), argc, argv, env);
|
||||
|
||||
+5
-3
@@ -59,6 +59,7 @@ struct do_dlopen_args
|
||||
{
|
||||
/* Argument to do_dlopen. */
|
||||
const char *name;
|
||||
off_t offset;
|
||||
/* Opening mode. */
|
||||
int mode;
|
||||
/* This is the caller of the dlopen() function. */
|
||||
@@ -84,9 +85,9 @@ do_dlopen (void *ptr)
|
||||
{
|
||||
struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
|
||||
/* Open and relocate the shared object. */
|
||||
args->map = GLRO(dl_open) (args->name, args->mode, args->caller_dlopen,
|
||||
__LM_ID_CALLER, __libc_argc, __libc_argv,
|
||||
__environ);
|
||||
args->map = GLRO(dl_open) (args->name, args->offset, args->mode,
|
||||
args->caller_dlopen, __LM_ID_CALLER,
|
||||
__libc_argc, __libc_argv, __environ);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -154,6 +155,7 @@ __libc_dlopen_mode (const char *name, int mode)
|
||||
{
|
||||
struct do_dlopen_args args;
|
||||
args.name = name;
|
||||
args.offset = 0;
|
||||
args.mode = mode;
|
||||
args.caller_dlopen = RETURN_ADDRESS (0);
|
||||
|
||||
|
||||
+113
-47
@@ -38,6 +38,7 @@
|
||||
#include <stap-probe.h>
|
||||
|
||||
#include <dl-dst.h>
|
||||
#include <_itoa.h>
|
||||
|
||||
/* On some systems, no flag bits are given to specify file mapping. */
|
||||
#ifndef MAP_FILE
|
||||
@@ -306,7 +307,8 @@ _dl_dst_count (const char *name, int is_path)
|
||||
if ((len = is_dst (start, name, "ORIGIN", is_path,
|
||||
INTUSE(__libc_enable_secure))) != 0
|
||||
|| (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
|
||||
|| (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
|
||||
|| (len = is_dst (start, name, "LIB", is_path, 0)) != 0
|
||||
|| (len = is_dst (start, name, "EXEC_ORIGIN", is_path, 0)) != 0)
|
||||
++cnt;
|
||||
|
||||
name = strchr (name + len, '$');
|
||||
@@ -350,6 +352,13 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
|
||||
repl = GLRO(dl_platform);
|
||||
else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
|
||||
repl = DL_DST_LIB;
|
||||
else if ((len = is_dst (start, name, "EXEC_ORIGIN", is_path, 0)) != 0)
|
||||
{
|
||||
if (INTUSE(__libc_enable_secure) != 0)
|
||||
_dl_fatal_printf ("$EXEC_ORIGIN rpath entry not allowed in setuid/setgid executables.\n");
|
||||
|
||||
repl = GLRO(google_exec_origin_dir);
|
||||
}
|
||||
|
||||
if (repl != NULL && repl != (const char *) -1)
|
||||
{
|
||||
@@ -917,7 +926,8 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||
static
|
||||
#endif
|
||||
struct link_map *
|
||||
_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
_dl_map_object_from_fd (const char *name, int fd, off_t offset,
|
||||
struct filebuf *fbp,
|
||||
char *realname, struct link_map *loader, int l_type,
|
||||
int mode, void **stack_endp, Lmid_t nsid)
|
||||
{
|
||||
@@ -947,7 +957,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
|
||||
/* Look again to see if the real name matched another already loaded. */
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
if (l->l_removed == 0 && l->l_ino == st.st_ino && l->l_dev == st.st_dev)
|
||||
if (l->l_removed == 0 && l->l_ino == st.st_ino && l->l_dev == st.st_dev
|
||||
&& l->l_off == offset)
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
@@ -956,7 +967,10 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
/* If the name is not in the list of names for this object add
|
||||
it. */
|
||||
free (realname);
|
||||
add_name_to_object (l, name);
|
||||
if (offset == 0)
|
||||
/* If offset!=0, foo.so/@0x<offset> should be the *only*
|
||||
name for this object. b/20141439. */
|
||||
add_name_to_object (l, name);
|
||||
|
||||
return l;
|
||||
}
|
||||
@@ -1055,8 +1069,30 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
else
|
||||
assert (r->r_state == RT_ADD);
|
||||
|
||||
#ifdef SHARED
|
||||
// This code could be linked into 'sln', which does not have _itoa.
|
||||
// We only care about this when this is linked into ld-linux.
|
||||
if (offset != 0)
|
||||
{
|
||||
/* Google-specific: to help GDB, and for b/18243822, turn realname
|
||||
into "realname/@0x<offset>" */
|
||||
realname = realloc (realname, strlen(realname) + 16 + 4 /* "/@0x" */);
|
||||
if (realname == NULL)
|
||||
{
|
||||
errstring = N_("unable to realloc");
|
||||
goto call_lose_errno;
|
||||
}
|
||||
strcat(realname, "/@0x");
|
||||
|
||||
char tmp[20];
|
||||
tmp[19] = '\0';
|
||||
strcat(realname, _itoa(offset, &tmp[19], 16, 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enter the new object in the list of loaded objects. */
|
||||
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
||||
l = _dl_new_object (realname, offset ? realname : name, l_type,
|
||||
loader, mode, nsid);
|
||||
if (__builtin_expect (l == NULL, 0))
|
||||
{
|
||||
#ifdef SHARED
|
||||
@@ -1144,7 +1180,12 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
c->dataend = ph->p_vaddr + ph->p_filesz;
|
||||
c->allocend = ph->p_vaddr + ph->p_memsz;
|
||||
c->mapoff = ph->p_offset & ~(GLRO(dl_pagesize) - 1);
|
||||
if (offset & (GLRO(dl_pagesize) - 1))
|
||||
{
|
||||
errstring = N_("invalid offset");
|
||||
goto call_lose;
|
||||
}
|
||||
c->mapoff = offset + ph->p_offset & ~(GLRO(dl_pagesize) - 1);
|
||||
|
||||
/* Determine whether there is a gap between the last segment
|
||||
and this one. */
|
||||
@@ -1583,6 +1624,7 @@ cannot enable executable stack as shared object requires");
|
||||
/* Finally the file information. */
|
||||
l->l_dev = st.st_dev;
|
||||
l->l_ino = st.st_ino;
|
||||
l->l_off = offset;
|
||||
|
||||
/* When we profile the SONAME might be needed for something else but
|
||||
loading. Add it right away. */
|
||||
@@ -1666,7 +1708,8 @@ print_search_path (struct r_search_path_elem **list,
|
||||
this could mean there is something wrong in the installation and the
|
||||
user might want to know about this. */
|
||||
static int
|
||||
open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
|
||||
open_verify (const char *name, off_t offset,
|
||||
struct filebuf *fbp, struct link_map *loader,
|
||||
int whatcode, bool *found_other_class, bool free_name)
|
||||
{
|
||||
/* This is the expected ELF header. */
|
||||
@@ -1734,6 +1777,9 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
|
||||
unsigned int osversion;
|
||||
size_t maplength;
|
||||
|
||||
if (__lseek (fd, offset, SEEK_SET) == -1)
|
||||
goto close_and_out;
|
||||
|
||||
/* We successfully opened the file. Now verify it is a file
|
||||
we can use. */
|
||||
__set_errno (0);
|
||||
@@ -1928,7 +1974,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
|
||||
if MAY_FREE_DIRS is true. */
|
||||
|
||||
static int
|
||||
open_path (const char *name, size_t namelen, int secure,
|
||||
open_path (const char *name, size_t namelen, off_t offset, int secure,
|
||||
struct r_search_path_struct *sps, char **realname,
|
||||
struct filebuf *fbp, struct link_map *loader, int whatcode,
|
||||
bool *found_other_class)
|
||||
@@ -1980,8 +2026,8 @@ open_path (const char *name, size_t namelen, int secure,
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
||||
_dl_debug_printf (" trying file=%s\n", buf);
|
||||
|
||||
fd = open_verify (buf, fbp, loader, whatcode, found_other_class,
|
||||
false);
|
||||
fd = open_verify (buf, offset, fbp, loader, whatcode,
|
||||
found_other_class, false);
|
||||
if (this_dir->status[cnt] == unknown)
|
||||
{
|
||||
if (fd != -1)
|
||||
@@ -2075,11 +2121,42 @@ open_path (const char *name, size_t namelen, int secure,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
match_one (const char *name, struct link_map *l)
|
||||
{
|
||||
/* If the requested name matches the soname of a loaded object,
|
||||
use that object. Elide this check for names that have not
|
||||
yet been opened. */
|
||||
if (__builtin_expect (l->l_faked, 0) != 0
|
||||
|| __builtin_expect (l->l_removed, 0) != 0)
|
||||
return 0;
|
||||
if (!_dl_name_match_p (name, l))
|
||||
{
|
||||
const char *soname;
|
||||
|
||||
if (__builtin_expect (l->l_soname_added, 1)
|
||||
|| l->l_info[DT_SONAME] == NULL)
|
||||
return 0;
|
||||
|
||||
soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
|
||||
+ l->l_info[DT_SONAME]->d_un.d_val);
|
||||
if (strcmp (name, soname) != 0)
|
||||
return 0;
|
||||
|
||||
/* We have a match on a new name -- cache it. */
|
||||
add_name_to_object (l, soname);
|
||||
l->l_soname_added = 1;
|
||||
}
|
||||
|
||||
/* We have a match. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Map in the shared object file NAME. */
|
||||
|
||||
struct link_map *
|
||||
internal_function
|
||||
_dl_map_object (struct link_map *loader, const char *name,
|
||||
_dl_map_object (struct link_map *loader, const char *name, off_t offset,
|
||||
int type, int trace_mode, int mode, Lmid_t nsid)
|
||||
{
|
||||
int fd;
|
||||
@@ -2092,34 +2169,21 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
assert (nsid < GL(dl_nns));
|
||||
|
||||
/* Look for this name among those already loaded. */
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
if (name[0] == '\0')
|
||||
{
|
||||
/* If the requested name matches the soname of a loaded object,
|
||||
use that object. Elide this check for names that have not
|
||||
yet been opened. */
|
||||
if (__builtin_expect (l->l_faked, 0) != 0
|
||||
|| __builtin_expect (l->l_removed, 0) != 0)
|
||||
continue;
|
||||
if (!_dl_name_match_p (name, l))
|
||||
{
|
||||
const char *soname;
|
||||
/* Special case: both main exe and vdso can have empty name;
|
||||
so search from head: it is important to return the map for main
|
||||
a.out; else dlsym(0, ...) will fail unexpectedly. */
|
||||
|
||||
if (__builtin_expect (l->l_soname_added, 1)
|
||||
|| l->l_info[DT_SONAME] == NULL)
|
||||
continue;
|
||||
|
||||
soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
|
||||
+ l->l_info[DT_SONAME]->d_un.d_val);
|
||||
if (strcmp (name, soname) != 0)
|
||||
continue;
|
||||
|
||||
/* We have a match on a new name -- cache it. */
|
||||
add_name_to_object (l, soname);
|
||||
l->l_soname_added = 1;
|
||||
}
|
||||
|
||||
/* We have a match. */
|
||||
return l;
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
if (match_one (name, l))
|
||||
return l;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (l = _dl_last_entry (&GL(dl_ns)[nsid]); l; l = l->l_prev)
|
||||
if (match_one (name, l))
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Display information if we are debugging. */
|
||||
@@ -2184,7 +2248,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
for (l = loader; l; l = l->l_loader)
|
||||
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||
{
|
||||
fd = open_path (name, namelen, mode & __RTLD_SECURE,
|
||||
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
|
||||
&l->l_rpath_dirs,
|
||||
&realname, &fb, loader, LA_SER_RUNPATH,
|
||||
&found_other_class);
|
||||
@@ -2200,7 +2264,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
&& main_map != NULL && main_map->l_type != lt_loaded
|
||||
&& cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
|
||||
"RPATH"))
|
||||
fd = open_path (name, namelen, mode & __RTLD_SECURE,
|
||||
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
|
||||
&main_map->l_rpath_dirs,
|
||||
&realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
|
||||
&found_other_class);
|
||||
@@ -2208,7 +2272,8 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
|
||||
/* Try the LD_LIBRARY_PATH environment variable. */
|
||||
if (fd == -1 && env_path_list.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, mode & __RTLD_SECURE, &env_path_list,
|
||||
fd = open_path (name, namelen, offset,
|
||||
mode & __RTLD_SECURE, &env_path_list,
|
||||
&realname, &fb,
|
||||
loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
|
||||
LA_SER_LIBPATH, &found_other_class);
|
||||
@@ -2217,7 +2282,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
if (fd == -1 && loader != NULL
|
||||
&& cache_rpath (loader, &loader->l_runpath_dirs,
|
||||
DT_RUNPATH, "RUNPATH"))
|
||||
fd = open_path (name, namelen, mode & __RTLD_SECURE,
|
||||
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
|
||||
&loader->l_runpath_dirs, &realname, &fb, loader,
|
||||
LA_SER_RUNPATH, &found_other_class);
|
||||
|
||||
@@ -2229,7 +2294,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
{
|
||||
/* Check the list of libraries in the file /etc/ld.so.cache,
|
||||
for compatibility with Linux's ldconfig program. */
|
||||
const char *cached = _dl_load_cache_lookup (name);
|
||||
const char *cached = _dl_load_cache_lookup (name, mode);
|
||||
|
||||
if (cached != NULL)
|
||||
{
|
||||
@@ -2265,7 +2330,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
|
||||
if (cached != NULL)
|
||||
{
|
||||
fd = open_verify (cached,
|
||||
fd = open_verify (cached, 0,
|
||||
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
|
||||
LA_SER_CONFIG, &found_other_class, false);
|
||||
if (__builtin_expect (fd != -1, 1))
|
||||
@@ -2287,7 +2352,8 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
&& ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
|
||||
|| __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
|
||||
&& rtld_search_dirs.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, mode & __RTLD_SECURE, &rtld_search_dirs,
|
||||
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
|
||||
&rtld_search_dirs,
|
||||
&realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
|
||||
|
||||
/* Add another newline when we are tracing the library loading. */
|
||||
@@ -2304,7 +2370,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
fd = -1;
|
||||
else
|
||||
{
|
||||
fd = open_verify (realname, &fb,
|
||||
fd = open_verify (realname, offset, &fb,
|
||||
loader ?: GL(dl_ns)[nsid]._ns_loaded, 0,
|
||||
&found_other_class, true);
|
||||
if (__builtin_expect (fd, 0) == -1)
|
||||
@@ -2366,8 +2432,8 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
}
|
||||
|
||||
void *stack_end = __libc_stack_end;
|
||||
return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
|
||||
&stack_end, nsid);
|
||||
return _dl_map_object_from_fd (name, fd, offset, &fb, realname, loader, type,
|
||||
mode, &stack_end, nsid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+475
@@ -33,6 +33,11 @@
|
||||
|
||||
#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
|
||||
|
||||
#ifndef ADDRIDX
|
||||
# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
||||
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
|
||||
#endif
|
||||
|
||||
/* We need this string more than once. */
|
||||
static const char undefined_msg[] = "undefined symbol: ";
|
||||
|
||||
@@ -68,6 +73,450 @@ struct sym_val
|
||||
# define bump_num_relocations() ((void) 0)
|
||||
#endif
|
||||
|
||||
/* Bob Jenkins's hash function, free for any use.
|
||||
http://burtleburtle.net/bob/hash/ */
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
typedef unsigned int uint32 __attribute__ ((mode (SI)));
|
||||
static uint32
|
||||
hash_with_seed (const char *k, uint32 length, uint32 seed)
|
||||
{
|
||||
uint32 a, b, c, len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
c = seed; /* the previous hash value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
while (len >= 12)
|
||||
{
|
||||
a += (k[0] +((uint32)k[1]<<8) +((uint32)k[2]<<16) +((uint32)k[3]<<24));
|
||||
b += (k[4] +((uint32)k[5]<<8) +((uint32)k[6]<<16) +((uint32)k[7]<<24));
|
||||
c += (k[8] +((uint32)k[9]<<8) +((uint32)k[10]<<16)+((uint32)k[11]<<24));
|
||||
mix (a,b,c);
|
||||
k += 12;
|
||||
len -= 12;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += length;
|
||||
switch (len) /* all the case statements fall through */
|
||||
{
|
||||
case 11: c+=((uint32)k[10]<<24);
|
||||
case 10: c+=((uint32)k[9]<<16);
|
||||
case 9 : c+=((uint32)k[8]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 : b+=((uint32)k[7]<<24);
|
||||
case 7 : b+=((uint32)k[6]<<16);
|
||||
case 6 : b+=((uint32)k[5]<<8);
|
||||
case 5 : b+=k[4];
|
||||
case 4 : a+=((uint32)k[3]<<24);
|
||||
case 3 : a+=((uint32)k[2]<<16);
|
||||
case 2 : a+=((uint32)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix (a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* A hash table used to speed up lookups when we have a lot of shared
|
||||
libraries. We record in the table how many ELF objects in the link
|
||||
map we can safely skip, because they are known to not contain the symbol
|
||||
we are looking for.
|
||||
|
||||
Values start out at N (num objects in the main_map). We then go through
|
||||
each object (executable or DSO) in their order in the main_map and insert
|
||||
pos_in_map_map into the table.
|
||||
|
||||
If there is already an earlier (smaller) entry in the table, we leave it
|
||||
alone. It could be a hash collision, or it could be an earlier
|
||||
instance of the same symbol (eg weak __stdout definition in
|
||||
multiple objects).
|
||||
|
||||
To save space, the table contains uint16_t entries, and so we can't
|
||||
record main map positions over 65535.
|
||||
|
||||
It turns out that even when only 25% of slots are used, collision
|
||||
rate is around 10%, which is quite high, and causes lookups to be slow.
|
||||
|
||||
So we use a second table (using a different hash seed). Hash collisions
|
||||
using two separate hashes are quite rare.
|
||||
|
||||
Note that we allocate the two tables together (a single block twice
|
||||
the size of one table). */
|
||||
|
||||
static void
|
||||
insert_into_hash_table_1 (int pos_in_main_map, const char *symbol_name,
|
||||
size_t name_len, dl_position_table_entry_t *table,
|
||||
int seed)
|
||||
{
|
||||
uint32 hash = hash_with_seed (symbol_name, name_len, seed);
|
||||
int pos = hash & GLRO(dl_position_hash_mask);
|
||||
if (pos_in_main_map < table[pos])
|
||||
{
|
||||
table[pos] = pos_in_main_map;
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload hash for %s: [%u] = %u (table %u)\n",
|
||||
symbol_name, (unsigned int) pos,
|
||||
(unsigned int) table[pos],
|
||||
(GLRO(dl_position_hash_table) == table) ? 0 : 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf
|
||||
("fastload hash for %s: [%u] already set to %u <= %u (table %u)\n",
|
||||
symbol_name, (unsigned int) pos,
|
||||
(unsigned int) table[pos],
|
||||
(unsigned int) pos_in_main_map,
|
||||
(GLRO(dl_position_hash_table) == table) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
#define HASH_SEED_A 0
|
||||
#define HASH_SEED_B 5381 /* As good as any other value. */
|
||||
|
||||
static void
|
||||
insert_into_hash_table (int pos_in_main_map, const char *symbol_name)
|
||||
{
|
||||
dl_position_table_entry_t *const table1 = GLRO(dl_position_hash_table);
|
||||
const int table_size = GLRO(dl_position_hash_mask) + 1;
|
||||
dl_position_table_entry_t *const table2 = table1 + table_size;
|
||||
const size_t name_len = strlen (symbol_name);
|
||||
|
||||
insert_into_hash_table_1 (pos_in_main_map, symbol_name, name_len, table1,
|
||||
HASH_SEED_A);
|
||||
insert_into_hash_table_1 (pos_in_main_map, symbol_name, name_len, table2,
|
||||
HASH_SEED_B);
|
||||
}
|
||||
|
||||
static inline int
|
||||
earliest_pos_from_hash_table_1 (const char *symbol_name,
|
||||
const dl_position_table_entry_t *table,
|
||||
int seed)
|
||||
{
|
||||
int pos;
|
||||
uint32 hash;
|
||||
|
||||
hash = hash_with_seed (symbol_name, strlen (symbol_name), seed);
|
||||
pos = hash & GLRO(dl_position_hash_mask);
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf
|
||||
("fastload earliest pos for %s: [%u] = %u (table %u)\n",
|
||||
symbol_name, (unsigned int) pos, (unsigned int) table[pos],
|
||||
(GLRO(dl_position_hash_table) == table) ? 0 : 1);
|
||||
|
||||
return table[pos];
|
||||
}
|
||||
|
||||
static inline int
|
||||
earliest_pos_from_hash_table (const char *undef_name)
|
||||
{
|
||||
dl_position_table_entry_t *const table1 = GLRO(dl_position_hash_table);
|
||||
|
||||
if (table1 == NULL)
|
||||
return 0; /* Search from the beginning of the list. */
|
||||
else
|
||||
{
|
||||
const int table_size = GLRO(dl_position_hash_mask) + 1;
|
||||
dl_position_table_entry_t *const table2 = table1 + table_size;
|
||||
const int skip_1 = earliest_pos_from_hash_table_1 (undef_name, table1,
|
||||
HASH_SEED_A);
|
||||
const int skip_2 = earliest_pos_from_hash_table_1 (undef_name, table2,
|
||||
HASH_SEED_B);
|
||||
|
||||
/* Possibilities:
|
||||
|
||||
* Both skip_1 and skip_2 are positive and same:
|
||||
there were no collisions at insertion in either table, or there
|
||||
was double-collision with symbols from the same library.
|
||||
|
||||
If skip_1 == skip_2 == N (num_directly_loaded_objects), then the
|
||||
slot was empty in both tables after they were filled (i.e. there
|
||||
is no symbol that hashes to corresponding slot). In that case,
|
||||
searching first [0, N) is pointless. See b/5609692.
|
||||
|
||||
True skip_to == skip_1 == skip_2.
|
||||
|
||||
* Both skip_1 and skip_2 are positive but different:
|
||||
there was a collision in one or both tables, or one of the slots
|
||||
remained unfilled after all symbols have been inserted.
|
||||
It is safe to start at max, true skip_to count can not be less
|
||||
than max. */
|
||||
|
||||
return (skip_1 < skip_2) ? skip_2 : skip_1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fill_hash_table (const struct link_map *const map, int pos_in_main_map,
|
||||
int num_symbols)
|
||||
{
|
||||
const ElfW(Sym) *const symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
||||
const char *const strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
||||
int k;
|
||||
|
||||
/* Iterate through the symbols defined in this map and insert them
|
||||
into the bloom filter. If the symbol wouldn't pass the tests in
|
||||
do_lookup_x(), then don't insert it. */
|
||||
for (k = 0; k < num_symbols; k++)
|
||||
{
|
||||
const ElfW(Sym) *sym = &symtab[k];
|
||||
|
||||
if (sym->st_value == 0
|
||||
&& ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
|
||||
continue;
|
||||
|
||||
switch (ELFW(ST_TYPE) (sym->st_info))
|
||||
{
|
||||
case STT_SECTION:
|
||||
case STT_FILE:
|
||||
case STT_COMMON:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ELFW(ST_BIND) (sym->st_info))
|
||||
{
|
||||
case STB_LOCAL: /* Local symbols are ignored. */
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
insert_into_hash_table (pos_in_main_map, strtab + sym->st_name);
|
||||
}
|
||||
}
|
||||
|
||||
static dl_position_table_entry_t *
|
||||
allocate_position_hash_table (size_t table_size, int max_pos)
|
||||
{
|
||||
/* Implementation detail: we actually allocate two "logical" tables in a
|
||||
single block. */
|
||||
|
||||
const size_t total_size = 2 * table_size;
|
||||
dl_position_table_entry_t *table
|
||||
= malloc (total_size * sizeof (dl_position_table_entry_t));
|
||||
|
||||
if (table == NULL)
|
||||
return NULL;
|
||||
|
||||
for (int k = 0; k < total_size; ++k)
|
||||
table[k] = max_pos;
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static int
|
||||
num_dynsyms (const struct link_map *const map)
|
||||
{
|
||||
if (map->l_info[DT_HASH] != NULL)
|
||||
{
|
||||
/* If DT_HASH is present, we unconditionally use it, since it already
|
||||
has the answer precomputed and waiting for us. */
|
||||
const Elf_Symndx *const hash = (void *) D_PTR (map, l_info[DT_HASH]);
|
||||
|
||||
if (hash != NULL)
|
||||
{
|
||||
/* DT_HASH dynamic structure points to a symbol hash table
|
||||
with the following layout:
|
||||
|
||||
nbucket
|
||||
nchain (== number of symbols in dynamic symbol table)
|
||||
bucket[0]
|
||||
...
|
||||
|
||||
http://refspecs.freestandards.org/elf/TIS1.1.pdf (p. 2.19). */
|
||||
|
||||
return hash[1];
|
||||
}
|
||||
}
|
||||
else if (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
|
||||
{
|
||||
/* The best documentation for GNU_HASH I found:
|
||||
http://blogs.sun.com/ali/entry/gnu_hash_elf_sections
|
||||
|
||||
_dl_setup_hash() has already set things up for us. */
|
||||
|
||||
if (__builtin_expect (map->l_nbuckets < 1, 0))
|
||||
{
|
||||
/* Paranoia: neither gold nor gnu-ld will construct an empty
|
||||
.gnu.hash, but some other linker just might. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In the GNU hash the symbol index of a symbol is determined by
|
||||
the offset of the symbol's entry in the hash table itself.
|
||||
|
||||
We start at the last bucket map->l_gnu_chain_zero[map->l_nbuckets-1]
|
||||
and loop backward from the end until we find a bucket which is
|
||||
not zero.
|
||||
|
||||
Then we walk forward to find the last entry in the chain which
|
||||
starts at that bucket. The terminating entry gives us desired
|
||||
symbol index. */
|
||||
|
||||
int last_bucket_idx = map->l_nbuckets - 1;
|
||||
|
||||
while (last_bucket_idx > 0 &&
|
||||
map->l_gnu_buckets[last_bucket_idx] == 0)
|
||||
{
|
||||
--last_bucket_idx;
|
||||
}
|
||||
|
||||
const Elf32_Word last_bucket = map->l_gnu_buckets[last_bucket_idx];
|
||||
|
||||
if (__builtin_expect (last_bucket == 0, 0))
|
||||
{
|
||||
/* This shouldn't happen unless the library has only static
|
||||
variables with global ctors, and nothing else. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start of the hash chain for the last non-zero bucket. */
|
||||
const Elf32_Word *hasharr = &map->l_gnu_chain_zero[last_bucket];
|
||||
|
||||
/* The chain is terminated by an entry with LSBit set. */
|
||||
while ((*hasharr & 1u) == 0)
|
||||
++hasharr;
|
||||
|
||||
/* Size of dynamic symbol table is "index of last symbol" + 1. */
|
||||
return hasharr - map->l_gnu_chain_zero + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the fastload position hash (if requested). Given a link_map
|
||||
containing all required objects, iterate through all symbols. For each
|
||||
symbol which could match in do_lookup_x, insert the index of the
|
||||
providing object in main_map. */
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_fill_position_hash (struct link_map *main_map)
|
||||
{
|
||||
const int num_objects = main_map->l_searchlist.r_nlist;
|
||||
const int debug_fastload = GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD;
|
||||
int k;
|
||||
|
||||
/* If we have more than dl_position_hash_cutoff shared libraries,
|
||||
fill in the hash table of earliest known positions for symbols in
|
||||
main_map. We'll use this in do_lookup_x(). */
|
||||
|
||||
/* If cutoff or size is negative, fastload is disabled. */
|
||||
if (GLRO(dl_position_hash_cutoff) < 0 || GLRO(dl_position_hash_bits) < 0)
|
||||
{
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: disabled (configuration)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we don't have enough mapped objects, fastload is disabled. */
|
||||
if (num_objects <= GLRO(dl_position_hash_cutoff))
|
||||
{
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: disabled (too few objects,"
|
||||
" %u <= cutoff %u)\n",
|
||||
num_objects, GLRO(dl_position_hash_cutoff));
|
||||
return;
|
||||
}
|
||||
|
||||
int *ndynsyms = NULL;
|
||||
|
||||
if (GLRO(dl_position_hash_bits) == 0)
|
||||
{
|
||||
/* Table size has not been specified via LD_FASTLOAD_HASH_BITS.
|
||||
Compute appropriate size for <= 25% load factor. */
|
||||
|
||||
int total_symbols = 0;
|
||||
|
||||
/* It is safe to call alloca() here, because we are executing in
|
||||
the context of dl_main, i.e. we are on the main stack, and are
|
||||
not yet using much of it. Assuming sane upper limit of 10K direct
|
||||
dependencies, we'll use at most 40K bytes here. */
|
||||
ndynsyms = alloca (num_objects * sizeof (int));
|
||||
|
||||
for (k = 0; k < num_objects; ++k)
|
||||
{
|
||||
const struct link_map *const map = main_map->l_searchlist.r_list[k];
|
||||
const int nsyms = num_dynsyms (map);
|
||||
|
||||
ndynsyms[k] = nsyms;
|
||||
total_symbols += nsyms;
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: %s: %u symbols\n", map->l_name, nsyms);
|
||||
}
|
||||
|
||||
/* Ensure table size is >= 4 * total_symbols. Generally this
|
||||
over-sizes the table by more than 4, since there usually are lots
|
||||
of duplicate symbols (from different DSOs) as well. */
|
||||
|
||||
GLRO(dl_position_hash_bits)
|
||||
= (8 * sizeof (total_symbols)) - __builtin_clz (total_symbols) + 2;
|
||||
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: will use %u hash bits for %u total "
|
||||
"symbols\n",
|
||||
GLRO(dl_position_hash_bits), total_symbols);
|
||||
}
|
||||
|
||||
/* If the requested or computed table size is too large, limit it. */
|
||||
if (GLRO(dl_position_hash_bits) > DL_POSITION_HASH_BITS_MAX)
|
||||
{
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: requested table too large"
|
||||
" (%u > max %u bits)\n",
|
||||
GLRO(dl_position_hash_bits),
|
||||
DL_POSITION_HASH_BITS_MAX);
|
||||
GLRO(dl_position_hash_bits) = DL_POSITION_HASH_BITS_MAX;
|
||||
}
|
||||
|
||||
int table_size = 1 << GLRO(dl_position_hash_bits);
|
||||
GLRO(dl_position_hash_mask) = table_size - 1;
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: enabled with %u entry table\n", table_size);
|
||||
|
||||
int max_pos = num_objects < DL_POSITION_MAX ? num_objects : DL_POSITION_MAX;
|
||||
GLRO(dl_position_hash_table) = allocate_position_hash_table (table_size,
|
||||
max_pos);
|
||||
if (GLRO(dl_position_hash_table) == NULL)
|
||||
{
|
||||
if (__builtin_expect (debug_fastload, 0))
|
||||
_dl_debug_printf ("fastload: failed to allocate table\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* There is no point in going beyond max_pos: the rest of the table
|
||||
has already been saturated with max_pos value. */
|
||||
for (k = 0; k < max_pos; ++k)
|
||||
{
|
||||
const struct link_map *const map = main_map->l_searchlist.r_list[k];
|
||||
|
||||
/* Reuse num_dynsyms() result we computed earlier if possible:
|
||||
recomputing it may be somewhat expensive with DT_GNU_HASH. */
|
||||
const int nsyms = ndynsyms ? ndynsyms[k] : num_dynsyms (map);
|
||||
|
||||
fill_hash_table (map, k, nsyms);
|
||||
}
|
||||
}
|
||||
|
||||
/* Inner part of the lookup functions. We return a value > 0 if we
|
||||
found the symbol, the value 0 if nothing is found and < 0 if
|
||||
@@ -88,6 +537,32 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
|
||||
__asm volatile ("" : "+r" (n), "+m" (scope->r_list));
|
||||
struct link_map **list = scope->r_list;
|
||||
|
||||
if (scope == GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist && i == 0)
|
||||
{
|
||||
const int skip_to = earliest_pos_from_hash_table (undef_name);
|
||||
|
||||
if (skip_to < n)
|
||||
{
|
||||
i = skip_to;
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload %s skipping to %u\n",
|
||||
undef_name, (unsigned int) i);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Symbol was not found in any of the initial libraries,
|
||||
and no new libraries have been added. */
|
||||
|
||||
assert (skip_to == n);
|
||||
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FASTLOAD, 0))
|
||||
_dl_debug_printf ("fastload %s, %u >= %u (scope->r_nlist)\n",
|
||||
undef_name, (unsigned int) skip_to,
|
||||
(unsigned int) n);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* These variables are used in the nested function. */
|
||||
|
||||
+142
@@ -19,6 +19,7 @@
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <libc-symbols.h>
|
||||
#include <limits.h>
|
||||
#include <link.h>
|
||||
#include <stdarg.h>
|
||||
@@ -364,3 +365,144 @@ _dl_higher_prime_number (unsigned long int n)
|
||||
|
||||
return *low;
|
||||
}
|
||||
|
||||
/* To support accessing TLS variables from signal handlers, we need an
|
||||
async signal safe memory allocator. These routines are never
|
||||
themselves invoked reentrantly (all calls to them are surrounded by
|
||||
signal masks) but may be invoked concurrently from many threads.
|
||||
The current implementation is not particularly performant nor space
|
||||
efficient, but it will be used rarely (and only in binaries that use
|
||||
dlopen.) The API matches that of malloc() and friends. */
|
||||
|
||||
struct __signal_safe_allocator_header
|
||||
{
|
||||
size_t size;
|
||||
void *start;
|
||||
};
|
||||
|
||||
static inline struct __signal_safe_allocator_header *
|
||||
ptr_to_signal_safe_allocator_header (void *ptr)
|
||||
{
|
||||
return (struct __signal_safe_allocator_header *)
|
||||
((char *) (ptr) - sizeof (struct __signal_safe_allocator_header));
|
||||
}
|
||||
|
||||
void *weak_function
|
||||
__signal_safe_memalign (size_t boundary, size_t size)
|
||||
{
|
||||
struct __signal_safe_allocator_header *header;
|
||||
|
||||
if (boundary < sizeof (*header))
|
||||
boundary = sizeof (*header);
|
||||
|
||||
/* Boundary must be a power of two. */
|
||||
if (!powerof2 (boundary))
|
||||
return NULL;
|
||||
|
||||
size_t pg = GLRO (dl_pagesize);
|
||||
size_t padded_size;
|
||||
if (boundary <= pg)
|
||||
{
|
||||
/* We'll get a pointer certainly aligned to boundary, so just
|
||||
add one more boundary-sized chunk to hold the header. */
|
||||
padded_size = roundup (size, boundary) + boundary;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we want K pages aligned to a J-page boundary, K+J+1 pages
|
||||
contains at least one such region that isn't directly at the start
|
||||
(so we can place the header.) This is wasteful, but you're the one
|
||||
who wanted 64K-aligned TLS. */
|
||||
padded_size = roundup (size, pg) + boundary + pg;
|
||||
}
|
||||
|
||||
|
||||
size_t actual_size = roundup (padded_size, pg);
|
||||
void *actual = mmap (NULL, actual_size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (actual == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
if (boundary <= pg)
|
||||
{
|
||||
header = actual + boundary - sizeof (*header);
|
||||
}
|
||||
else
|
||||
{
|
||||
intptr_t actual_pg = ((intptr_t) actual) / pg;
|
||||
intptr_t boundary_pg = boundary / pg;
|
||||
intptr_t start_pg = actual_pg + boundary_pg;
|
||||
start_pg -= start_pg % boundary_pg;
|
||||
if (start_pg > (actual_pg + 1))
|
||||
{
|
||||
int ret = munmap (actual, (start_pg - actual_pg - 1) * pg);
|
||||
assert (ret == 0);
|
||||
actual = (void *) ((start_pg - 1) * pg);
|
||||
}
|
||||
char *start = (void *) (start_pg * pg);
|
||||
header = ptr_to_signal_safe_allocator_header (start);
|
||||
}
|
||||
|
||||
header->size = actual_size;
|
||||
header->start = actual;
|
||||
void *ptr = header;
|
||||
ptr += sizeof (*header);
|
||||
if (((intptr_t) ptr) % boundary != 0)
|
||||
_dl_fatal_printf ("__signal_safe_memalign produced incorrect alignment\n");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * weak_function
|
||||
__signal_safe_malloc (size_t size)
|
||||
{
|
||||
return __signal_safe_memalign (1, size);
|
||||
}
|
||||
|
||||
void weak_function
|
||||
__signal_safe_free (void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
struct __signal_safe_allocator_header *header
|
||||
= ptr_to_signal_safe_allocator_header (ptr);
|
||||
int ret = munmap (header->start, header->size);
|
||||
|
||||
assert (ret == 0);
|
||||
}
|
||||
|
||||
void * weak_function
|
||||
__signal_safe_realloc (void *ptr, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
__signal_safe_free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (ptr == NULL)
|
||||
return __signal_safe_malloc (size);
|
||||
|
||||
struct __signal_safe_allocator_header *header
|
||||
= ptr_to_signal_safe_allocator_header (ptr);
|
||||
size_t old_size = header->size;
|
||||
if (old_size - sizeof (*header) >= size)
|
||||
return ptr;
|
||||
|
||||
void *new_ptr = __signal_safe_malloc (size);
|
||||
if (new_ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy (new_ptr, ptr, old_size);
|
||||
__signal_safe_free (ptr);
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void * weak_function
|
||||
__signal_safe_calloc (size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr = __signal_safe_malloc (nmemb * size);
|
||||
if (ptr == NULL)
|
||||
return NULL;
|
||||
return memset (ptr, 0, nmemb * size);
|
||||
}
|
||||
|
||||
+10
-4
@@ -45,6 +45,8 @@ extern int __libc_multiple_libcs; /* Defined in init-first.c. */
|
||||
struct dl_open_args
|
||||
{
|
||||
const char *file;
|
||||
/* ELF header at offset in file. */
|
||||
off_t offset;
|
||||
int mode;
|
||||
/* This is the caller of the dlopen() function. */
|
||||
const void *caller_dlopen;
|
||||
@@ -221,7 +223,7 @@ dl_open_worker (void *a)
|
||||
|
||||
/* Load the named object. */
|
||||
struct link_map *new;
|
||||
args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
|
||||
args->map = new = _dl_map_object (call_map, file, args->offset, lt_loaded, 0,
|
||||
mode | __RTLD_CALLMAP, args->nsid);
|
||||
|
||||
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
|
||||
@@ -548,7 +550,10 @@ cannot load any more object with static TLS"));
|
||||
generation of the DSO we are allocating data for. */
|
||||
_dl_update_slotinfo (imap->l_tls_modid);
|
||||
#endif
|
||||
|
||||
/* We do this iteration under a signal mask in dl-reloc; why not
|
||||
here? Because these symbols are new and dlopen hasn't
|
||||
returned yet. So we can't possibly be racing with a TLS
|
||||
access to them from another thread. */
|
||||
GL(dl_init_static_tls) (imap);
|
||||
assert (imap->l_need_tls_init == 0);
|
||||
}
|
||||
@@ -589,9 +594,9 @@ cannot load any more object with static TLS"));
|
||||
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
|
||||
_dl_open (const char *file, off_t offset, int mode,
|
||||
const void *caller_dlopen, Lmid_t nsid,
|
||||
int argc, char *argv[], char *env[])
|
||||
{
|
||||
if ((mode & RTLD_BINDING_MASK) == 0)
|
||||
@@ -635,6 +640,7 @@ no more namespaces available for dlmopen()"));
|
||||
|
||||
struct dl_open_args args;
|
||||
args.file = file;
|
||||
args.offset = offset;
|
||||
args.mode = mode;
|
||||
args.caller_dlopen = caller_dlopen;
|
||||
args.caller_dl_open = RETURN_ADDRESS (0);
|
||||
|
||||
+43
-5
@@ -16,8 +16,10 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <atomic.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
@@ -70,8 +72,6 @@ _dl_try_allocate_static_tls (struct link_map *map)
|
||||
|
||||
size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
|
||||
- map->l_tls_firstbyte_offset);
|
||||
|
||||
map->l_tls_offset = GL(dl_tls_static_used) = offset;
|
||||
#elif TLS_DTV_AT_TP
|
||||
/* dl_tls_static_used includes the TCB at the beginning. */
|
||||
size_t offset = (((GL(dl_tls_static_used)
|
||||
@@ -83,7 +83,36 @@ _dl_try_allocate_static_tls (struct link_map *map)
|
||||
if (used > GL(dl_tls_static_size))
|
||||
goto fail;
|
||||
|
||||
map->l_tls_offset = offset;
|
||||
#else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
/* We've computed the new value we want, now try to install it. */
|
||||
ptrdiff_t val;
|
||||
if ((val = map->l_tls_offset) == NO_TLS_OFFSET)
|
||||
{
|
||||
/* l_tls_offset starts out at NO_TLS_OFFSET, and all attempts to
|
||||
change it go from NO_TLS_OFFSET to some other value. We use
|
||||
compare_and_exchange to ensure only one attempt succeeds. We
|
||||
don't actually need any memory ordering here, but _acq is the
|
||||
weakest available. */
|
||||
(void ) atomic_compare_and_exchange_bool_acq (&map->l_tls_offset,
|
||||
offset,
|
||||
NO_TLS_OFFSET);
|
||||
val = map->l_tls_offset;
|
||||
assert (val != NO_TLS_OFFSET);
|
||||
}
|
||||
if (val != offset)
|
||||
{
|
||||
/* We'd like to set a static offset for this section, but another
|
||||
thread has already used a dynamic TLS block for it. Since we can
|
||||
only use static offsets if everyone does (and it's not practical
|
||||
to move that thread's dynamic block), we have to fail. */
|
||||
goto fail;
|
||||
}
|
||||
/* We installed the value; now update the globals. */
|
||||
#if TLS_TCB_AT_TP
|
||||
GL(dl_tls_static_used) = offset;
|
||||
#elif TLS_DTV_AT_TP
|
||||
map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
|
||||
GL(dl_tls_static_used) = used;
|
||||
#else
|
||||
@@ -114,8 +143,17 @@ void
|
||||
internal_function __attribute_noinline__
|
||||
_dl_allocate_static_tls (struct link_map *map)
|
||||
{
|
||||
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|
||||
|| _dl_try_allocate_static_tls (map))
|
||||
/* We wrap this in a signal mask because it has to iterate all threads
|
||||
(including this one) and update this map's TLS entry. A signal handler
|
||||
accessing TLS would try to do the same update and break. */
|
||||
sigset_t old;
|
||||
_dl_mask_all_signals (&old);
|
||||
int err = -1;
|
||||
if (map->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
|
||||
err = _dl_try_allocate_static_tls (map);
|
||||
|
||||
_dl_unmask_signals (&old);
|
||||
if (err != 0)
|
||||
{
|
||||
_dl_signal_error (0, map->l_name, NULL, N_("\
|
||||
cannot allocate memory in static TLS block"));
|
||||
|
||||
@@ -67,6 +67,9 @@ void *__libc_stack_end;
|
||||
/* Path where the binary is found. */
|
||||
const char *_dl_origin_path;
|
||||
|
||||
/* Directory where the AT_EXECFN is found. */
|
||||
const char *_google_exec_origin_dir;
|
||||
|
||||
/* Nonzero if runtime lookup should not update the .got/.plt. */
|
||||
int _dl_bind_not;
|
||||
|
||||
@@ -142,6 +145,12 @@ hp_timing_t _dl_cpuclock_offset;
|
||||
|
||||
void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
|
||||
|
||||
/* The merged position hash table used if we have a lot of shared objects. */
|
||||
dl_position_table_entry_t *_dl_position_hash_table;
|
||||
int _dl_position_hash_mask;
|
||||
int _dl_position_hash_cutoff = DL_POSITION_HASH_CUTOFF_DEFAULT;
|
||||
int _dl_position_hash_bits;
|
||||
|
||||
size_t _dl_pagesize = EXEC_PAGESIZE;
|
||||
|
||||
int _dl_inhibit_cache;
|
||||
@@ -222,6 +231,8 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock)
|
||||
that list. */
|
||||
__rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
|
||||
|
||||
/* Colon-separated list of absolute paths to ld.so.cache files we'll load. */
|
||||
const char *_google_ld_so_cache_list = GOOGLE_LD_SO_CACHE_LIST;
|
||||
|
||||
#ifdef HAVE_AUX_VECTOR
|
||||
int _dl_clktck;
|
||||
@@ -234,6 +245,9 @@ _dl_aux_init (ElfW(auxv_t) *av)
|
||||
uid_t uid = 0;
|
||||
gid_t gid = 0;
|
||||
|
||||
extern ElfW(auxv_t) *__google_auxv;
|
||||
__google_auxv = av;
|
||||
|
||||
_dl_auxv = av;
|
||||
for (; av->a_type != AT_NULL; ++av)
|
||||
switch (av->a_type)
|
||||
|
||||
+105
-52
@@ -17,6 +17,7 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <atomic.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <signal.h>
|
||||
@@ -293,7 +294,7 @@ allocate_dtv (void *result)
|
||||
initial set of modules. This should avoid in most cases expansions
|
||||
of the dtv. */
|
||||
dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
|
||||
dtv = calloc (dtv_length + 2, sizeof (dtv_t));
|
||||
dtv = __signal_safe_calloc (dtv_length + 2, sizeof (dtv_t));
|
||||
if (dtv != NULL)
|
||||
{
|
||||
/* This is the initial length of the dtv. */
|
||||
@@ -463,6 +464,18 @@ _dl_allocate_tls (void *mem)
|
||||
}
|
||||
rtld_hidden_def (_dl_allocate_tls)
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_clear_dtv (dtv_t *dtv)
|
||||
{
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
if (! dtv[1 + cnt].pointer.is_static
|
||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
__signal_safe_free (dtv[1 + cnt].pointer.val);
|
||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||
}
|
||||
|
||||
rtld_hidden_def (_dl_clear_dtv)
|
||||
|
||||
#ifndef SHARED
|
||||
extern dtv_t _dl_static_dtv[];
|
||||
@@ -479,11 +492,11 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
if (! dtv[1 + cnt].pointer.is_static
|
||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
free (dtv[1 + cnt].pointer.val);
|
||||
__signal_safe_free (dtv[1 + cnt].pointer.val);
|
||||
|
||||
/* The array starts with dtv[-1]. */
|
||||
if (dtv != GL(dl_initial_dtv))
|
||||
free (dtv - 1);
|
||||
__signal_safe_free (dtv - 1);
|
||||
|
||||
if (dealloc_tcb)
|
||||
{
|
||||
@@ -521,20 +534,21 @@ rtld_hidden_def (_dl_deallocate_tls)
|
||||
# endif
|
||||
|
||||
|
||||
static void *
|
||||
allocate_and_init (struct link_map *map)
|
||||
static void
|
||||
allocate_and_init (dtv_t *dtv, struct link_map *map)
|
||||
{
|
||||
void *newp;
|
||||
|
||||
newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
|
||||
newp = __signal_safe_memalign (map->l_tls_align, map->l_tls_blocksize);
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
|
||||
/* Initialize the memory. */
|
||||
/* Initialize the memory. Since this is our thread's space, we are
|
||||
under a signal mask, and no one has touched this section before,
|
||||
we can safely just overwrite whatever's there. */
|
||||
memset (__mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
|
||||
return newp;
|
||||
dtv->pointer.val = newp;
|
||||
}
|
||||
|
||||
|
||||
@@ -576,7 +590,15 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
the entry we need. */
|
||||
size_t new_gen = listp->slotinfo[idx].gen;
|
||||
size_t total = 0;
|
||||
sigset_t old;
|
||||
|
||||
_dl_mask_all_signals (&old);
|
||||
/* We use the signal mask as a lock against reentrancy here.
|
||||
Check that a signal taken before the lock didn't already
|
||||
update us. */
|
||||
dtv = THREAD_DTV ();
|
||||
if (dtv[0].counter >= listp->slotinfo[idx].gen)
|
||||
goto out;
|
||||
/* We have to look through the entire dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
do
|
||||
@@ -596,25 +618,27 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
if (gen <= dtv[0].counter)
|
||||
continue;
|
||||
|
||||
size_t modid = total + cnt;
|
||||
|
||||
/* If there is no map this means the entry is empty. */
|
||||
struct link_map *map = listp->slotinfo[cnt].map;
|
||||
if (map == NULL)
|
||||
{
|
||||
/* If this modid was used at some point the memory
|
||||
might still be allocated. */
|
||||
if (! dtv[total + cnt].pointer.is_static
|
||||
&& dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
if (dtv[-1].counter >= modid
|
||||
&& !dtv[modid].pointer.is_static
|
||||
&& dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
free (dtv[total + cnt].pointer.val);
|
||||
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
__signal_safe_free (dtv[modid].pointer.val);
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
assert (modid == map->l_tls_modid);
|
||||
/* Check whether the current dtv array is large enough. */
|
||||
size_t modid = map->l_tls_modid;
|
||||
assert (total + cnt == modid);
|
||||
if (dtv[-1].counter < modid)
|
||||
{
|
||||
/* Reallocate the dtv. */
|
||||
@@ -628,17 +652,18 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
{
|
||||
/* This is the initial dtv that was allocated
|
||||
during rtld startup using the dl-minimal.c
|
||||
malloc instead of the real malloc. We can't
|
||||
malloc instead of the real allocator. We can't
|
||||
free it, we have to abandon the old storage. */
|
||||
|
||||
newp = malloc ((2 + newsize) * sizeof (dtv_t));
|
||||
newp = __signal_safe_malloc (
|
||||
(2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
newp = realloc (&dtv[-1],
|
||||
newp = __signal_safe_realloc (&dtv[-1],
|
||||
(2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
@@ -668,12 +693,17 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
deallocate even if it is this dtv entry we are
|
||||
supposed to load. The reason is that we call
|
||||
memalign and not malloc. */
|
||||
free (dtv[modid].pointer.val);
|
||||
__signal_safe_free (dtv[modid].pointer.val);
|
||||
|
||||
/* This module is loaded dynamically- We defer memory
|
||||
allocation. */
|
||||
dtv[modid].pointer.is_static = false;
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
/* Google-local fix for issues solved differently upstream. */
|
||||
if (map->l_tls_offset == NO_TLS_OFFSET
|
||||
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||
{
|
||||
/* This module is loaded dynamically- We defer memory
|
||||
allocation. */
|
||||
dtv[modid].pointer.is_static = false;
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
}
|
||||
|
||||
if (modid == req_modid)
|
||||
the_map = map;
|
||||
@@ -685,6 +715,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
|
||||
/* This will be the new maximum generation counter. */
|
||||
dtv[0].counter = new_gen;
|
||||
out:
|
||||
_dl_unmask_signals (&old);
|
||||
}
|
||||
|
||||
return the_map;
|
||||
@@ -710,39 +742,60 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
|
||||
the_map = listp->slotinfo[idx].map;
|
||||
}
|
||||
sigset_t old;
|
||||
_dl_mask_all_signals (&old);
|
||||
|
||||
again:
|
||||
/* Make sure that, if a dlopen running in parallel forces the
|
||||
variable into static storage, we'll wait until the address in the
|
||||
static TLS block is set up, and use that. If we're undecided
|
||||
yet, make sure we make the decision holding the lock as well. */
|
||||
if (__builtin_expect (the_map->l_tls_offset
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET, 0))
|
||||
/* As with update_slotinfo, we use the sigmask as a check against
|
||||
reentrancy. */
|
||||
if (dtv[GET_ADDR_MODULE].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
goto out;
|
||||
|
||||
/* Synchronize against a parallel dlopen() forcing this variable
|
||||
into static storage. If that happens, we have to be more careful
|
||||
about initializing the area, as that dlopen() will be iterating
|
||||
the threads to do so itself. */
|
||||
ptrdiff_t offset;
|
||||
if ((offset = the_map->l_tls_offset) == NO_TLS_OFFSET)
|
||||
{
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
if (__builtin_expect (the_map->l_tls_offset == NO_TLS_OFFSET, 1))
|
||||
{
|
||||
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
else
|
||||
{
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
if (__builtin_expect (the_map->l_tls_offset
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET, 1))
|
||||
{
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
|
||||
goto again;
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
}
|
||||
/* l_tls_offset starts out at NO_TLS_OFFSET, and all attempts to
|
||||
change it go from NO_TLS_OFFSET to some other value. We use
|
||||
compare_and_exchange to ensure only one attempt succeeds. We
|
||||
don't actually need any memory ordering here, but _acq is the
|
||||
weakest available. */
|
||||
(void) atomic_compare_and_exchange_bool_acq (&the_map->l_tls_offset,
|
||||
FORCED_DYNAMIC_TLS_OFFSET,
|
||||
NO_TLS_OFFSET);
|
||||
offset = the_map->l_tls_offset;
|
||||
assert (offset != NO_TLS_OFFSET);
|
||||
}
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
||||
dtv[GET_ADDR_MODULE].pointer.is_static = false;
|
||||
if (offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||
{
|
||||
allocate_and_init (&dtv[GET_ADDR_MODULE], the_map);
|
||||
}
|
||||
else
|
||||
{
|
||||
void ** volatile pp = &dtv[GET_ADDR_MODULE].pointer.val;
|
||||
while (atomic_forced_read (*pp) == TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
/* for lack of a better (safe) thing to do, just spin.
|
||||
Someone else (not us; it's done under a signal mask) set
|
||||
this map to a static TLS offset, and they'll iterate all
|
||||
threads to initialize it. They'll eventually write
|
||||
to pointer.val, at which point we know they've fully
|
||||
completed initialization. */
|
||||
atomic_delay ();
|
||||
}
|
||||
/* Make sure we've picked up their initialization of the actual
|
||||
block; this pairs against the write barrier in
|
||||
init_one_static_tls, guaranteeing that we see their write of
|
||||
the tls_initimage into the static region. */
|
||||
atomic_read_barrier ();
|
||||
}
|
||||
out:
|
||||
assert (dtv[GET_ADDR_MODULE].pointer.val != TLS_DTV_UNALLOCATED);
|
||||
_dl_unmask_signals (&old);
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
return (char *) dtv[GET_ADDR_MODULE].pointer.val + GET_ADDR_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+17
-4
@@ -53,10 +53,23 @@ find_needed (const char *name, struct link_map *map)
|
||||
struct link_map *tmap;
|
||||
unsigned int n;
|
||||
|
||||
for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
|
||||
tmap = tmap->l_next)
|
||||
if (_dl_name_match_p (name, tmap))
|
||||
return tmap;
|
||||
if (name[0] == '\0')
|
||||
{
|
||||
/* Special case: both main exe and vdso can have empty name;
|
||||
so search from head: it is important to return the map for main
|
||||
a.out; else dlsym(0, ...) will fail unexpectedly. */
|
||||
for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
|
||||
tmap = tmap->l_next)
|
||||
if (_dl_name_match_p (name, tmap))
|
||||
return tmap;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (tmap = _dl_last_entry (&GL(dl_ns)[map->l_ns]); tmap != NULL;
|
||||
tmap = tmap->l_prev)
|
||||
if (_dl_name_match_p (name, tmap))
|
||||
return tmap;
|
||||
}
|
||||
|
||||
/* The required object is not in the global scope, look to see if it is
|
||||
a dependency of the current object. */
|
||||
|
||||
@@ -2283,6 +2283,9 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||
#define DT_PPC64_OPD (DT_LOPROC + 1)
|
||||
#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
|
||||
#define DT_PPC64_OPT (DT_LOPROC + 3)
|
||||
/* This should have the value 4, to match with the four tag values
|
||||
above, but the change needs to be coordinated with an update to
|
||||
L_INFO_ELEMENTS in libunwind/google_link.h. */
|
||||
#define DT_PPC64_NUM 3
|
||||
|
||||
/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */
|
||||
|
||||
+10
-21
@@ -150,31 +150,23 @@ for file do
|
||||
echo "ldd: ${file}:" $"not regular file" >&2
|
||||
result=1
|
||||
elif test -r "$file"; then
|
||||
test -x "$file" || echo 'ldd:' $"\
|
||||
warning: you do not have execution permission for" "\`$file'" >&2
|
||||
RTLD=
|
||||
ret=1
|
||||
for rtld in ${RTLDLIST}; do
|
||||
if test -x $rtld; then
|
||||
verify_out=`${rtld} --verify "$file"`
|
||||
ret=$?
|
||||
case $ret in
|
||||
[02]) RTLD=${rtld}; break;;
|
||||
esac
|
||||
dummy=`$rtld 2>&1`
|
||||
if test $? = 127; then
|
||||
verify_out=`${rtld} --verify "$file"`
|
||||
ret=$?
|
||||
case $ret in
|
||||
[02]) RTLD=${rtld}; break;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
done
|
||||
case $ret in
|
||||
0)
|
||||
# If the program exits with exit code 5, it means the process has been
|
||||
# invoked with __libc_enable_secure. Fall back to running it through
|
||||
# the dynamic linker.
|
||||
try_trace "$file"
|
||||
rc=$?
|
||||
if [ $rc = 5 ]; then
|
||||
try_trace "$RTLD" "$file"
|
||||
rc=$?
|
||||
fi
|
||||
[ $rc = 0 ] || result=1
|
||||
0|2)
|
||||
try_trace "$RTLD" "$file" || result=1
|
||||
;;
|
||||
1)
|
||||
# This can be a non-ELF binary or no binary at all.
|
||||
@@ -183,9 +175,6 @@ warning: you do not have execution permission for" "\`$file'" >&2
|
||||
result=1
|
||||
}
|
||||
;;
|
||||
2)
|
||||
try_trace "$RTLD" "$file" || result=1
|
||||
;;
|
||||
*)
|
||||
echo 'ldd:' ${RTLD} $"exited with unknown exit code" "($ret)" >&2
|
||||
exit 1
|
||||
|
||||
+4
-4
@@ -34,6 +34,8 @@
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||
details of shared object loading to the debugger. If the executable's
|
||||
dynamic section has a DT_DEBUG element, the run-time linker sets that
|
||||
@@ -162,8 +164,6 @@ struct dl_phdr_info
|
||||
void *dlpi_tls_data;
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
|
||||
size_t, void *),
|
||||
void *__data);
|
||||
@@ -187,8 +187,8 @@ extern uintptr_t la_symbind64 (Elf64_Sym *__sym, unsigned int __ndx,
|
||||
unsigned int *__flags, const char *__symname);
|
||||
extern unsigned int la_objclose (uintptr_t *__cookie);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* link.h */
|
||||
|
||||
+151
-16
@@ -51,6 +51,12 @@ extern __typeof (__mempcpy) __mempcpy attribute_hidden;
|
||||
extern __typeof (_exit) exit_internal asm ("_exit") attribute_hidden;
|
||||
#define _exit exit_internal
|
||||
|
||||
/* Iterate over auxv, find AT_EXECFN if any. */
|
||||
static char * get_at_execfn(ElfW(auxv_t) *auxv);
|
||||
|
||||
/* Given file path, return fully resolved directory path. */
|
||||
static char * get_directory (const char *file_path);
|
||||
|
||||
/* Helper function to handle errors while resolving symbols. */
|
||||
static void print_unresolved (int errcode, const char *objname,
|
||||
const char *errsting);
|
||||
@@ -73,6 +79,9 @@ enum mode { normal, list, verify, trace };
|
||||
all the entries. */
|
||||
static void process_envvars (enum mode *modep);
|
||||
|
||||
/* Set GLRO(google_exec_origin_dir). */
|
||||
static void set_exec_origin_dir(const char *exe_path);
|
||||
|
||||
#ifdef DL_ARGV_NOT_RELRO
|
||||
int _dl_argc attribute_hidden;
|
||||
char **_dl_argv = NULL;
|
||||
@@ -162,7 +171,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
|
||||
._dl_hwcap_mask = HWCAP_IMPORTANT,
|
||||
._dl_lazy = 1,
|
||||
._dl_fpu_control = _FPU_DEFAULT,
|
||||
._dl_pointer_guard = 1,
|
||||
._dl_pagesize = EXEC_PAGESIZE,
|
||||
._dl_inhibit_cache = 0,
|
||||
|
||||
@@ -176,6 +184,8 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
|
||||
._dl_open = _dl_open,
|
||||
._dl_close = _dl_close,
|
||||
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
|
||||
._dl_position_hash_cutoff = DL_POSITION_HASH_CUTOFF_DEFAULT,
|
||||
._dl_position_hash_bits = 0,
|
||||
#ifdef HAVE_DL_DISCOVER_OSVERSION
|
||||
._dl_discover_osversion = _dl_discover_osversion
|
||||
#endif
|
||||
@@ -623,15 +633,15 @@ static void
|
||||
map_doit (void *a)
|
||||
{
|
||||
struct map_args *args = (struct map_args *) a;
|
||||
args->map = _dl_map_object (args->loader, args->str, lt_library, 0,
|
||||
args->mode, LM_ID_BASE);
|
||||
args->map = _dl_map_object (args->loader, args->str, 0, lt_library,
|
||||
0, args->mode, LM_ID_BASE);
|
||||
}
|
||||
|
||||
static void
|
||||
dlmopen_doit (void *a)
|
||||
{
|
||||
struct dlmopen_args *args = (struct dlmopen_args *) a;
|
||||
args->map = _dl_open (args->fname,
|
||||
args->map = _dl_open (args->fname, 0,
|
||||
(RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT
|
||||
| __RTLD_SECURE),
|
||||
dl_main, LM_ID_NEWLM, _dl_argc, INTUSE(_dl_argv),
|
||||
@@ -857,15 +867,12 @@ security_init (void)
|
||||
#endif
|
||||
|
||||
/* Set up the pointer guard as well, if necessary. */
|
||||
if (GLRO(dl_pointer_guard))
|
||||
{
|
||||
uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
|
||||
stack_chk_guard);
|
||||
uintptr_t pointer_chk_guard
|
||||
= _dl_setup_pointer_guard (_dl_random, stack_chk_guard);
|
||||
#ifdef THREAD_SET_POINTER_GUARD
|
||||
THREAD_SET_POINTER_GUARD (pointer_chk_guard);
|
||||
THREAD_SET_POINTER_GUARD (pointer_chk_guard);
|
||||
#endif
|
||||
__pointer_chk_guard_local = pointer_chk_guard;
|
||||
}
|
||||
__pointer_chk_guard_local = pointer_chk_guard;
|
||||
|
||||
/* We do not need the _dl_random value anymore. The less
|
||||
information we leave behind, the better, so clear the
|
||||
@@ -1032,6 +1039,8 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
in LIST\n\
|
||||
--audit LIST use objects named in LIST as auditors\n");
|
||||
|
||||
set_exec_origin_dir (INTUSE(_dl_argv)[1]);
|
||||
|
||||
++_dl_skip_args;
|
||||
--_dl_argc;
|
||||
++INTUSE(_dl_argv);
|
||||
@@ -1075,7 +1084,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
else
|
||||
{
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_map_object (NULL, rtld_progname, lt_library, 0,
|
||||
_dl_map_object (NULL, rtld_progname, 0, lt_library, 0,
|
||||
__RTLD_OPENEXEC, LM_ID_BASE);
|
||||
HP_TIMING_NOW (stop);
|
||||
|
||||
@@ -1126,6 +1135,8 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
}
|
||||
else
|
||||
{
|
||||
set_exec_origin_dir (get_at_execfn (auxv));
|
||||
|
||||
/* Create a link_map for the executable itself.
|
||||
This will be what dlopen on "" returns. */
|
||||
main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
|
||||
@@ -1636,6 +1647,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_ETC_LD_SO_PRELOAD /* Google-local: we don't want
|
||||
/etc/ld.so.preload for GRTE. */
|
||||
|
||||
/* There usually is no ld.so.preload file, it should only be used
|
||||
for emergencies and testing. So the open call etc should usually
|
||||
fail. Using access() on a non-existing file is faster than using
|
||||
@@ -1720,6 +1735,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* end "/etc/ld.so.preload" disable. */
|
||||
|
||||
if (__builtin_expect (*first_preload != NULL, 0))
|
||||
{
|
||||
/* Set up PRELOADS with a vector of the preloaded libraries. */
|
||||
@@ -1739,6 +1756,11 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
dependencies in the executable's searchlist for symbol resolution. */
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
|
||||
|
||||
/* We have now finished loading every required (linked-in) object.
|
||||
Set up the position hash if needed. */
|
||||
_dl_fill_position_hash (main_map);
|
||||
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
@@ -2367,10 +2389,12 @@ process_dl_debug (const char *dl_debug)
|
||||
DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
|
||||
{ LEN_AND_STR ("scopes"), "display scope information",
|
||||
DL_DEBUG_SCOPES },
|
||||
{ LEN_AND_STR ("fastload"), "display fastload information",
|
||||
DL_DEBUG_FASTLOAD },
|
||||
{ LEN_AND_STR ("all"), "all previous options combined",
|
||||
DL_DEBUG_LIBS | DL_DEBUG_RELOC | DL_DEBUG_FILES | DL_DEBUG_SYMBOLS
|
||||
| DL_DEBUG_BINDINGS | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS
|
||||
| DL_DEBUG_SCOPES },
|
||||
| DL_DEBUG_SCOPES | DL_DEBUG_FASTLOAD },
|
||||
{ LEN_AND_STR ("statistics"), "display relocation statistics",
|
||||
DL_DEBUG_STATISTICS },
|
||||
{ LEN_AND_STR ("unused"), "determined unused DSOs",
|
||||
@@ -2488,6 +2512,8 @@ process_envvars (enum mode *modep)
|
||||
GLRO(dl_profile_output)
|
||||
= &"/var/tmp\0/var/profile"[INTUSE(__libc_enable_secure) ? 9 : 0];
|
||||
|
||||
GLRO(google_ld_so_cache_list) = GOOGLE_LD_SO_CACHE_LIST;
|
||||
|
||||
while ((envline = _dl_next_ld_env_entry (&runp)) != NULL)
|
||||
{
|
||||
size_t len = 0;
|
||||
@@ -2605,9 +2631,6 @@ process_envvars (enum mode *modep)
|
||||
GLRO(dl_use_load_bias) = envline[14] == '1' ? -1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp (envline, "POINTER_GUARD", 13) == 0)
|
||||
GLRO(dl_pointer_guard) = envline[14] != '0';
|
||||
break;
|
||||
|
||||
case 14:
|
||||
@@ -2635,6 +2658,13 @@ process_envvars (enum mode *modep)
|
||||
mode = trace;
|
||||
break;
|
||||
|
||||
/* Google local change. */
|
||||
case 23:
|
||||
if (!INTUSE(__libc_enable_secure)
|
||||
&& memcmp (envline, "GOOGLE_LD_SO_CACHE_LIST", 23) == 0)
|
||||
GLRO(google_ld_so_cache_list) = &envline[24];
|
||||
break;
|
||||
|
||||
/* We might have some extra environment variable to handle. This
|
||||
is tricky due to the pre-processing of the length of the name
|
||||
in the switch statement here. The code here assumes that added
|
||||
@@ -2643,6 +2673,27 @@ process_envvars (enum mode *modep)
|
||||
EXTRA_LD_ENVVARS
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Handle all fastload-related env vars here. This may duplicate
|
||||
effort with the switch table above, but it localizes changes
|
||||
made by the fastload patch. On Linux, the '15' case is used
|
||||
by another environment variable (LIBRARY_VERSION) and much
|
||||
change would be needed to add support adding a variable of
|
||||
that length with the existing style. */
|
||||
switch (len)
|
||||
{
|
||||
case 15:
|
||||
if (memcmp (envline, "FASTLOAD_CUTOFF", 15) == 0)
|
||||
GLRO(dl_position_hash_cutoff)
|
||||
= __strtoul_internal (&envline[16], NULL, 0, 0);;
|
||||
break;
|
||||
|
||||
case 18:
|
||||
if (memcmp (envline, "FASTLOAD_HASH_BITS", 18) == 0)
|
||||
GLRO(dl_position_hash_bits)
|
||||
= __strtoul_internal (&envline[19], NULL, 0, 0);;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The caller wants this information. */
|
||||
@@ -2659,6 +2710,19 @@ process_envvars (enum mode *modep)
|
||||
UNSECURE_ENVVARS;
|
||||
const char *nextp;
|
||||
|
||||
/* We may destory the connection between __environ and the auxv[]
|
||||
by unsetting one or more of the insecure variables in the
|
||||
original environment. Here is our last chance to record correct
|
||||
__google_auxv. See b/13901604. */
|
||||
extern ElfW(auxv_t) *__google_auxv;
|
||||
if (__builtin_expect (__google_auxv == NULL, 1))
|
||||
{
|
||||
char **e;
|
||||
|
||||
for (e = __environ; *e; ++e) /* Skip. */;
|
||||
__google_auxv = (ElfW(auxv_t) *) ++e;
|
||||
}
|
||||
|
||||
nextp = unsecure_envvars;
|
||||
do
|
||||
{
|
||||
@@ -2807,3 +2871,74 @@ print_statistics (hp_timing_t *rtld_total_timep)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Given file path, return an absolute directory path.
|
||||
Examples: in: "/foo/bar/a.out", out: "/foo/bar/";
|
||||
in: "./a.out", out: "/dot/resolved/to/full/path/./". */
|
||||
static char *
|
||||
get_directory (const char *file_path)
|
||||
{
|
||||
assert (file_path != NULL);
|
||||
|
||||
/* Find the end of the directory substring in file_path. */
|
||||
size_t path_len = strlen (file_path);
|
||||
while (path_len > 0 && file_path[path_len - 1] != '/')
|
||||
--path_len;
|
||||
|
||||
/* Allocate space and set the path prefix according to whether or not
|
||||
this is an absolute path. */
|
||||
char *dest;
|
||||
char *full_dir_path;
|
||||
if (file_path[0] == '/')
|
||||
{
|
||||
full_dir_path = malloc (path_len + 1);
|
||||
assert (full_dir_path != NULL);
|
||||
dest = full_dir_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For a relative path, we need to include space for the largest
|
||||
possible current path, a joining '/', the relevant part of
|
||||
file_path, and a trailing '\0'. */
|
||||
full_dir_path = malloc (PATH_MAX + path_len + 2);
|
||||
assert (full_dir_path != NULL);
|
||||
|
||||
char *status = __getcwd (full_dir_path, PATH_MAX);
|
||||
assert (status != NULL);
|
||||
|
||||
dest = __rawmemchr (full_dir_path, '\0');
|
||||
if (dest[-1] != '/')
|
||||
*dest++ = '/';
|
||||
}
|
||||
|
||||
if (path_len > 0)
|
||||
dest = __mempcpy (dest, file_path, path_len);
|
||||
*dest = '\0';
|
||||
|
||||
return full_dir_path;
|
||||
}
|
||||
|
||||
/* Set GLRO(google_exec_origin_dir). */
|
||||
static void
|
||||
set_exec_origin_dir (const char *exe_path)
|
||||
{
|
||||
assert (GLRO(google_exec_origin_dir) == NULL);
|
||||
|
||||
if (GLRO(dl_origin_path) != NULL)
|
||||
GLRO(google_exec_origin_dir) = strdup (GLRO(dl_origin_path));
|
||||
else if (exe_path != NULL)
|
||||
GLRO(google_exec_origin_dir) = get_directory (exe_path);
|
||||
}
|
||||
|
||||
/* Iterate over auxv, find AT_EXECFN if any. */
|
||||
static char *
|
||||
get_at_execfn (ElfW(auxv_t) *auxv)
|
||||
{
|
||||
assert (auxv != NULL);
|
||||
|
||||
for (; auxv->a_type != AT_NULL; ++auxv)
|
||||
if (auxv->a_type == AT_EXECFN)
|
||||
return (char *) auxv->a_un.a_val;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2003-2013 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/>.
|
||||
|
||||
# Makefile for google-nsl-stub add-on subdirectory of GNU C Library.
|
||||
# Based on libidn/Makefile.
|
||||
|
||||
subdir := google-nsl-stub
|
||||
|
||||
extra-libs = libnsl
|
||||
extra-libs-others = $(extra-libs)
|
||||
|
||||
libnsl-routines := ypclnt
|
||||
|
||||
include $(..)Makeconfig
|
||||
|
||||
libnsl-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
include $(..)Rules
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
# This is a shell script fragment sourced by the main configure script.
|
||||
# We're obliged to give here the canonical name that will be used to
|
||||
# as a subdirectory to search for in other add-ons' sysdeps trees.
|
||||
|
||||
libc_add_on_canonical=google-nsl-stub
|
||||
libc_add_on_subdirs=.
|
||||
@@ -0,0 +1 @@
|
||||
.*-.*-.* libnsl=1
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright (C) 2013 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 is a Google-local stub version of nis/ypclnt.c. These functions
|
||||
are required for dynamic linking of some precompiled executables. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int yp_get_default_domain(char **domp) {
|
||||
/* We duplicate glibc's error behavior and return a null pointer. */
|
||||
*domp = NULL;
|
||||
return 12; /* YPERR_NODOM */
|
||||
}
|
||||
|
||||
static const char err[] = "not implemented in Google-local stub";
|
||||
char *yperr_string(int incode) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
|
||||
char **outval, int *outvallen) {
|
||||
*outval = malloc(2);
|
||||
(*outval)[0] = '\n';
|
||||
(*outval)[1] = '\0';
|
||||
*outvallen = 0;
|
||||
return 0;
|
||||
}
|
||||
+2
-1
@@ -20,7 +20,8 @@
|
||||
#
|
||||
subdir := hesiod
|
||||
|
||||
extra-libs := libnss_hesiod
|
||||
# Google-local: Disable hesiod.
|
||||
# extra-libs := libnss_hesiod
|
||||
extra-libs-others = $(extra-libs)
|
||||
|
||||
subdir-dirs = nss_hesiod
|
||||
|
||||
+4
-173
@@ -238,181 +238,12 @@ __gconv_transliterate (struct __gconv_step *step,
|
||||
return __GCONV_ILLEGAL_INPUT;
|
||||
}
|
||||
|
||||
|
||||
/* Structure to represent results of found (or not) transliteration
|
||||
modules. */
|
||||
struct known_trans
|
||||
{
|
||||
/* This structure must remain the first member. */
|
||||
struct trans_struct info;
|
||||
|
||||
char *fname;
|
||||
void *handle;
|
||||
int open_count;
|
||||
};
|
||||
|
||||
|
||||
/* Tree with results of previous calls to __gconv_translit_find. */
|
||||
static void *search_tree;
|
||||
|
||||
/* We modify global data. */
|
||||
__libc_lock_define_initialized (static, lock);
|
||||
|
||||
|
||||
/* Compare two transliteration entries. */
|
||||
static int
|
||||
trans_compare (const void *p1, const void *p2)
|
||||
{
|
||||
const struct known_trans *s1 = (const struct known_trans *) p1;
|
||||
const struct known_trans *s2 = (const struct known_trans *) p2;
|
||||
|
||||
return strcmp (s1->info.name, s2->info.name);
|
||||
}
|
||||
|
||||
|
||||
/* Open (maybe reopen) the module named in the struct. Get the function
|
||||
and data structure pointers we need. */
|
||||
static int
|
||||
open_translit (struct known_trans *trans)
|
||||
{
|
||||
__gconv_trans_query_fct queryfct;
|
||||
|
||||
trans->handle = __libc_dlopen (trans->fname);
|
||||
if (trans->handle == NULL)
|
||||
/* Not available. */
|
||||
return 1;
|
||||
|
||||
/* Find the required symbol. */
|
||||
queryfct = __libc_dlsym (trans->handle, "gconv_trans_context");
|
||||
if (queryfct == NULL)
|
||||
{
|
||||
/* We cannot live with that. */
|
||||
close_and_out:
|
||||
__libc_dlclose (trans->handle);
|
||||
trans->handle = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get the context. */
|
||||
if (queryfct (trans->info.name, &trans->info.csnames, &trans->info.ncsnames)
|
||||
!= 0)
|
||||
goto close_and_out;
|
||||
|
||||
/* Of course we also have to have the actual function. */
|
||||
trans->info.trans_fct = __libc_dlsym (trans->handle, "gconv_trans");
|
||||
if (trans->info.trans_fct == NULL)
|
||||
goto close_and_out;
|
||||
|
||||
/* Now the optional functions. */
|
||||
trans->info.trans_init_fct =
|
||||
__libc_dlsym (trans->handle, "gconv_trans_init");
|
||||
trans->info.trans_context_fct =
|
||||
__libc_dlsym (trans->handle, "gconv_trans_context");
|
||||
trans->info.trans_end_fct =
|
||||
__libc_dlsym (trans->handle, "gconv_trans_end");
|
||||
|
||||
trans->open_count = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
internal_function
|
||||
__gconv_translit_find (struct trans_struct *trans)
|
||||
{
|
||||
struct known_trans **found;
|
||||
const struct path_elem *runp;
|
||||
int res = 1;
|
||||
|
||||
/* We have to have a name. */
|
||||
assert (trans->name != NULL);
|
||||
|
||||
/* Acquire the lock. */
|
||||
__libc_lock_lock (lock);
|
||||
|
||||
/* See whether we know this module already. */
|
||||
found = __tfind (trans, &search_tree, trans_compare);
|
||||
if (found != NULL)
|
||||
{
|
||||
/* Is this module available? */
|
||||
if ((*found)->handle != NULL)
|
||||
{
|
||||
/* Maybe we have to reopen the file. */
|
||||
if ((*found)->handle != (void *) -1)
|
||||
/* The object is not unloaded. */
|
||||
res = 0;
|
||||
else if (open_translit (*found) == 0)
|
||||
{
|
||||
/* Copy the data. */
|
||||
*trans = (*found)->info;
|
||||
(*found)->open_count++;
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t name_len = strlen (trans->name) + 1;
|
||||
int need_so = 0;
|
||||
struct known_trans *newp;
|
||||
|
||||
/* We have to continue looking for the module. */
|
||||
if (__gconv_path_elem == NULL)
|
||||
__gconv_get_path ();
|
||||
|
||||
/* See whether we have to append .so. */
|
||||
if (name_len <= 4 || memcmp (&trans->name[name_len - 4], ".so", 3) != 0)
|
||||
need_so = 1;
|
||||
|
||||
/* Create a new entry. */
|
||||
newp = (struct known_trans *) malloc (sizeof (struct known_trans)
|
||||
+ (__gconv_max_path_elem_len
|
||||
+ name_len + 3)
|
||||
+ name_len);
|
||||
if (newp != NULL)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
/* Clear the struct. */
|
||||
memset (newp, '\0', sizeof (struct known_trans));
|
||||
|
||||
/* Store a copy of the module name. */
|
||||
newp->info.name = cp = (char *) (newp + 1);
|
||||
cp = __mempcpy (cp, trans->name, name_len);
|
||||
|
||||
newp->fname = cp;
|
||||
|
||||
/* Search in all the directories. */
|
||||
for (runp = __gconv_path_elem; runp->name != NULL; ++runp)
|
||||
{
|
||||
cp = __mempcpy (__stpcpy ((char *) newp->fname, runp->name),
|
||||
trans->name, name_len);
|
||||
if (need_so)
|
||||
memcpy (cp, ".so", sizeof (".so"));
|
||||
|
||||
if (open_translit (newp) == 0)
|
||||
{
|
||||
/* We found a module. */
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
newp->fname = NULL;
|
||||
|
||||
/* In any case we'll add the entry to our search tree. */
|
||||
if (__tsearch (newp, &search_tree, trans_compare) == NULL)
|
||||
{
|
||||
/* Yickes, this should not happen. Unload the object. */
|
||||
res = 1;
|
||||
/* XXX unload here. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__libc_lock_unlock (lock);
|
||||
|
||||
return res;
|
||||
/* Transliteration module loading has been removed because it never
|
||||
worked as intended and suffered from a security vulnerability.
|
||||
Consequently, this function always fails. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ extern int __libc_use_alloca (size_t size) __attribute__ ((const));
|
||||
extern int __libc_alloca_cutoff (size_t size) __attribute__ ((const));
|
||||
libc_hidden_proto (__libc_alloca_cutoff)
|
||||
|
||||
#define __MAX_ALLOCA_CUTOFF 65536
|
||||
#define __MAX_ALLOCA_CUTOFF 8192
|
||||
|
||||
#include <allocalim.h>
|
||||
|
||||
|
||||
+17
-1
@@ -1,5 +1,6 @@
|
||||
#ifndef _DLFCN_H
|
||||
#include <dlfcn/dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef _ISOMAC
|
||||
#include <link.h> /* For ElfW. */
|
||||
#include <stdbool.h>
|
||||
@@ -13,6 +14,10 @@
|
||||
#define __RTLD_SECURE 0x04000000 /* Apply additional security checks. */
|
||||
#define __RTLD_NOIFUNC 0x02000000 /* Suppress calling ifunc functions. */
|
||||
|
||||
/* Google-local; use only $prefix/etc/ld.so.cache.
|
||||
See b/3133396 */
|
||||
#define __RTLD_GOOGLE_IGNORE_HOST_LD_SO_CACHE 0x01000000
|
||||
|
||||
#define __LM_ID_CALLER -2
|
||||
|
||||
#ifdef SHARED
|
||||
@@ -32,7 +37,8 @@ extern char **__libc_argv attribute_hidden;
|
||||
/* Now define the internal interfaces. */
|
||||
|
||||
#define __libc_dlopen(name) \
|
||||
__libc_dlopen_mode (name, RTLD_LAZY | __RTLD_DLOPEN)
|
||||
__libc_dlopen_mode (name, RTLD_LAZY | __RTLD_DLOPEN | \
|
||||
__RTLD_GOOGLE_IGNORE_HOST_LD_SO_CACHE)
|
||||
extern void *__libc_dlopen_mode (const char *__name, int __mode);
|
||||
extern void *__libc_dlsym (void *__map, const char *__name);
|
||||
extern int __libc_dlclose (void *__map);
|
||||
@@ -101,6 +107,8 @@ extern int _dlerror_run (void (*operate) (void *), void *args)
|
||||
struct dlfcn_hook
|
||||
{
|
||||
void *(*dlopen) (const char *file, int mode, void *dl_caller);
|
||||
void *(*dlopen_with_offset) (const char *file, off_t offset,
|
||||
int mode, void *dl_caller);
|
||||
int (*dlclose) (void *handle);
|
||||
void *(*dlsym) (void *handle, const char *name, void *dl_caller);
|
||||
void *(*dlvsym) (void *handle, const char *name, const char *version,
|
||||
@@ -111,6 +119,8 @@ struct dlfcn_hook
|
||||
void **extra_info, int flags);
|
||||
int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller);
|
||||
void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller);
|
||||
void *(*dlmopen_with_offset) (Lmid_t nsid, const char *file, off_t offset,
|
||||
int mode, void *dl_caller);
|
||||
void *pad[4];
|
||||
};
|
||||
|
||||
@@ -119,8 +129,14 @@ libdl_hidden_proto (_dlfcn_hook)
|
||||
|
||||
extern void *__dlopen (const char *file, int mode DL_CALLER_DECL)
|
||||
attribute_hidden;
|
||||
extern void *__dlopen_with_offset (const char *file, off_t offset,
|
||||
int mode DL_CALLER_DECL)
|
||||
attribute_hidden;
|
||||
extern void *__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
|
||||
attribute_hidden;
|
||||
extern void *__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset,
|
||||
int mode DL_CALLER_DECL)
|
||||
attribute_hidden;
|
||||
extern int __dlclose (void *handle)
|
||||
attribute_hidden;
|
||||
extern void *__dlsym (void *handle, const char *name DL_CALLER_DECL)
|
||||
|
||||
+5
-1
@@ -308,7 +308,8 @@
|
||||
# define __USE_LARGEFILE64 1
|
||||
#endif
|
||||
|
||||
#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
|
||||
#if !(defined SUPPRESS_USE_FILE_OFFSET64) && defined _FILE_OFFSET_BITS && \
|
||||
_FILE_OFFSET_BITS == 64
|
||||
# define __USE_FILE_OFFSET64 1
|
||||
#endif
|
||||
|
||||
@@ -372,6 +373,9 @@
|
||||
#define __GLIBC_PREREQ(maj, min) \
|
||||
((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
|
||||
|
||||
/* GRTEv4 (glibc-2.19) date */
|
||||
#define __GOOGLE_GRTE_VERSION__ 20140228L
|
||||
|
||||
/* This is here only because every header file already includes this one. */
|
||||
#ifndef __ASSEMBLER__
|
||||
# ifndef _SYS_CDEFS_H
|
||||
|
||||
@@ -53,6 +53,7 @@ extern enum nss_status _nss_ ## service ##_initgroups_dyn \
|
||||
long int *size, gid_t **groupsp, long int limit, \
|
||||
int *errnop);
|
||||
|
||||
DECLARE_NSS_PROTOTYPES (cache)
|
||||
DECLARE_NSS_PROTOTYPES (compat)
|
||||
DECLARE_NSS_PROTOTYPES (files)
|
||||
DECLARE_NSS_PROTOTYPES (hesiod)
|
||||
|
||||
@@ -238,6 +238,12 @@ struct link_map
|
||||
dev_t l_dev;
|
||||
ino64_t l_ino;
|
||||
|
||||
/* Google-specific extension, intended to be part of public interface
|
||||
to the debugger. As such, it belongs right after l_prev... except
|
||||
putting it there causes Google libunwind to crash due to its own
|
||||
peeking into glibc internals (see grte_v1_glibc_link_map). */
|
||||
size_t l_off; /* File offset to Elf_Ehdr. */
|
||||
|
||||
/* Collected information about own RUNPATH directories. */
|
||||
struct r_search_path_struct l_runpath_dirs;
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@ extern enum nss_status _nss_ ## service ##_getpwent_r \
|
||||
(struct passwd *result, char *buffer, \
|
||||
size_t buflen, int *errnop);
|
||||
|
||||
DECLARE_NSS_PROTOTYPES (cache)
|
||||
DECLARE_NSS_PROTOTYPES (compat)
|
||||
DECLARE_NSS_PROTOTYPES (files)
|
||||
DECLARE_NSS_PROTOTYPES (borg)
|
||||
DECLARE_NSS_PROTOTYPES (hesiod)
|
||||
DECLARE_NSS_PROTOTYPES (nis)
|
||||
DECLARE_NSS_PROTOTYPES (nisplus)
|
||||
|
||||
+3
-3
@@ -48,11 +48,11 @@ libc_hidden_proto (__res_randomid)
|
||||
libc_hidden_proto (__res_state)
|
||||
|
||||
int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
|
||||
u_char **, u_char **, int *, int *);
|
||||
u_char **, u_char **, int *, int *, int *);
|
||||
int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
|
||||
u_char **, u_char **, int *, int *);
|
||||
u_char **, u_char **, int *, int *, int *);
|
||||
int __libc_res_nsend (res_state, const u_char *, int, const u_char *, int,
|
||||
u_char *, int, u_char **, u_char **, int *, int *)
|
||||
u_char *, int, u_char **, u_char **, int *, int *, int *)
|
||||
attribute_hidden;
|
||||
|
||||
libresolv_hidden_proto (_sethtent)
|
||||
|
||||
@@ -38,6 +38,7 @@ extern enum nss_status _nss_ ## service ## _getspnam_r \
|
||||
(const char *name, struct spwd *pwd, \
|
||||
char *buffer, size_t buflen, int *errnop);
|
||||
|
||||
DECLARE_NSS_PROTOTYPES (cache)
|
||||
DECLARE_NSS_PROTOTYPES (compat)
|
||||
DECLARE_NSS_PROTOTYPES (files)
|
||||
DECLARE_NSS_PROTOTYPES (hesiod)
|
||||
|
||||
@@ -203,6 +203,24 @@ libc_hidden_proto (strtoll)
|
||||
libc_hidden_proto (strtoul)
|
||||
libc_hidden_proto (strtoull)
|
||||
|
||||
extern float __strtof_nan (const char *, char **, char) internal_function;
|
||||
extern double __strtod_nan (const char *, char **, char) internal_function;
|
||||
extern long double __strtold_nan (const char *, char **, char)
|
||||
internal_function;
|
||||
extern float __wcstof_nan (const wchar_t *, wchar_t **, wchar_t)
|
||||
internal_function;
|
||||
extern double __wcstod_nan (const wchar_t *, wchar_t **, wchar_t)
|
||||
internal_function;
|
||||
extern long double __wcstold_nan (const wchar_t *, wchar_t **, wchar_t)
|
||||
internal_function;
|
||||
|
||||
libc_hidden_proto (__strtof_nan)
|
||||
libc_hidden_proto (__strtod_nan)
|
||||
libc_hidden_proto (__strtold_nan)
|
||||
libc_hidden_proto (__wcstof_nan)
|
||||
libc_hidden_proto (__wcstod_nan)
|
||||
libc_hidden_proto (__wcstold_nan)
|
||||
|
||||
extern char *__ecvt (double __value, int __ndigit, int *__restrict __decpt,
|
||||
int *__restrict __sign);
|
||||
extern char *__fcvt (double __value, int __ndigit, int *__restrict __decpt,
|
||||
|
||||
@@ -52,6 +52,9 @@ extern unsigned long long int __wcstoull_internal (const wchar_t *
|
||||
__restrict __endptr,
|
||||
int __base,
|
||||
int __group) __THROW;
|
||||
extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
|
||||
wchar_t **, int, int,
|
||||
__locale_t);
|
||||
libc_hidden_proto (__wcstof_internal)
|
||||
libc_hidden_proto (__wcstod_internal)
|
||||
libc_hidden_proto (__wcstold_internal)
|
||||
|
||||
+5
-1
@@ -60,7 +60,8 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
|
||||
tst-wmemstream1 tst-wmemstream2 \
|
||||
bug-memstream1 bug-wmemstream1 \
|
||||
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
|
||||
tst-fwrite-error tst-ftell-partial-wide
|
||||
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
|
||||
tst-ftell-append
|
||||
ifeq (yes,$(build-shared))
|
||||
# Add test-fopenloc only if shared library is enabled since it depends on
|
||||
# shared localedata objects.
|
||||
@@ -160,6 +161,9 @@ tst-swscanf-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
bug-ftell-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
tst-fgetwc-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
tst-fseek-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
tst-ftell-partial-wide-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
tst-ftell-active-handler-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
tst-ftell-append-ENV = LOCPATH=$(common-objpfx)localedata
|
||||
|
||||
generated = tst-fopenloc.mtrace tst-fopenloc.check
|
||||
|
||||
|
||||
+87
-38
@@ -91,7 +91,9 @@ extern struct __gconv_trans_data __libio_translit attribute_hidden;
|
||||
|
||||
The position in the buffer that corresponds to the position
|
||||
in external file system is normally _IO_read_end, except in putback
|
||||
mode, when it is _IO_save_end.
|
||||
mode, when it is _IO_save_end and also when the file is in append mode,
|
||||
since switching from read to write mode automatically sends the position in
|
||||
the external file system to the end of file.
|
||||
If the field _fb._offset is >= 0, it gives the offset in
|
||||
the file as a whole corresponding to eGptr(). (?)
|
||||
|
||||
@@ -232,13 +234,18 @@ _IO_file_open (fp, filename, posix_mode, prot, read_write, is32not64)
|
||||
return NULL;
|
||||
fp->_fileno = fdesc;
|
||||
_IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
|
||||
if ((read_write & _IO_IS_APPENDING) && (read_write & _IO_NO_READS))
|
||||
if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
|
||||
== _IO_pos_BAD && errno != ESPIPE)
|
||||
{
|
||||
close_not_cancel (fdesc);
|
||||
return NULL;
|
||||
}
|
||||
/* For append mode, send the file offset to the end of the file. Don't
|
||||
update the offset cache though, since the file handle is not active. */
|
||||
if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
|
||||
== (_IO_IS_APPENDING | _IO_NO_READS))
|
||||
{
|
||||
_IO_off64_t new_pos = _IO_SYSSEEK (fp, 0, _IO_seek_end);
|
||||
if (new_pos == _IO_pos_BAD && errno != ESPIPE)
|
||||
{
|
||||
close_not_cancel (fdesc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
_IO_link_in ((struct _IO_FILE_plus *) fp);
|
||||
return fp;
|
||||
}
|
||||
@@ -929,6 +936,68 @@ _IO_file_sync_mmap (_IO_FILE *fp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ftell{,o} implementation. The only time we modify the state of the stream
|
||||
is when we have unflushed writes. In that case we seek to the end and
|
||||
record that offset in the stream object. */
|
||||
static _IO_off64_t
|
||||
do_ftell (_IO_FILE *fp)
|
||||
{
|
||||
_IO_off64_t result, offset = 0;
|
||||
|
||||
/* No point looking at unflushed data if we haven't allocated buffers
|
||||
yet. */
|
||||
if (fp->_IO_buf_base != NULL)
|
||||
{
|
||||
bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
|
||||
|| _IO_in_put_mode (fp));
|
||||
|
||||
bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
|
||||
|
||||
/* When we have unflushed writes in append mode, seek to the end of the
|
||||
file and record that offset. This is the only time we change the file
|
||||
stream state and it is safe since the file handle is active. */
|
||||
if (was_writing && append_mode)
|
||||
{
|
||||
result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
|
||||
if (result == _IO_pos_BAD)
|
||||
return EOF;
|
||||
else
|
||||
fp->_offset = result;
|
||||
}
|
||||
|
||||
/* Adjust for unflushed data. */
|
||||
if (!was_writing)
|
||||
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
||||
/* We don't trust _IO_read_end to represent the current file offset when
|
||||
writing in append mode because the value would have to be shifted to
|
||||
the end of the file during a flush. Use the write base instead, along
|
||||
with the new offset we got above when we did a seek to the end of the
|
||||
file. */
|
||||
else if (append_mode)
|
||||
offset += fp->_IO_write_ptr - fp->_IO_write_base;
|
||||
/* For all other modes, _IO_read_end represents the file offset. */
|
||||
else
|
||||
offset += fp->_IO_write_ptr - fp->_IO_read_end;
|
||||
}
|
||||
|
||||
if (fp->_offset != _IO_pos_BAD)
|
||||
result = fp->_offset;
|
||||
else
|
||||
result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
|
||||
|
||||
if (result == EOF)
|
||||
return result;
|
||||
|
||||
result += offset;
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
__set_errno (EINVAL);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
_IO_off64_t
|
||||
_IO_new_file_seekoff (fp, offset, dir, mode)
|
||||
@@ -940,6 +1009,13 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
|
||||
_IO_off64_t result;
|
||||
_IO_off64_t delta, new_offset;
|
||||
long count;
|
||||
|
||||
/* Short-circuit into a separate function. We don't want to mix any
|
||||
functionality and we don't want to touch anything inside the FILE
|
||||
object. */
|
||||
if (mode == 0)
|
||||
return do_ftell (fp);
|
||||
|
||||
/* POSIX.1 8.2.3.7 says that after a call the fflush() the file
|
||||
offset of the underlying file must be exact. */
|
||||
int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
|
||||
@@ -948,9 +1024,6 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
|
||||
bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
|
||||
|| _IO_in_put_mode (fp));
|
||||
|
||||
if (mode == 0)
|
||||
dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
|
||||
|
||||
/* Flush unwritten characters.
|
||||
(This may do an unneeded write if we seek within the buffer.
|
||||
But to be able to switch to reading, we would need to set
|
||||
@@ -958,7 +1031,7 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
|
||||
which assumes file_ptr() is eGptr. Anyway, since we probably
|
||||
end up flushing when we close(), it doesn't make much difference.)
|
||||
FIXME: simulate mem-mapped files. */
|
||||
else if (was_writing && _IO_switch_to_get_mode (fp))
|
||||
if (was_writing && _IO_switch_to_get_mode (fp))
|
||||
return EOF;
|
||||
|
||||
if (fp->_IO_buf_base == NULL)
|
||||
@@ -978,30 +1051,10 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
|
||||
{
|
||||
case _IO_seek_cur:
|
||||
/* Adjust for read-ahead (bytes is buffer). */
|
||||
if (mode != 0 || !was_writing)
|
||||
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
||||
else
|
||||
{
|
||||
/* _IO_read_end coincides with fp._offset, so the actual file position
|
||||
is fp._offset - (_IO_read_end - new_write_ptr). This is fine
|
||||
even if fp._offset is not set, since fp->_IO_read_end is then at
|
||||
_IO_buf_base and this adjustment is for unbuffered output. */
|
||||
offset -= fp->_IO_read_end - fp->_IO_write_ptr;
|
||||
}
|
||||
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
||||
|
||||
if (fp->_offset == _IO_pos_BAD)
|
||||
{
|
||||
if (mode != 0)
|
||||
goto dumb;
|
||||
else
|
||||
{
|
||||
result = _IO_SYSSEEK (fp, 0, dir);
|
||||
if (result == EOF)
|
||||
return result;
|
||||
|
||||
fp->_offset = result;
|
||||
}
|
||||
}
|
||||
goto dumb;
|
||||
/* Make offset absolute, assuming current pointer is file_ptr(). */
|
||||
offset += fp->_offset;
|
||||
if (offset < 0)
|
||||
@@ -1028,10 +1081,6 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
|
||||
}
|
||||
/* At this point, dir==_IO_seek_set. */
|
||||
|
||||
/* If we are only interested in the current position we've found it now. */
|
||||
if (mode == 0)
|
||||
return offset;
|
||||
|
||||
/* If destination is within current buffer, optimize: */
|
||||
if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
|
||||
&& !_IO_in_backup (fp))
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ fmemopen_write (void *cookie, const char *b, size_t s)
|
||||
|
||||
if (c->pos + s + addnullc > c->size)
|
||||
{
|
||||
if ((size_t) (c->pos + addnullc) == c->size)
|
||||
if ((size_t) (c->pos + addnullc) >= c->size)
|
||||
{
|
||||
__set_errno (ENOSPC);
|
||||
return 0;
|
||||
|
||||
+15
-10
@@ -141,9 +141,6 @@ _IO_new_fdopen (fd, mode)
|
||||
#ifdef _IO_MTSAFE_IO
|
||||
new_f->fp.file._lock = &new_f->lock;
|
||||
#endif
|
||||
/* Set up initially to use the `maybe_mmap' jump tables rather than using
|
||||
__fopen_maybe_mmap to do it, because we need them in place before we
|
||||
call _IO_file_attach or else it will allocate a buffer immediately. */
|
||||
_IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd,
|
||||
#ifdef _G_HAVE_MMAP
|
||||
(use_mmap && (read_write & _IO_NO_WRITES))
|
||||
@@ -159,18 +156,26 @@ _IO_new_fdopen (fd, mode)
|
||||
#if !_IO_UNIFIED_JUMPTABLES
|
||||
new_f->fp.vtable = NULL;
|
||||
#endif
|
||||
if (_IO_file_attach ((_IO_FILE *) &new_f->fp, fd) == NULL)
|
||||
{
|
||||
_IO_setb (&new_f->fp.file, NULL, NULL, 0);
|
||||
_IO_un_link (&new_f->fp);
|
||||
free (new_f);
|
||||
return NULL;
|
||||
}
|
||||
/* We only need to record the fd because _IO_file_init will have unset the
|
||||
offset. It is important to unset the cached offset because the real
|
||||
offset in the file could change between now and when the handle is
|
||||
activated and we would then mislead ftell into believing that we have a
|
||||
valid offset. */
|
||||
new_f->fp.file._fileno = fd;
|
||||
new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE;
|
||||
|
||||
_IO_mask_flags (&new_f->fp.file, read_write,
|
||||
_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
|
||||
|
||||
/* For append mode, set the file offset to the end of the file. Don't
|
||||
update the offset cache though, since the file handle is not active. */
|
||||
if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
|
||||
== (_IO_IS_APPENDING | _IO_NO_READS))
|
||||
{
|
||||
_IO_off64_t new_pos = _IO_SYSSEEK (&new_f->fp.file, 0, _IO_seek_end);
|
||||
if (new_pos == _IO_pos_BAD && errno != ESPIPE)
|
||||
return NULL;
|
||||
}
|
||||
return &new_f->fp.file;
|
||||
}
|
||||
libc_hidden_ver (_IO_new_fdopen, _IO_fdopen)
|
||||
|
||||
@@ -199,12 +199,6 @@ _IO_fwide (fp, mode)
|
||||
|
||||
/* From now on use the wide character callback functions. */
|
||||
((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
|
||||
|
||||
/* One last twist: we get the current stream position. The wide
|
||||
char streams have much more problems with not knowing the
|
||||
current position and so we should disable the optimization
|
||||
which allows the functions without knowing the position. */
|
||||
fp->_offset = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
|
||||
}
|
||||
|
||||
/* Set the mode now. */
|
||||
|
||||
@@ -397,6 +397,7 @@ extern void _IO_wdoallocbuf (_IO_FILE *) __THROW;
|
||||
libc_hidden_proto (_IO_wdoallocbuf)
|
||||
extern void _IO_unsave_wmarkers (_IO_FILE *) __THROW;
|
||||
extern unsigned _IO_adjust_wcolumn (unsigned, const wchar_t *, int) __THROW;
|
||||
extern _IO_off64_t get_file_offset (_IO_FILE *fp);
|
||||
|
||||
/* Marker-related function. */
|
||||
|
||||
|
||||
+17
-5
@@ -1,5 +1,5 @@
|
||||
/* Test for fmemopen implementation.
|
||||
Copyright (C) 2000-2014 Free Software Foundation, Inc.
|
||||
Copyright (C) 2000-2015 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
|
||||
|
||||
@@ -21,19 +21,31 @@ static char buffer[] = "foobar";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
int
|
||||
main (void)
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ch;
|
||||
FILE *stream;
|
||||
int ret = 0;
|
||||
|
||||
stream = fmemopen (buffer, strlen (buffer), "r");
|
||||
stream = fmemopen (buffer, strlen (buffer), "r+");
|
||||
|
||||
while ((ch = fgetc (stream)) != EOF)
|
||||
printf ("Got %c\n", ch);
|
||||
|
||||
fputc ('1', stream);
|
||||
if (fflush (stream) != EOF || errno != ENOSPC)
|
||||
{
|
||||
printf ("fflush didn't fail with ENOSPC\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
fclose (stream);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
@@ -0,0 +1,488 @@
|
||||
/* Verify that ftell returns the correct value at various points before and
|
||||
after the handler on which it is called becomes active.
|
||||
Copyright (C) 2014 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
|
||||
static int do_test (void);
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
#define get_handles_fdopen(filename, fd, fp, fd_mode, mode) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
(fd) = open ((filename), (fd_mode), 0); \
|
||||
if ((fd) == -1) \
|
||||
{ \
|
||||
printf ("open failed: %m\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(fp) = fdopen ((fd), (mode)); \
|
||||
if ((fp) == NULL) \
|
||||
{ \
|
||||
printf ("fdopen failed: %m\n"); \
|
||||
close (fd); \
|
||||
ret = 1; \
|
||||
} \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define get_handles_fopen(filename, fd, fp, mode) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
(fp) = fopen ((filename), (mode)); \
|
||||
if ((fp) == NULL) \
|
||||
{ \
|
||||
printf ("fopen failed: %m\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(fd) = fileno (fp); \
|
||||
if ((fd) == -1) \
|
||||
{ \
|
||||
printf ("fileno failed: %m\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
/* data points to either char_data or wide_data, depending on whether we're
|
||||
testing regular file mode or wide mode respectively. Similarly,
|
||||
fputs_func points to either fputs or fputws. data_len keeps track of the
|
||||
length of the current data and file_len maintains the current file
|
||||
length. */
|
||||
static const void *data;
|
||||
static const char *char_data = "abcdef";
|
||||
static const wchar_t *wide_data = L"abcdef";
|
||||
static size_t data_len;
|
||||
static size_t file_len;
|
||||
|
||||
typedef int (*fputs_func_t) (const void *data, FILE *fp);
|
||||
fputs_func_t fputs_func;
|
||||
|
||||
/* Test that ftell output after a rewind is correct. */
|
||||
static int
|
||||
do_rewind_test (const char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
struct test
|
||||
{
|
||||
const char *mode;
|
||||
int fd_mode;
|
||||
size_t old_off;
|
||||
size_t new_off;
|
||||
} test_modes[] = {
|
||||
{"w", O_WRONLY, 0, data_len},
|
||||
{"w+", O_RDWR, 0, data_len},
|
||||
{"r+", O_RDWR, 0, data_len},
|
||||
/* The new offsets for 'a' and 'a+' modes have to factor in the
|
||||
previous writes since they always append to the end of the
|
||||
file. */
|
||||
{"a", O_WRONLY, 0, 3 * data_len},
|
||||
{"a+", O_RDWR, 0, 4 * data_len},
|
||||
};
|
||||
|
||||
/* Empty the file before the test so that our offsets are simple to
|
||||
calculate. */
|
||||
FILE *fp = fopen (filename, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf ("Failed to open file for emptying\n");
|
||||
return 1;
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
int fileret;
|
||||
|
||||
printf ("\trewind: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen",
|
||||
test_modes[i].mode);
|
||||
|
||||
if (j == 0)
|
||||
fileret = get_handles_fdopen (filename, fd, fp,
|
||||
test_modes[i].fd_mode,
|
||||
test_modes[i].mode);
|
||||
else
|
||||
fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
|
||||
|
||||
if (fileret != 0)
|
||||
return fileret;
|
||||
|
||||
/* Write some content to the file, rewind and ensure that the ftell
|
||||
output after the rewind is 0. POSIX does not specify what the
|
||||
behavior is when a file is rewound in 'a' mode, so we retain
|
||||
current behavior, which is to keep the 0 offset. */
|
||||
size_t written = fputs_func (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs[1] failed to write data\n");
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
rewind (fp);
|
||||
long offset = ftell (fp);
|
||||
|
||||
if (offset != test_modes[i].old_off)
|
||||
{
|
||||
printf ("Incorrect old offset. Expected %zu, but got %ld, ",
|
||||
test_modes[i].old_off, offset);
|
||||
ret |= 1;
|
||||
}
|
||||
else
|
||||
printf ("old offset = %ld, ", offset);
|
||||
|
||||
written = fputs_func (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs[1] failed to write data\n");
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
/* After this write, the offset in append modes should factor in the
|
||||
implicit lseek to the end of file. */
|
||||
offset = ftell (fp);
|
||||
if (offset != test_modes[i].new_off)
|
||||
{
|
||||
printf ("Incorrect new offset. Expected %zu, but got %ld\n",
|
||||
test_modes[i].new_off, offset);
|
||||
ret |= 1;
|
||||
}
|
||||
else
|
||||
printf ("new offset = %ld\n", offset);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Test that the value of ftell is not cached when the stream handle is not
|
||||
active. */
|
||||
static int
|
||||
do_ftell_test (const char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
struct test
|
||||
{
|
||||
const char *mode;
|
||||
int fd_mode;
|
||||
size_t old_off;
|
||||
size_t new_off;
|
||||
} test_modes[] = {
|
||||
/* In w, w+ and r+ modes, the file position should be at the
|
||||
beginning of the file. After the write, the offset should be
|
||||
updated to data_len. */
|
||||
{"w", O_WRONLY, 0, data_len},
|
||||
{"w+", O_RDWR, 0, data_len},
|
||||
{"r+", O_RDWR, 0, data_len},
|
||||
/* For the 'a' mode, the initial file position should be the
|
||||
current end of file. After the write, the offset has data_len
|
||||
added to the old value. For a+ mode however, the initial file
|
||||
position is the file position of the underlying file descriptor,
|
||||
since it is initially assumed to be in read mode. */
|
||||
{"a", O_WRONLY, data_len, 2 * data_len},
|
||||
{"a+", O_RDWR, 0, 3 * data_len},
|
||||
};
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
printf ("\tftell: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen",
|
||||
test_modes[i].mode);
|
||||
|
||||
if (j == 0)
|
||||
ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode,
|
||||
test_modes[i].mode);
|
||||
else
|
||||
ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
long off = ftell (fp);
|
||||
if (off != test_modes[i].old_off)
|
||||
{
|
||||
printf ("Incorrect old offset. Expected %zu but got %ld, ",
|
||||
test_modes[i].old_off, off);
|
||||
ret |= 1;
|
||||
}
|
||||
else
|
||||
printf ("old offset = %ld, ", off);
|
||||
|
||||
/* The effect of this write on the offset should be seen in the ftell
|
||||
call that follows it. */
|
||||
int ret = write (fd, data, data_len);
|
||||
off = ftell (fp);
|
||||
|
||||
if (off != test_modes[i].new_off)
|
||||
{
|
||||
printf ("Incorrect new offset. Expected %zu but got %ld\n",
|
||||
test_modes[i].new_off, off);
|
||||
ret |= 1;
|
||||
}
|
||||
else
|
||||
printf ("new offset = %ld\n", off);
|
||||
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This test opens the file for writing, moves the file offset of the
|
||||
underlying file, writes out data and then checks if ftell trips on it. */
|
||||
static int
|
||||
do_write_test (const char *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int fd;
|
||||
int ret = 0;
|
||||
struct test
|
||||
{
|
||||
const char *mode;
|
||||
int fd_mode;
|
||||
} test_modes[] = {
|
||||
{"w", O_WRONLY},
|
||||
{"w+", O_RDWR},
|
||||
{"r+", O_RDWR}
|
||||
};
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
|
||||
{
|
||||
printf ("\twrite: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen",
|
||||
test_modes[i].mode);
|
||||
|
||||
if (j == 0)
|
||||
ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
|
||||
else
|
||||
ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode,
|
||||
test_modes[i].mode);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* Move offset to just before the end of the file. */
|
||||
off_t ret = lseek (fd, file_len - 1, SEEK_SET);
|
||||
if (ret == -1)
|
||||
{
|
||||
printf ("lseek failed: %m\n");
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
/* Write some data. */
|
||||
size_t written = fputs_func (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs[1] failed to write data\n");
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
/* Verify that the offset points to the end of the file. The length
|
||||
of the file would be the original length + the length of data
|
||||
written to it - the amount by which we moved the offset using
|
||||
lseek. */
|
||||
long offset = ftell (fp);
|
||||
file_len = file_len - 1 + data_len;
|
||||
|
||||
if (offset != file_len)
|
||||
{
|
||||
printf ("Incorrect offset. Expected %zu, but got %ld\n",
|
||||
file_len, offset);
|
||||
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
printf ("offset = %ld\n", offset);
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This test opens a file in append mode, writes some data, and then verifies
|
||||
that ftell does not trip over it. */
|
||||
static int
|
||||
do_append_test (const char *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int ret = 0;
|
||||
int fd;
|
||||
|
||||
struct test
|
||||
{
|
||||
const char *mode;
|
||||
int fd_mode;
|
||||
} test_modes[] = {
|
||||
{"a", O_WRONLY},
|
||||
{"a+", O_RDWR}
|
||||
};
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
|
||||
{
|
||||
printf ("\tappend: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen",
|
||||
test_modes[i].mode);
|
||||
|
||||
if (j == 0)
|
||||
ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
|
||||
else
|
||||
ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode,
|
||||
test_modes[i].mode);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* Write some data. */
|
||||
size_t written = fputs_func (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs[1] failed to write all data\n");
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
/* Verify that the offset points to the end of the file. The file
|
||||
len is maintained by adding data_len each time to reflect the data
|
||||
written to it. */
|
||||
long offset = ftell (fp);
|
||||
file_len += data_len;
|
||||
|
||||
if (offset != file_len)
|
||||
{
|
||||
printf ("Incorrect offset. Expected %zu, but got %ld\n",
|
||||
file_len, offset);
|
||||
|
||||
ret |= 1;
|
||||
}
|
||||
|
||||
printf ("offset = %ld\n", offset);
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_one_test (const char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret |= do_ftell_test (filename);
|
||||
ret |= do_write_test (filename);
|
||||
ret |= do_append_test (filename);
|
||||
ret |= do_rewind_test (filename);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Run a set of tests for ftell for regular files and wide mode files. */
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *fp = NULL;
|
||||
char *filename;
|
||||
size_t written;
|
||||
int fd = create_temp_file ("tst-active-handler-tmp.", &filename);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
printf ("create_temp_file: %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp = fdopen (fd, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf ("fdopen[0]: %m\n");
|
||||
close (fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
data = char_data;
|
||||
data_len = strlen (char_data);
|
||||
file_len = strlen (char_data);
|
||||
written = fputs (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs[1] failed to write data\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Tests for regular files. */
|
||||
puts ("Regular mode:");
|
||||
fputs_func = (fputs_func_t) fputs;
|
||||
data = char_data;
|
||||
data_len = strlen (char_data);
|
||||
ret |= do_one_test (filename);
|
||||
|
||||
/* Truncate the file before repeating the tests in wide mode. */
|
||||
fp = fopen (filename, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf ("fopen failed %m\n");
|
||||
return 1;
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
/* Tests for wide files. */
|
||||
puts ("Wide mode:");
|
||||
if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
|
||||
{
|
||||
printf ("Cannot set en_US.UTF-8 locale.\n");
|
||||
return 1;
|
||||
}
|
||||
fputs_func = (fputs_func_t) fputws;
|
||||
data = wide_data;
|
||||
data_len = wcslen (wide_data);
|
||||
ret |= do_one_test (filename);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/* Verify that ftell returns the correct value after a read and a write on a
|
||||
file opened in a+ mode.
|
||||
Copyright (C) 2014 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
|
||||
/* data points to either char_data or wide_data, depending on whether we're
|
||||
testing regular file mode or wide mode respectively. Similarly,
|
||||
fputs_func points to either fputs or fputws. data_len keeps track of the
|
||||
length of the current data and file_len maintains the current file
|
||||
length. */
|
||||
#define BUF_LEN 4
|
||||
static void *buf;
|
||||
static char char_buf[BUF_LEN];
|
||||
static wchar_t wide_buf[BUF_LEN];
|
||||
static const void *data;
|
||||
static const char *char_data = "abcdefghijklmnopqrstuvwxyz";
|
||||
static const wchar_t *wide_data = L"abcdefghijklmnopqrstuvwxyz";
|
||||
static size_t data_len;
|
||||
static size_t file_len;
|
||||
|
||||
typedef int (*fputs_func_t) (const void *data, FILE *fp);
|
||||
fputs_func_t fputs_func;
|
||||
|
||||
typedef void *(*fgets_func_t) (void *s, int size, FILE *stream);
|
||||
fgets_func_t fgets_func;
|
||||
|
||||
static int do_test (void);
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
static FILE *
|
||||
init_file (const char *filename)
|
||||
{
|
||||
FILE *fp = fopen (filename, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf ("fopen: %m\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int written = fputs_func (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs failed to write data\n");
|
||||
fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_len = data_len;
|
||||
|
||||
fclose (fp);
|
||||
|
||||
fp = fopen (filename, "a+");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf ("fopen(a+): %m\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static int
|
||||
do_one_test (const char *filename)
|
||||
{
|
||||
FILE *fp = init_file (filename);
|
||||
|
||||
if (fp == NULL)
|
||||
return 1;
|
||||
|
||||
void *ret = fgets_func (buf, BUF_LEN, fp);
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
printf ("read failed: %m\n");
|
||||
fclose (fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int written = fputs_func (data, fp);
|
||||
|
||||
if (written == EOF)
|
||||
{
|
||||
printf ("fputs failed to write data\n");
|
||||
fclose (fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file_len += data_len;
|
||||
|
||||
long off = ftell (fp);
|
||||
|
||||
if (off != file_len)
|
||||
{
|
||||
printf ("Incorrect offset %ld, expected %zu\n", off, file_len);
|
||||
fclose (fp);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
printf ("Correct offset %ld after write.\n", off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Run the tests for regular files and wide mode files. */
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0;
|
||||
char *filename;
|
||||
int fd = create_temp_file ("tst-ftell-append-tmp.", &filename);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
printf ("create_temp_file: %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
/* Tests for regular files. */
|
||||
puts ("Regular mode:");
|
||||
fputs_func = (fputs_func_t) fputs;
|
||||
fgets_func = (fgets_func_t) fgets;
|
||||
data = char_data;
|
||||
buf = char_buf;
|
||||
data_len = strlen (char_data);
|
||||
ret |= do_one_test (filename);
|
||||
|
||||
/* Tests for wide files. */
|
||||
puts ("Wide mode:");
|
||||
if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
|
||||
{
|
||||
printf ("Cannot set en_US.UTF-8 locale.\n");
|
||||
return 1;
|
||||
}
|
||||
fputs_func = (fputs_func_t) fputws;
|
||||
fgets_func = (fgets_func_t) fgetws;
|
||||
data = wide_data;
|
||||
buf = wide_buf;
|
||||
data_len = wcslen (wide_data);
|
||||
ret |= do_one_test (filename);
|
||||
|
||||
return ret;
|
||||
}
|
||||
+158
-102
@@ -596,29 +596,39 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
_IO_off64_t
|
||||
_IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
_IO_FILE *fp;
|
||||
_IO_off64_t offset;
|
||||
int dir;
|
||||
int mode;
|
||||
/* ftell{,o} implementation for wide mode. Don't modify any state of the file
|
||||
pointer while we try to get the current state of the stream except in one
|
||||
case, which is when we have unflushed writes in append mode. */
|
||||
static _IO_off64_t
|
||||
do_ftell_wide (_IO_FILE *fp)
|
||||
{
|
||||
_IO_off64_t result;
|
||||
_IO_off64_t delta, new_offset;
|
||||
long int count;
|
||||
/* POSIX.1 8.2.3.7 says that after a call the fflush() the file
|
||||
offset of the underlying file must be exact. */
|
||||
int must_be_exact = ((fp->_wide_data->_IO_read_base
|
||||
== fp->_wide_data->_IO_read_end)
|
||||
&& (fp->_wide_data->_IO_write_base
|
||||
== fp->_wide_data->_IO_write_ptr));
|
||||
_IO_off64_t result, offset = 0;
|
||||
|
||||
bool was_writing = ((fp->_wide_data->_IO_write_ptr
|
||||
> fp->_wide_data->_IO_write_base)
|
||||
|| _IO_in_put_mode (fp));
|
||||
|
||||
if (mode == 0)
|
||||
/* No point looking for offsets in the buffer if it hasn't even been
|
||||
allocated. */
|
||||
if (fp->_wide_data->_IO_buf_base != NULL)
|
||||
{
|
||||
const wchar_t *wide_read_base;
|
||||
const wchar_t *wide_read_ptr;
|
||||
const wchar_t *wide_read_end;
|
||||
bool was_writing = ((fp->_wide_data->_IO_write_ptr
|
||||
> fp->_wide_data->_IO_write_base)
|
||||
|| _IO_in_put_mode (fp));
|
||||
|
||||
bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
|
||||
|
||||
/* When we have unflushed writes in append mode, seek to the end of the
|
||||
file and record that offset. This is the only time we change the file
|
||||
stream state and it is safe since the file handle is active. */
|
||||
if (was_writing && append_mode)
|
||||
{
|
||||
result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
|
||||
if (result == _IO_pos_BAD)
|
||||
return EOF;
|
||||
else
|
||||
fp->_offset = result;
|
||||
}
|
||||
|
||||
/* XXX For wide stream with backup store it is not very
|
||||
reasonable to determine the offset. The pushed-back
|
||||
character might require a state change and we need not be
|
||||
@@ -633,14 +643,136 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* There is no more data in the backup buffer. We can
|
||||
switch back. */
|
||||
_IO_switch_to_main_wget_area (fp);
|
||||
/* Nothing in the backup store, so note the backed up pointers
|
||||
without changing the state. */
|
||||
wide_read_base = fp->_wide_data->_IO_save_base;
|
||||
wide_read_ptr = wide_read_base;
|
||||
wide_read_end = fp->_wide_data->_IO_save_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
wide_read_base = fp->_wide_data->_IO_read_base;
|
||||
wide_read_ptr = fp->_wide_data->_IO_read_ptr;
|
||||
wide_read_end = fp->_wide_data->_IO_read_end;
|
||||
}
|
||||
|
||||
dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
|
||||
struct _IO_codecvt *cv = fp->_codecvt;
|
||||
int clen = (*cv->__codecvt_do_encoding) (cv);
|
||||
|
||||
if (!was_writing)
|
||||
{
|
||||
if (clen > 0)
|
||||
{
|
||||
offset -= (wide_read_end - wide_read_ptr) * clen;
|
||||
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nread;
|
||||
|
||||
size_t delta = wide_read_ptr - wide_read_base;
|
||||
__mbstate_t state = fp->_wide_data->_IO_last_state;
|
||||
nread = (*cv->__codecvt_do_length) (cv, &state,
|
||||
fp->_IO_read_base,
|
||||
fp->_IO_read_end, delta);
|
||||
offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (clen > 0)
|
||||
offset += (fp->_wide_data->_IO_write_ptr
|
||||
- fp->_wide_data->_IO_write_base) * clen;
|
||||
else
|
||||
{
|
||||
size_t delta = (fp->_wide_data->_IO_write_ptr
|
||||
- fp->_wide_data->_IO_write_base);
|
||||
|
||||
/* Allocate enough space for the conversion. */
|
||||
size_t outsize = delta * sizeof (wchar_t);
|
||||
char *out = malloc (outsize);
|
||||
char *outstop = out;
|
||||
const wchar_t *in = fp->_wide_data->_IO_write_base;
|
||||
|
||||
enum __codecvt_result status;
|
||||
|
||||
__mbstate_t state = fp->_wide_data->_IO_last_state;
|
||||
status = (*cv->__codecvt_do_out) (cv, &state,
|
||||
in, in + delta, &in,
|
||||
out, out + outsize, &outstop);
|
||||
|
||||
/* We don't check for __codecvt_partial because it can be
|
||||
returned on one of two conditions: either the output
|
||||
buffer is full or the input sequence is incomplete. We
|
||||
take care to allocate enough buffer and our input
|
||||
sequences must be complete since they are accepted as
|
||||
wchar_t; if not, then that is an error. */
|
||||
if (__glibc_unlikely (status != __codecvt_ok))
|
||||
return WEOF;
|
||||
|
||||
offset += outstop - out;
|
||||
}
|
||||
|
||||
/* We don't trust _IO_read_end to represent the current file offset
|
||||
when writing in append mode because the value would have to be
|
||||
shifted to the end of the file during a flush. Use the write base
|
||||
instead, along with the new offset we got above when we did a seek
|
||||
to the end of the file. */
|
||||
if (append_mode)
|
||||
offset += fp->_IO_write_ptr - fp->_IO_write_base;
|
||||
/* For all other modes, _IO_read_end represents the file offset. */
|
||||
else
|
||||
offset += fp->_IO_write_ptr - fp->_IO_read_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp->_offset != _IO_pos_BAD)
|
||||
result = fp->_offset;
|
||||
else
|
||||
result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
|
||||
|
||||
if (result == EOF)
|
||||
return result;
|
||||
|
||||
result += offset;
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
__set_errno (EINVAL);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
_IO_off64_t
|
||||
_IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
_IO_FILE *fp;
|
||||
_IO_off64_t offset;
|
||||
int dir;
|
||||
int mode;
|
||||
{
|
||||
_IO_off64_t result;
|
||||
_IO_off64_t delta, new_offset;
|
||||
long int count;
|
||||
|
||||
/* Short-circuit into a separate function. We don't want to mix any
|
||||
functionality and we don't want to touch anything inside the FILE
|
||||
object. */
|
||||
if (mode == 0)
|
||||
return do_ftell_wide (fp);
|
||||
|
||||
/* POSIX.1 8.2.3.7 says that after a call the fflush() the file
|
||||
offset of the underlying file must be exact. */
|
||||
int must_be_exact = ((fp->_wide_data->_IO_read_base
|
||||
== fp->_wide_data->_IO_read_end)
|
||||
&& (fp->_wide_data->_IO_write_base
|
||||
== fp->_wide_data->_IO_write_ptr));
|
||||
|
||||
bool was_writing = ((fp->_wide_data->_IO_write_ptr
|
||||
> fp->_wide_data->_IO_write_base)
|
||||
|| _IO_in_put_mode (fp));
|
||||
|
||||
/* Flush unwritten characters.
|
||||
(This may do an unneeded write if we seek within the buffer.
|
||||
But to be able to switch to reading, we would need to set
|
||||
@@ -648,7 +780,7 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
which assumes file_ptr() is eGptr. Anyway, since we probably
|
||||
end up flushing when we close(), it doesn't make much difference.)
|
||||
FIXME: simulate mem-mapped files. */
|
||||
else if (was_writing && _IO_switch_to_wget_mode (fp))
|
||||
if (was_writing && _IO_switch_to_wget_mode (fp))
|
||||
return WEOF;
|
||||
|
||||
if (fp->_wide_data->_IO_buf_base == NULL)
|
||||
@@ -693,7 +825,6 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
{
|
||||
int nread;
|
||||
|
||||
flushed:
|
||||
delta = (fp->_wide_data->_IO_read_ptr
|
||||
- fp->_wide_data->_IO_read_base);
|
||||
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
|
||||
@@ -706,80 +837,9 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *new_write_ptr = fp->_IO_write_ptr;
|
||||
|
||||
if (clen > 0)
|
||||
offset += (fp->_wide_data->_IO_write_ptr
|
||||
- fp->_wide_data->_IO_write_base) / clen;
|
||||
else
|
||||
{
|
||||
enum __codecvt_result status = __codecvt_ok;
|
||||
delta = (fp->_wide_data->_IO_write_ptr
|
||||
- fp->_wide_data->_IO_write_base);
|
||||
const wchar_t *write_base = fp->_wide_data->_IO_write_base;
|
||||
|
||||
/* FIXME: This actually ends up in two iterations of conversion,
|
||||
one here and the next when the buffer actually gets flushed.
|
||||
It may be possible to optimize this in future so that
|
||||
wdo_write identifies already converted content and does not
|
||||
redo it. In any case, this is much better than having to
|
||||
flush buffers for every ftell. */
|
||||
do
|
||||
{
|
||||
/* There is not enough space in the buffer to do the entire
|
||||
conversion, so there is no point trying to avoid the
|
||||
buffer flush. Just do it and go back to how it was with
|
||||
the read mode. */
|
||||
if (status == __codecvt_partial
|
||||
|| (delta > 0 && new_write_ptr == fp->_IO_buf_end))
|
||||
{
|
||||
if (_IO_switch_to_wget_mode (fp))
|
||||
return WEOF;
|
||||
goto flushed;
|
||||
}
|
||||
|
||||
const wchar_t *new_wbase = fp->_wide_data->_IO_write_base;
|
||||
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
|
||||
status = (*cv->__codecvt_do_out) (cv,
|
||||
&fp->_wide_data->_IO_state,
|
||||
write_base,
|
||||
write_base + delta,
|
||||
&new_wbase,
|
||||
new_write_ptr,
|
||||
fp->_IO_buf_end,
|
||||
&new_write_ptr);
|
||||
|
||||
delta -= new_wbase - write_base;
|
||||
|
||||
/* If there was an error, then return WEOF.
|
||||
TODO: set buffer state. */
|
||||
if (__builtin_expect (status == __codecvt_error, 0))
|
||||
return WEOF;
|
||||
}
|
||||
while (delta > 0);
|
||||
}
|
||||
|
||||
/* _IO_read_end coincides with fp._offset, so the actual file position
|
||||
is fp._offset - (_IO_read_end - new_write_ptr). This is fine
|
||||
even if fp._offset is not set, since fp->_IO_read_end is then at
|
||||
_IO_buf_base and this adjustment is for unbuffered output. */
|
||||
offset -= fp->_IO_read_end - new_write_ptr;
|
||||
}
|
||||
|
||||
if (fp->_offset == _IO_pos_BAD)
|
||||
{
|
||||
if (mode != 0)
|
||||
goto dumb;
|
||||
else
|
||||
{
|
||||
result = _IO_SYSSEEK (fp, 0, dir);
|
||||
if (result == EOF)
|
||||
return result;
|
||||
fp->_offset = result;
|
||||
}
|
||||
}
|
||||
goto dumb;
|
||||
|
||||
/* Make offset absolute, assuming current pointer is file_ptr(). */
|
||||
offset += fp->_offset;
|
||||
@@ -802,10 +862,6 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
|
||||
}
|
||||
/* At this point, dir==_IO_seek_set. */
|
||||
|
||||
/* If we are only interested in the current position we've found it now. */
|
||||
if (mode == 0)
|
||||
return offset;
|
||||
|
||||
/* If destination is within current buffer, optimize: */
|
||||
if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
|
||||
&& !_IO_in_backup (fp))
|
||||
|
||||
+61
-13
@@ -17,6 +17,7 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -57,6 +58,45 @@ struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST];
|
||||
|
||||
const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR;
|
||||
|
||||
/* Checks if the name is actually present, that is, not NULL and not
|
||||
empty. */
|
||||
static inline int
|
||||
name_present (const char *name)
|
||||
{
|
||||
return name != NULL && name[0] != '\0';
|
||||
}
|
||||
|
||||
/* Checks that the locale name neither extremely long, nor contains a
|
||||
".." path component (to prevent directory traversal). */
|
||||
static inline int
|
||||
valid_locale_name (const char *name)
|
||||
{
|
||||
/* Not set. */
|
||||
size_t namelen = strlen (name);
|
||||
/* Name too long. The limit is arbitrary and prevents stack overflow
|
||||
issues later. */
|
||||
if (__glibc_unlikely (namelen > 255))
|
||||
return 0;
|
||||
/* Directory traversal attempt. */
|
||||
static const char slashdot[4] = {'/', '.', '.', '/'};
|
||||
if (__glibc_unlikely (memmem (name, namelen,
|
||||
slashdot, sizeof (slashdot)) != NULL))
|
||||
return 0;
|
||||
if (namelen == 2 && __glibc_unlikely (name[0] == '.' && name [1] == '.'))
|
||||
return 0;
|
||||
if (namelen >= 3
|
||||
&& __glibc_unlikely (((name[0] == '.'
|
||||
&& name[1] == '.'
|
||||
&& name[2] == '/')
|
||||
|| (name[namelen - 3] == '/'
|
||||
&& name[namelen - 2] == '.'
|
||||
&& name[namelen - 1] == '.'))))
|
||||
return 0;
|
||||
/* If there is a slash in the name, it must start with one. */
|
||||
if (__glibc_unlikely (memchr (name, '/', namelen) != NULL) && name[0] != '/')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct __locale_data *
|
||||
internal_function
|
||||
@@ -65,7 +105,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
|
||||
{
|
||||
int mask;
|
||||
/* Name of the locale for this category. */
|
||||
char *loc_name;
|
||||
char *loc_name = (char *) *name;
|
||||
const char *language;
|
||||
const char *modifier;
|
||||
const char *territory;
|
||||
@@ -73,31 +113,39 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
|
||||
const char *normalized_codeset;
|
||||
struct loaded_l10nfile *locale_file;
|
||||
|
||||
if ((*name)[0] == '\0')
|
||||
if (loc_name[0] == '\0')
|
||||
{
|
||||
/* The user decides which locale to use by setting environment
|
||||
variables. */
|
||||
*name = getenv ("LC_ALL");
|
||||
if (*name == NULL || (*name)[0] == '\0')
|
||||
*name = getenv (_nl_category_names.str
|
||||
loc_name = getenv ("LC_ALL");
|
||||
if (!name_present (loc_name))
|
||||
loc_name = getenv (_nl_category_names.str
|
||||
+ _nl_category_name_idxs[category]);
|
||||
if (*name == NULL || (*name)[0] == '\0')
|
||||
*name = getenv ("LANG");
|
||||
if (!name_present (loc_name))
|
||||
loc_name = getenv ("LANG");
|
||||
if (!name_present (loc_name))
|
||||
loc_name = (char *) _nl_C_name;
|
||||
}
|
||||
|
||||
if (*name == NULL || (*name)[0] == '\0'
|
||||
|| (__builtin_expect (__libc_enable_secure, 0)
|
||||
&& strchr (*name, '/') != NULL))
|
||||
*name = (char *) _nl_C_name;
|
||||
/* We used to fall back to the C locale if the name contains a slash
|
||||
character '/', but we now check for directory traversal in
|
||||
valid_locale_name, so this is no longer necessary. */
|
||||
|
||||
if (__builtin_expect (strcmp (*name, _nl_C_name), 1) == 0
|
||||
|| __builtin_expect (strcmp (*name, _nl_POSIX_name), 1) == 0)
|
||||
if (__builtin_expect (strcmp (loc_name, _nl_C_name), 1) == 0
|
||||
|| __builtin_expect (strcmp (loc_name, _nl_POSIX_name), 1) == 0)
|
||||
{
|
||||
/* We need not load anything. The needed data is contained in
|
||||
the library itself. */
|
||||
*name = (char *) _nl_C_name;
|
||||
return _nl_C[category];
|
||||
}
|
||||
else if (!valid_locale_name (loc_name))
|
||||
{
|
||||
__set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*name = loc_name;
|
||||
|
||||
/* We really have to load some data. First we try the archive,
|
||||
but only if there was no LOCPATH environment variable specified. */
|
||||
|
||||
@@ -67,12 +67,20 @@ static const char *locnames[] =
|
||||
#undef DEFINE_CATEGORY
|
||||
};
|
||||
|
||||
/* Google local change: we've reduced the initial archive header
|
||||
sizes, since we use very few of the entries. This saves ~100k.
|
||||
|
||||
The hash tables are sized larger than the number of entries we use.
|
||||
The code will round their sizes up to the next power of 2, and if
|
||||
it finds that they're >75% full will grow them as well. We set the
|
||||
defaults to the size that we'll end up with given what we use.
|
||||
|
||||
The vectors are sized exactly to hold what we use. */
|
||||
/* Size of the initial archive header. */
|
||||
#define INITIAL_NUM_NAMES 900
|
||||
#define INITIAL_SIZE_STRINGS 7500
|
||||
#define INITIAL_NUM_LOCREC 420
|
||||
#define INITIAL_NUM_SUMS 2000
|
||||
#define INITIAL_NUM_NAMES 5 /* (hash table of structs) We use 3. */
|
||||
#define INITIAL_SIZE_STRINGS 32 /* (vector of bytes) We use 32. */
|
||||
#define INITIAL_NUM_LOCREC 2 /* (vector of structs) We use 2. */
|
||||
#define INITIAL_NUM_SUMS 11 /* (hash table of structs) We use 6. */
|
||||
|
||||
|
||||
/* Get and set values (possibly endian-swapped) in structures mapped
|
||||
|
||||
+12
-2
@@ -272,6 +272,8 @@ setlocale (int category, const char *locale)
|
||||
of entries of the form `CATEGORY=VALUE'. */
|
||||
const char *newnames[__LC_LAST];
|
||||
struct __locale_data *newdata[__LC_LAST];
|
||||
/* Copy of the locale argument, for in-place splitting. */
|
||||
char *locale_copy = NULL;
|
||||
|
||||
/* Set all name pointers to the argument name. */
|
||||
for (category = 0; category < __LC_LAST; ++category)
|
||||
@@ -281,7 +283,13 @@ setlocale (int category, const char *locale)
|
||||
if (__builtin_expect (strchr (locale, ';') != NULL, 0))
|
||||
{
|
||||
/* This is a composite name. Make a copy and split it up. */
|
||||
char *np = strdupa (locale);
|
||||
locale_copy = strdup (locale);
|
||||
if (__glibc_unlikely (locale_copy == NULL))
|
||||
{
|
||||
__libc_rwlock_unlock (__libc_setlocale_lock);
|
||||
return NULL;
|
||||
}
|
||||
char *np = locale_copy;
|
||||
char *cp;
|
||||
int cnt;
|
||||
|
||||
@@ -299,6 +307,7 @@ setlocale (int category, const char *locale)
|
||||
{
|
||||
error_return:
|
||||
__libc_rwlock_unlock (__libc_setlocale_lock);
|
||||
free (locale_copy);
|
||||
|
||||
/* Bogus category name. */
|
||||
ERROR_RETURN;
|
||||
@@ -391,8 +400,9 @@ setlocale (int category, const char *locale)
|
||||
/* Critical section left. */
|
||||
__libc_rwlock_unlock (__libc_setlocale_lock);
|
||||
|
||||
/* Free the resources (the locale path variable). */
|
||||
/* Free the resources. */
|
||||
free (locale_path);
|
||||
free (locale_copy);
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
@@ -398,8 +398,17 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
|
||||
|
||||
|
||||
/* Definition for getting more memory from the OS. */
|
||||
#if 0 /* Google-local: b/5732800: make calls go through PLT instead. */
|
||||
#define MORECORE (*__morecore)
|
||||
#define MORECORE_FAILURE 0
|
||||
#else
|
||||
#define __mmap mmap
|
||||
#define __munmap munmap
|
||||
#define __mremap mremap
|
||||
#define __mprotect mprotect
|
||||
#define MORECORE sbrk
|
||||
#define MORECORE_FAILURE -1
|
||||
#endif
|
||||
void * __default_morecore (ptrdiff_t);
|
||||
void *(*__morecore)(ptrdiff_t) = __default_morecore;
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ tests = test-matherr test-fenv atest-exp atest-sincos atest-exp2 basic-test \
|
||||
test-misc test-fpucw test-fpucw-ieee tst-definitions test-tgmath \
|
||||
test-tgmath-ret bug-nextafter bug-nexttoward bug-tgmath1 \
|
||||
test-tgmath-int test-tgmath2 test-powl tst-CMPLX tst-CMPLX2 test-snan \
|
||||
test-nan-overflow test-nan-payload \
|
||||
test-fenv-tls $(tests-static)
|
||||
tests-static = test-fpucw-static test-fpucw-ieee-static
|
||||
# We do the `long double' tests only if this data type is available and
|
||||
|
||||
@@ -474,6 +474,7 @@ cos 0x1.0000010b239a9p0
|
||||
cos 0x1.00000162a932bp0
|
||||
cos 0x1.000002d452a10p0
|
||||
cos 0x1.000005bc7d86dp0
|
||||
cos 0x1.200145a975ce6p32
|
||||
cos 1
|
||||
cos 2
|
||||
cos 3
|
||||
@@ -1373,6 +1374,7 @@ sin 7
|
||||
sin 8
|
||||
sin 9
|
||||
sin 10
|
||||
sin 0x1.2001469775ce6p32
|
||||
|
||||
sincos 0
|
||||
sincos -0
|
||||
|
||||
@@ -47298,6 +47298,75 @@ cos 0x1.000005bc7d86dp0
|
||||
= cos tonearest ldbl-128ibm 0x1.000005bc7d86dp+0L : 0x8.a513ba9f703d3ffffffcb92354p-4L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.000005bc7d86dp+0L : 0x8.a513ba9f703d3ffffffcb92354p-4L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.000005bc7d86dp+0L : 0x8.a513ba9f703d3ffffffcb92358p-4L : inexact-ok
|
||||
cos 0x1.200145a975ce6p32
|
||||
= cos downward flt-32 0x1.200146p+32f : -0xf.74fbep-4f : inexact-ok
|
||||
= cos tonearest flt-32 0x1.200146p+32f : -0xf.74fbdp-4f : inexact-ok
|
||||
= cos towardzero flt-32 0x1.200146p+32f : -0xf.74fbdp-4f : inexact-ok
|
||||
= cos upward flt-32 0x1.200146p+32f : -0xf.74fbdp-4f : inexact-ok
|
||||
= cos downward dbl-64 0x1.200146p+32 : -0xf.74fbd5498fe5p-4 : inexact-ok
|
||||
= cos tonearest dbl-64 0x1.200146p+32 : -0xf.74fbd5498fe5p-4 : inexact-ok
|
||||
= cos towardzero dbl-64 0x1.200146p+32 : -0xf.74fbd5498fe48p-4 : inexact-ok
|
||||
= cos upward dbl-64 0x1.200146p+32 : -0xf.74fbd5498fe48p-4 : inexact-ok
|
||||
= cos downward ldbl-96-intel 0x1.200146p+32L : -0xf.74fbd5498fe4c0dp-4L : inexact-ok
|
||||
= cos tonearest ldbl-96-intel 0x1.200146p+32L : -0xf.74fbd5498fe4c0cp-4L : inexact-ok
|
||||
= cos towardzero ldbl-96-intel 0x1.200146p+32L : -0xf.74fbd5498fe4c0cp-4L : inexact-ok
|
||||
= cos upward ldbl-96-intel 0x1.200146p+32L : -0xf.74fbd5498fe4c0cp-4L : inexact-ok
|
||||
= cos downward ldbl-96-m68k 0x1.200146p+32L : -0xf.74fbd5498fe4c0dp-4L : inexact-ok
|
||||
= cos tonearest ldbl-96-m68k 0x1.200146p+32L : -0xf.74fbd5498fe4c0cp-4L : inexact-ok
|
||||
= cos towardzero ldbl-96-m68k 0x1.200146p+32L : -0xf.74fbd5498fe4c0cp-4L : inexact-ok
|
||||
= cos upward ldbl-96-m68k 0x1.200146p+32L : -0xf.74fbd5498fe4c0cp-4L : inexact-ok
|
||||
= cos downward ldbl-128 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef59e8p-4L : inexact-ok
|
||||
= cos tonearest ldbl-128 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef59e8p-4L : inexact-ok
|
||||
= cos towardzero ldbl-128 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef59ep-4L : inexact-ok
|
||||
= cos upward ldbl-128 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef59ep-4L : inexact-ok
|
||||
= cos downward ldbl-128ibm 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef5cp-4L : inexact-ok
|
||||
= cos tonearest ldbl-128ibm 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef58p-4L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef58p-4L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.200146p+32L : -0xf.74fbd5498fe4c0c71bd9e4ef58p-4L : inexact-ok
|
||||
= cos downward flt-32 0x1.200144p+32f : 0xf.bc96cp-4f : inexact-ok
|
||||
= cos tonearest flt-32 0x1.200144p+32f : 0xf.bc96dp-4f : inexact-ok
|
||||
= cos towardzero flt-32 0x1.200144p+32f : 0xf.bc96cp-4f : inexact-ok
|
||||
= cos upward flt-32 0x1.200144p+32f : 0xf.bc96dp-4f : inexact-ok
|
||||
= cos downward dbl-64 0x1.200144p+32 : 0xf.bc96ca2c658a8p-4 : inexact-ok
|
||||
= cos tonearest dbl-64 0x1.200144p+32 : 0xf.bc96ca2c658a8p-4 : inexact-ok
|
||||
= cos towardzero dbl-64 0x1.200144p+32 : 0xf.bc96ca2c658a8p-4 : inexact-ok
|
||||
= cos upward dbl-64 0x1.200144p+32 : 0xf.bc96ca2c658bp-4 : inexact-ok
|
||||
= cos downward ldbl-96-intel 0x1.200144p+32L : 0xf.bc96ca2c658abf5p-4L : inexact-ok
|
||||
= cos tonearest ldbl-96-intel 0x1.200144p+32L : 0xf.bc96ca2c658abf6p-4L : inexact-ok
|
||||
= cos towardzero ldbl-96-intel 0x1.200144p+32L : 0xf.bc96ca2c658abf5p-4L : inexact-ok
|
||||
= cos upward ldbl-96-intel 0x1.200144p+32L : 0xf.bc96ca2c658abf6p-4L : inexact-ok
|
||||
= cos downward ldbl-96-m68k 0x1.200144p+32L : 0xf.bc96ca2c658abf5p-4L : inexact-ok
|
||||
= cos tonearest ldbl-96-m68k 0x1.200144p+32L : 0xf.bc96ca2c658abf6p-4L : inexact-ok
|
||||
= cos towardzero ldbl-96-m68k 0x1.200144p+32L : 0xf.bc96ca2c658abf5p-4L : inexact-ok
|
||||
= cos upward ldbl-96-m68k 0x1.200144p+32L : 0xf.bc96ca2c658abf6p-4L : inexact-ok
|
||||
= cos downward ldbl-128 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a8fbp-4L : inexact-ok
|
||||
= cos tonearest ldbl-128 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a8fbp-4L : inexact-ok
|
||||
= cos towardzero ldbl-128 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a8fbp-4L : inexact-ok
|
||||
= cos upward ldbl-128 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a8fb8p-4L : inexact-ok
|
||||
= cos downward ldbl-128ibm 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a8cp-4L : inexact-ok
|
||||
= cos tonearest ldbl-128ibm 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a9p-4L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a8cp-4L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.200144p+32L : 0xf.bc96ca2c658abf5ace7b886a9p-4L : inexact-ok
|
||||
= cos downward dbl-64 0x1.200145a975ce6p+32 : -0x6.568e7ed3dffdp-4 : inexact-ok
|
||||
= cos tonearest dbl-64 0x1.200145a975ce6p+32 : -0x6.568e7ed3dffccp-4 : inexact-ok
|
||||
= cos towardzero dbl-64 0x1.200145a975ce6p+32 : -0x6.568e7ed3dffccp-4 : inexact-ok
|
||||
= cos upward dbl-64 0x1.200145a975ce6p+32 : -0x6.568e7ed3dffccp-4 : inexact-ok
|
||||
= cos downward ldbl-96-intel 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe8p-4L : inexact-ok
|
||||
= cos tonearest ldbl-96-intel 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfep-4L : inexact-ok
|
||||
= cos towardzero ldbl-96-intel 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfep-4L : inexact-ok
|
||||
= cos upward ldbl-96-intel 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfep-4L : inexact-ok
|
||||
= cos downward ldbl-96-m68k 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe8p-4L : inexact-ok
|
||||
= cos tonearest ldbl-96-m68k 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfep-4L : inexact-ok
|
||||
= cos towardzero ldbl-96-m68k 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfep-4L : inexact-ok
|
||||
= cos upward ldbl-96-m68k 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfep-4L : inexact-ok
|
||||
= cos downward ldbl-128 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd726840e8p-4L : inexact-ok
|
||||
= cos tonearest ldbl-128 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd726840e4p-4L : inexact-ok
|
||||
= cos towardzero ldbl-128 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd726840e4p-4L : inexact-ok
|
||||
= cos upward ldbl-128 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd726840e4p-4L : inexact-ok
|
||||
= cos downward ldbl-128ibm 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd726842p-4L : inexact-ok
|
||||
= cos tonearest ldbl-128ibm 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd72684p-4L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd72684p-4L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.200145a975ce6p+32L : -0x6.568e7ed3dffcdfe227fd72684p-4L : inexact-ok
|
||||
cos 1
|
||||
= cos downward flt-32 0x1p+0f : 0x8.a514p-4f : inexact-ok
|
||||
= cos tonearest flt-32 0x1p+0f : 0x8.a514p-4f : inexact-ok
|
||||
@@ -115514,6 +115583,75 @@ sin 10
|
||||
= sin tonearest ldbl-128ibm 0xap+0L : -0x8.b44f7af9a7a92ce7fb22be025p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0xap+0L : -0x8.b44f7af9a7a92ce7fb22be024cp-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0xap+0L : -0x8.b44f7af9a7a92ce7fb22be024cp-4L : inexact-ok
|
||||
sin 0x1.2001469775ce6p32
|
||||
= sin downward flt-32 0x1.200148p+32f : -0x5.595d8p-4f : inexact-ok
|
||||
= sin tonearest flt-32 0x1.200148p+32f : -0x5.595d8p-4f : inexact-ok
|
||||
= sin towardzero flt-32 0x1.200148p+32f : -0x5.595d78p-4f : inexact-ok
|
||||
= sin upward flt-32 0x1.200148p+32f : -0x5.595d78p-4f : inexact-ok
|
||||
= sin downward dbl-64 0x1.200148p+32 : -0x5.595d7e536fe38p-4 : inexact-ok
|
||||
= sin tonearest dbl-64 0x1.200148p+32 : -0x5.595d7e536fe34p-4 : inexact-ok
|
||||
= sin towardzero dbl-64 0x1.200148p+32 : -0x5.595d7e536fe34p-4 : inexact-ok
|
||||
= sin upward dbl-64 0x1.200148p+32 : -0x5.595d7e536fe34p-4 : inexact-ok
|
||||
= sin downward ldbl-96-intel 0x1.200148p+32L : -0x5.595d7e536fe35eep-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-intel 0x1.200148p+32L : -0x5.595d7e536fe35ed8p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-intel 0x1.200148p+32L : -0x5.595d7e536fe35ed8p-4L : inexact-ok
|
||||
= sin upward ldbl-96-intel 0x1.200148p+32L : -0x5.595d7e536fe35ed8p-4L : inexact-ok
|
||||
= sin downward ldbl-96-m68k 0x1.200148p+32L : -0x5.595d7e536fe35eep-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-m68k 0x1.200148p+32L : -0x5.595d7e536fe35ed8p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-m68k 0x1.200148p+32L : -0x5.595d7e536fe35ed8p-4L : inexact-ok
|
||||
= sin upward ldbl-96-m68k 0x1.200148p+32L : -0x5.595d7e536fe35ed8p-4L : inexact-ok
|
||||
= sin downward ldbl-128 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9d944p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9d94p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9d94p-4L : inexact-ok
|
||||
= sin upward ldbl-128 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9d94p-4L : inexact-ok
|
||||
= sin downward ldbl-128ibm 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9dap-4L : inexact-ok
|
||||
= sin tonearest ldbl-128ibm 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9dap-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9d8p-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0x1.200148p+32L : -0x5.595d7e536fe35edbe2ad0df9d8p-4L : inexact-ok
|
||||
= sin downward flt-32 0x1.200146p+32f : 0x4.220ffp-4f : inexact-ok
|
||||
= sin tonearest flt-32 0x1.200146p+32f : 0x4.220ffp-4f : inexact-ok
|
||||
= sin towardzero flt-32 0x1.200146p+32f : 0x4.220ffp-4f : inexact-ok
|
||||
= sin upward flt-32 0x1.200146p+32f : 0x4.220ff8p-4f : inexact-ok
|
||||
= sin downward dbl-64 0x1.200146p+32 : 0x4.220ff25f5cfp-4 : inexact-ok
|
||||
= sin tonearest dbl-64 0x1.200146p+32 : 0x4.220ff25f5cf04p-4 : inexact-ok
|
||||
= sin towardzero dbl-64 0x1.200146p+32 : 0x4.220ff25f5cfp-4 : inexact-ok
|
||||
= sin upward dbl-64 0x1.200146p+32 : 0x4.220ff25f5cf04p-4 : inexact-ok
|
||||
= sin downward ldbl-96-intel 0x1.200146p+32L : 0x4.220ff25f5cf02a4p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-intel 0x1.200146p+32L : 0x4.220ff25f5cf02a48p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-intel 0x1.200146p+32L : 0x4.220ff25f5cf02a4p-4L : inexact-ok
|
||||
= sin upward ldbl-96-intel 0x1.200146p+32L : 0x4.220ff25f5cf02a48p-4L : inexact-ok
|
||||
= sin downward ldbl-96-m68k 0x1.200146p+32L : 0x4.220ff25f5cf02a4p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-m68k 0x1.200146p+32L : 0x4.220ff25f5cf02a48p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-m68k 0x1.200146p+32L : 0x4.220ff25f5cf02a4p-4L : inexact-ok
|
||||
= sin upward ldbl-96-m68k 0x1.200146p+32L : 0x4.220ff25f5cf02a48p-4L : inexact-ok
|
||||
= sin downward ldbl-128 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679ccp-4L : inexact-ok
|
||||
= sin tonearest ldbl-128 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679ccp-4L : inexact-ok
|
||||
= sin towardzero ldbl-128 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679ccp-4L : inexact-ok
|
||||
= sin upward ldbl-128 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679cc4p-4L : inexact-ok
|
||||
= sin downward ldbl-128ibm 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679cp-4L : inexact-ok
|
||||
= sin tonearest ldbl-128ibm 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679cp-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679cp-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0x1.200146p+32L : 0x4.220ff25f5cf02a464dbb3a679ep-4L : inexact-ok
|
||||
= sin downward dbl-64 0x1.2001469775ce6p+32 : -0x6.444fda50019fcp-4 : inexact-ok
|
||||
= sin tonearest dbl-64 0x1.2001469775ce6p+32 : -0x6.444fda50019f8p-4 : inexact-ok
|
||||
= sin towardzero dbl-64 0x1.2001469775ce6p+32 : -0x6.444fda50019f8p-4 : inexact-ok
|
||||
= sin upward dbl-64 0x1.2001469775ce6p+32 : -0x6.444fda50019f8p-4 : inexact-ok
|
||||
= sin downward ldbl-96-intel 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f6p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-intel 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f58p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-intel 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f58p-4L : inexact-ok
|
||||
= sin upward ldbl-96-intel 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f58p-4L : inexact-ok
|
||||
= sin downward ldbl-96-m68k 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f6p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-m68k 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f58p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-m68k 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f58p-4L : inexact-ok
|
||||
= sin upward ldbl-96-m68k 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f58p-4L : inexact-ok
|
||||
= sin downward ldbl-128 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca70604p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca706p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca706p-4L : inexact-ok
|
||||
= sin upward ldbl-128 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca706p-4L : inexact-ok
|
||||
= sin downward ldbl-128ibm 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca708p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128ibm 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca706p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca706p-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0x1.2001469775ce6p+32L : -0x6.444fda50019f9f5ba3779ca706p-4L : inexact-ok
|
||||
sincos 0
|
||||
= sincos downward flt-32 0x0p+0f : 0x0p+0f 0x1p+0f : inexact-ok
|
||||
= sincos tonearest flt-32 0x0p+0f : 0x0p+0f 0x1p+0f : inexact-ok
|
||||
|
||||
@@ -150,6 +150,7 @@ __END_NAMESPACE_C99
|
||||
|
||||
_Mdouble_BEGIN_NAMESPACE
|
||||
/* Return X to the Y power. */
|
||||
__attribute_noplt__
|
||||
__MATHCALL (pow,, (_Mdouble_ __x, _Mdouble_ __y));
|
||||
|
||||
/* Return the square root of X. */
|
||||
|
||||
@@ -6000,6 +6000,15 @@ static const struct test_f_f_data ceil_test_data[] =
|
||||
TEST_f_f (ceil, -72057594037927936.75L, -72057594037927936.0L),
|
||||
TEST_f_f (ceil, -72057594037927937.5L, -72057594037927937.0L),
|
||||
|
||||
/* Check cases where first double is a exact integer higher than 2^52 and
|
||||
the precision is determined by second long double for IBM long double. */
|
||||
TEST_f_f (ceil, 34503599627370498.515625L, 34503599627370499.0L),
|
||||
TEST_f_f (ceil, -34503599627370498.515625L, -34503599627370498.0L),
|
||||
# if LDBL_MANT_DIG >= 106
|
||||
TEST_f_f (ceil, 1192568192774434123539907640624.484375L, 1192568192774434123539907640625.0L),
|
||||
TEST_f_f (ceil, -1192568192774434123539907640624.484375L, -1192568192774434123539907640624.0L),
|
||||
# endif
|
||||
|
||||
TEST_f_f (ceil, 10141204801825835211973625643007.5L, 10141204801825835211973625643008.0L),
|
||||
TEST_f_f (ceil, 10141204801825835211973625643008.25L, 10141204801825835211973625643009.0L),
|
||||
TEST_f_f (ceil, 10141204801825835211973625643008.5L, 10141204801825835211973625643009.0L),
|
||||
@@ -8714,6 +8723,15 @@ static const struct test_f_f1_data frexp_test_data[] =
|
||||
|
||||
TEST_fI_f1 (frexp, 12.8L, 0.8L, 4, NO_INEXACT_EXCEPTION),
|
||||
TEST_fI_f1 (frexp, -27.34L, -0.854375L, 5, NO_INEXACT_EXCEPTION),
|
||||
|
||||
#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
|
||||
TEST_fI_f1 (frexp, 1.0L-0x1p-106L, 1.0L-0x1p-106L, 0, NO_INEXACT_EXCEPTION),
|
||||
TEST_fI_f1 (frexp, 1.0L, 0.5L, 1, NO_INEXACT_EXCEPTION),
|
||||
TEST_fI_f1 (frexp, 1.0L+0x1p-105L, 0.5L+0x1p-106L, 1, NO_INEXACT_EXCEPTION),
|
||||
TEST_fI_f1 (frexp, -1.0L+0x1p-106L, -1.0L+0x1p-106L, 0, NO_INEXACT_EXCEPTION),
|
||||
TEST_fI_f1 (frexp, -1.0L, -0.5L, 1, NO_INEXACT_EXCEPTION),
|
||||
TEST_fI_f1 (frexp, -1.0L-0x1p-105L, -0.5L-0x1p-106L, 1, NO_INEXACT_EXCEPTION),
|
||||
#endif
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -10494,6 +10512,20 @@ static const struct test_f_f_data nearbyint_test_data[] =
|
||||
TEST_f_f (nearbyint, -281474976710656.75, -281474976710657.0, NO_INEXACT_EXCEPTION),
|
||||
TEST_f_f (nearbyint, -562949953421312.75, -562949953421313.0, NO_INEXACT_EXCEPTION),
|
||||
TEST_f_f (nearbyint, -1125899906842624.75, -1125899906842625.0, NO_INEXACT_EXCEPTION),
|
||||
#endif
|
||||
#ifdef TEST_LDOUBLE
|
||||
/* Check cases where first double is a exact integer higher than 2^52 and
|
||||
the precision is determined by second long double for IBM long double. */
|
||||
TEST_f_f (nearbyint, 34503599627370498.515625L, 34503599627370499.0L),
|
||||
TEST_f_f (nearbyint, -34503599627370498.515625L, -34503599627370499.0L),
|
||||
# if LDBL_MANT_DIG >= 106
|
||||
TEST_f_f (nearbyint, 1024.5000000000001L, 1025.0L, NO_INEXACT_EXCEPTION),
|
||||
TEST_f_f (nearbyint, 1025.5000000000001L, 1026.0L, NO_INEXACT_EXCEPTION),
|
||||
TEST_f_f (nearbyint, -1024.5000000000001L, -1025.0L, NO_INEXACT_EXCEPTION),
|
||||
TEST_f_f (nearbyint, -1025.5000000000001L, -1026.0L, NO_INEXACT_EXCEPTION),
|
||||
TEST_f_f (nearbyint, 1192568192774434123539907640624.484375L, 1192568192774434123539907640624.0L),
|
||||
TEST_f_f (nearbyint, -1192568192774434123539907640624.484375L, -1192568192774434123539907640624.0L),
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -10528,6 +10560,14 @@ static const struct test_ff_f_data nextafter_test_data[] =
|
||||
// XXX Enable once gcc is fixed.
|
||||
//TEST_ff_f (nextafter, 0x0.00000040000000000000p-16385L, -0.1L, 0x0.0000003ffffffff00000p-16385L),
|
||||
#endif
|
||||
#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 106
|
||||
TEST_ff_f (nextafter, 1.0L, -10.0L, 1.0L-0x1p-106L, NO_EXCEPTION),
|
||||
TEST_ff_f (nextafter, 1.0L, 10.0L, 1.0L+0x1p-105L, NO_EXCEPTION),
|
||||
TEST_ff_f (nextafter, 1.0L-0x1p-106L, 10.0L, 1.0L, NO_EXCEPTION),
|
||||
TEST_ff_f (nextafter, -1.0L, -10.0L, -1.0L-0x1p-105L, NO_EXCEPTION),
|
||||
TEST_ff_f (nextafter, -1.0L, 10.0L, -1.0L+0x1p-106L, NO_EXCEPTION),
|
||||
TEST_ff_f (nextafter, -1.0L+0x1p-106L, -10.0L, -1.0L, NO_EXCEPTION),
|
||||
#endif
|
||||
|
||||
/* XXX We need the hexadecimal FP number representation here for further
|
||||
tests. */
|
||||
@@ -11299,6 +11339,10 @@ static const struct test_f_f_data rint_test_data[] =
|
||||
TEST_f_f (rint, 4503599627370497.5L, 4503599627370498.0L, INEXACT_EXCEPTION),
|
||||
|
||||
# if LDBL_MANT_DIG > 100
|
||||
TEST_f_f (rint, 1024.5000000000001L, 1025.0L, INEXACT_EXCEPTION),
|
||||
TEST_f_f (rint, 1025.5000000000001L, 1026.0L, INEXACT_EXCEPTION),
|
||||
TEST_f_f (rint, -1024.5000000000001L, -1025.0L, INEXACT_EXCEPTION),
|
||||
TEST_f_f (rint, -1025.5000000000001L, -1026.0L, INEXACT_EXCEPTION),
|
||||
TEST_f_f (rint, 4503599627370494.5000000000001L, 4503599627370495.0L, INEXACT_EXCEPTION),
|
||||
TEST_f_f (rint, 4503599627370495.5000000000001L, 4503599627370496.0L, INEXACT_EXCEPTION),
|
||||
TEST_f_f (rint, 4503599627370496.5000000000001L, 4503599627370497.0L, INEXACT_EXCEPTION),
|
||||
@@ -11784,6 +11828,15 @@ static const struct test_f_f_data round_test_data[] =
|
||||
TEST_f_f (round, -72057594037927936.75L, -72057594037927937.0L),
|
||||
TEST_f_f (round, -72057594037927937.5L, -72057594037927938.0L),
|
||||
|
||||
/* Check cases where first double is a exact integer higher than 2^52 and
|
||||
the precision is determined by second long double for IBM long double. */
|
||||
TEST_f_f (round, 34503599627370498.515625L, 34503599627370499.0L),
|
||||
TEST_f_f (round, -34503599627370498.515625L, -34503599627370499.0L),
|
||||
# if LDBL_MANT_DIG >= 106
|
||||
TEST_f_f (round, 1192568192774434123539907640624.484375L, 1192568192774434123539907640624.0L),
|
||||
TEST_f_f (round, -1192568192774434123539907640624.484375L, -1192568192774434123539907640624.0L),
|
||||
# endif
|
||||
|
||||
TEST_f_f (round, 10141204801825835211973625643007.5L, 10141204801825835211973625643008.0L),
|
||||
TEST_f_f (round, 10141204801825835211973625643008.25L, 10141204801825835211973625643008.0L),
|
||||
TEST_f_f (round, 10141204801825835211973625643008.5L, 10141204801825835211973625643009.0L),
|
||||
|
||||
+1
-8
@@ -28,14 +28,7 @@
|
||||
double
|
||||
__nan (const char *tagp)
|
||||
{
|
||||
if (tagp[0] != '\0')
|
||||
{
|
||||
char buf[6 + strlen (tagp)];
|
||||
sprintf (buf, "NAN(%s)", tagp);
|
||||
return strtod (buf, NULL);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
return __strtod_nan (tagp, NULL, 0);
|
||||
}
|
||||
weak_alias (__nan, nan)
|
||||
#ifdef NO_LONG_DOUBLE
|
||||
|
||||
+1
-8
@@ -28,13 +28,6 @@
|
||||
float
|
||||
__nanf (const char *tagp)
|
||||
{
|
||||
if (tagp[0] != '\0')
|
||||
{
|
||||
char buf[6 + strlen (tagp)];
|
||||
sprintf (buf, "NAN(%s)", tagp);
|
||||
return strtof (buf, NULL);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
return __strtof_nan (tagp, NULL, 0);
|
||||
}
|
||||
weak_alias (__nanf, nanf)
|
||||
|
||||
+1
-8
@@ -28,13 +28,6 @@
|
||||
long double
|
||||
__nanl (const char *tagp)
|
||||
{
|
||||
if (tagp[0] != '\0')
|
||||
{
|
||||
char buf[6 + strlen (tagp)];
|
||||
sprintf (buf, "NAN(%s)", tagp);
|
||||
return strtold (buf, NULL);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
return __strtold_nan (tagp, NULL, 0);
|
||||
}
|
||||
weak_alias (__nanl, nanl)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Test nan functions stack overflow (bug 16962).
|
||||
Copyright (C) 2015 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#define STACK_LIM 1048576
|
||||
#define STRING_SIZE (2 * STACK_LIM)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
struct rlimit lim;
|
||||
getrlimit (RLIMIT_STACK, &lim);
|
||||
lim.rlim_cur = STACK_LIM;
|
||||
setrlimit (RLIMIT_STACK, &lim);
|
||||
char *nanstr = malloc (STRING_SIZE);
|
||||
if (nanstr == NULL)
|
||||
{
|
||||
puts ("malloc failed, cannot test");
|
||||
return 77;
|
||||
}
|
||||
memset (nanstr, '0', STRING_SIZE - 1);
|
||||
nanstr[STRING_SIZE - 1] = 0;
|
||||
#define NAN_TEST(TYPE, FUNC) \
|
||||
do \
|
||||
{ \
|
||||
char *volatile p = nanstr; \
|
||||
volatile TYPE v = FUNC (p); \
|
||||
if (isnan (v)) \
|
||||
puts ("PASS: " #FUNC); \
|
||||
else \
|
||||
{ \
|
||||
puts ("FAIL: " #FUNC); \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
NAN_TEST (float, nanf);
|
||||
NAN_TEST (double, nan);
|
||||
#ifndef NO_LONG_DOUBLE
|
||||
NAN_TEST (long double, nanl);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -0,0 +1,122 @@
|
||||
/* Test nan functions payload handling (bug 16961).
|
||||
Copyright (C) 2015 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 <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Avoid built-in functions. */
|
||||
#define WRAP_NAN(FUNC, STR) \
|
||||
({ const char *volatile wns = (STR); FUNC (wns); })
|
||||
#define WRAP_STRTO(FUNC, STR) \
|
||||
({ const char *volatile wss = (STR); FUNC (wss, NULL); })
|
||||
|
||||
#define CHECK_IS_NAN(TYPE, A) \
|
||||
do \
|
||||
{ \
|
||||
if (isnan (A)) \
|
||||
puts ("PASS: " #TYPE " " #A); \
|
||||
else \
|
||||
{ \
|
||||
puts ("FAIL: " #TYPE " " #A); \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define CHECK_SAME_NAN(TYPE, A, B) \
|
||||
do \
|
||||
{ \
|
||||
if (memcmp (&(A), &(B), sizeof (A)) == 0) \
|
||||
puts ("PASS: " #TYPE " " #A " = " #B); \
|
||||
else \
|
||||
{ \
|
||||
puts ("FAIL: " #TYPE " " #A " = " #B); \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define CHECK_DIFF_NAN(TYPE, A, B) \
|
||||
do \
|
||||
{ \
|
||||
if (memcmp (&(A), &(B), sizeof (A)) != 0) \
|
||||
puts ("PASS: " #TYPE " " #A " != " #B); \
|
||||
else \
|
||||
{ \
|
||||
puts ("FAIL: " #TYPE " " #A " != " #B); \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Cannot test payloads by memcmp for formats where NaNs have padding
|
||||
bits. */
|
||||
#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
|
||||
|
||||
#define RUN_TESTS(TYPE, SFUNC, FUNC, MANT_DIG) \
|
||||
do \
|
||||
{ \
|
||||
TYPE n123 = WRAP_NAN (FUNC, "123"); \
|
||||
CHECK_IS_NAN (TYPE, n123); \
|
||||
TYPE s123 = WRAP_STRTO (SFUNC, "NAN(123)"); \
|
||||
CHECK_IS_NAN (TYPE, s123); \
|
||||
TYPE n456 = WRAP_NAN (FUNC, "456"); \
|
||||
CHECK_IS_NAN (TYPE, n456); \
|
||||
TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
|
||||
CHECK_IS_NAN (TYPE, s456); \
|
||||
TYPE n123x = WRAP_NAN (FUNC, "123)"); \
|
||||
CHECK_IS_NAN (TYPE, n123x); \
|
||||
TYPE nemp = WRAP_NAN (FUNC, ""); \
|
||||
CHECK_IS_NAN (TYPE, nemp); \
|
||||
TYPE semp = WRAP_STRTO (SFUNC, "NAN()"); \
|
||||
CHECK_IS_NAN (TYPE, semp); \
|
||||
TYPE sx = WRAP_STRTO (SFUNC, "NAN"); \
|
||||
CHECK_IS_NAN (TYPE, sx); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, n123, s123); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, n456, s456); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, nemp, semp); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, n123x, sx); \
|
||||
CHECK_DIFF_NAN (TYPE, n123, n456); \
|
||||
CHECK_DIFF_NAN (TYPE, n123, nemp); \
|
||||
CHECK_DIFF_NAN (TYPE, n123, n123x); \
|
||||
CHECK_DIFF_NAN (TYPE, n456, nemp); \
|
||||
CHECK_DIFF_NAN (TYPE, n456, n123x); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
RUN_TESTS (float, strtof, nanf, FLT_MANT_DIG);
|
||||
RUN_TESTS (double, strtod, nan, DBL_MANT_DIG);
|
||||
#ifndef NO_LONG_DOUBLE
|
||||
RUN_TESTS (long double, strtold, nanl, LDBL_MANT_DIG);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
+2
-1
@@ -76,7 +76,8 @@ install-lib := libg.a
|
||||
gpl2lgpl := error.c error.h
|
||||
|
||||
tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
|
||||
tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1
|
||||
tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1 \
|
||||
bug18240
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests: $(objpfx)tst-error1-mem
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Test integer wraparound in hcreate.
|
||||
Copyright (C) 2016-2017 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 <limits.h>
|
||||
#include <search.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static void
|
||||
test_size (size_t size)
|
||||
{
|
||||
int res = hcreate (size);
|
||||
if (res == 0)
|
||||
{
|
||||
if (errno == ENOMEM)
|
||||
return;
|
||||
printf ("error: hcreate (%zu): %m\n", size);
|
||||
exit (1);
|
||||
}
|
||||
char *keys[100];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
if (asprintf (keys + i, "%d", i) < 0)
|
||||
{
|
||||
printf ("error: asprintf: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
ENTRY e = { keys[i], (char *) "value" };
|
||||
if (hsearch (e, ENTER) == NULL)
|
||||
{
|
||||
printf ("error: hsearch (\"%s\"): %m\n", keys[i]);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
hdestroy ();
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
free (keys[i]);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Limit the size of the process, so that memory allocation will
|
||||
fail without impacting the entire system. */
|
||||
{
|
||||
struct rlimit limit;
|
||||
if (getrlimit (RLIMIT_AS, &limit) != 0)
|
||||
{
|
||||
printf ("getrlimit (RLIMIT_AS) failed: %m\n");
|
||||
return 1;
|
||||
}
|
||||
long target = 100 * 1024 * 1024;
|
||||
if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
|
||||
{
|
||||
limit.rlim_cur = target;
|
||||
if (setrlimit (RLIMIT_AS, &limit) != 0)
|
||||
{
|
||||
printf ("setrlimit (RLIMIT_AS) failed: %m\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_size (500);
|
||||
test_size (-1);
|
||||
test_size (-3);
|
||||
test_size (INT_MAX - 2);
|
||||
test_size (INT_MAX - 1);
|
||||
test_size (INT_MAX);
|
||||
test_size (((unsigned) INT_MAX) + 1);
|
||||
test_size (UINT_MAX - 2);
|
||||
test_size (UINT_MAX - 1);
|
||||
test_size (UINT_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
+18
-12
@@ -19,7 +19,7 @@
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <search.h>
|
||||
|
||||
/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
|
||||
@@ -46,15 +46,12 @@ static int
|
||||
isprime (unsigned int number)
|
||||
{
|
||||
/* no even number will be passed */
|
||||
unsigned int div = 3;
|
||||
|
||||
while (div * div < number && number % div != 0)
|
||||
div += 2;
|
||||
|
||||
return number % div != 0;
|
||||
for (unsigned int div = 3; div <= number / div; div += 2)
|
||||
if (number % div == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Before using the hash table we must allocate memory for it.
|
||||
Test for an existing table are done. We allocate one element
|
||||
more as the found prime number says. This is done for more effective
|
||||
@@ -81,10 +78,19 @@ hcreate_r (nel, htab)
|
||||
use will not work. */
|
||||
if (nel < 3)
|
||||
nel = 3;
|
||||
/* Change nel to the first prime number not smaller as nel. */
|
||||
nel |= 1; /* make odd */
|
||||
while (!isprime (nel))
|
||||
nel += 2;
|
||||
|
||||
/* Change nel to the first prime number in the range [nel, UINT_MAX - 2],
|
||||
The '- 2' means 'nel += 2' cannot overflow. */
|
||||
for (nel |= 1; ; nel += 2)
|
||||
{
|
||||
if (UINT_MAX - 2 < nel)
|
||||
{
|
||||
__set_errno (ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
if (isprime (nel))
|
||||
break;
|
||||
}
|
||||
|
||||
htab->size = nel;
|
||||
htab->filled = 0;
|
||||
|
||||
@@ -33,4 +33,6 @@ __mktemp (template)
|
||||
}
|
||||
weak_alias (__mktemp, mktemp)
|
||||
|
||||
#if 0 /* Google-local: b/6115789 */
|
||||
link_warning (mktemp, "the use of `mktemp' is dangerous, better use `mkstemp'")
|
||||
#endif
|
||||
|
||||
@@ -232,6 +232,15 @@
|
||||
# define __attribute_pure__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* GCC 4.9 onwards supports function attribute "noplt". Calls to functions
|
||||
declared with this attribute avoid the PLT and call them indirectly via
|
||||
a GOT entry. */
|
||||
#if __GNUC_PREREQ (4,9) && defined(__GOOGLE_GLIBC_NOPLT)
|
||||
# define __attribute_noplt__ __attribute__ ((noplt))
|
||||
#else
|
||||
# define __attribute_noplt__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* This declaration tells the compiler that the value is constant. */
|
||||
#if __GNUC_PREREQ (2,5)
|
||||
# define __attribute_const__ __attribute__ ((__const__))
|
||||
@@ -303,6 +312,13 @@
|
||||
# define __wur /* Ignore */
|
||||
#endif
|
||||
|
||||
/* Google specific: Disable __warn_unused_result__ attribute even if
|
||||
_FORTIFY_SOURCE is specified. Not all google3 code compiles when it's set */
|
||||
#ifdef _GOOGLE_FORTIFY_SOURCE_NO_WARN_UNUSED_RESULT
|
||||
# undef __wur
|
||||
# define __wur /* Ignore */
|
||||
#endif
|
||||
|
||||
/* Forces a function to be always inlined. */
|
||||
#if __GNUC_PREREQ (3,2)
|
||||
# define __always_inline __inline __attribute__ ((__always_inline__))
|
||||
|
||||
+5
-2
@@ -34,9 +34,12 @@ databases = proto service hosts network grp pwd rpc ethers \
|
||||
spwd netgrp alias publickey
|
||||
|
||||
# Specify rules for the nss_* modules.
|
||||
services := nis nisplus compat
|
||||
|
||||
extra-libs = libnsl $(services:%=libnss_%)
|
||||
# Google-local: Disable NIS.
|
||||
# services := nis nisplus compat
|
||||
#
|
||||
# extra-libs = libnsl $(services:%=libnss_%)
|
||||
|
||||
# These libraries will be built in the `others' pass rather than
|
||||
# the `lib' pass, because they depend on libc.so being built already.
|
||||
extra-libs-others = $(extra-libs)
|
||||
|
||||
+31
-9
@@ -137,6 +137,10 @@ libpthread-static-only-routines = pthread_atfork
|
||||
|
||||
CFLAGS-pthread_atfork.c = -DNOT_IN_libc
|
||||
|
||||
# Google-local (b/14616463): Turn off function sections in events.c to
|
||||
# avoid folding that causes a bad debugging experience.
|
||||
CFLAGS-events.c = -fno-function-sections
|
||||
|
||||
# Since cancellation handling is in large parts handled using exceptions
|
||||
# we have to compile some files with exception handling enabled, some
|
||||
# even with asynchronous unwind tables.
|
||||
@@ -170,8 +174,10 @@ CFLAGS-forward.c = -fexceptions
|
||||
# block and therefore temporarily enable asynchronous cancellation.
|
||||
# Those must be compiled asynchronous unwind tables.
|
||||
CFLAGS-pthread_testcancel.c = -fexceptions
|
||||
CFLAGS-pthread_join.c = -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-pthread_timedjoin.c = -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-pthread_join.c = -fexceptions -fasynchronous-unwind-tables \
|
||||
-fno-omit-frame-pointer
|
||||
CFLAGS-pthread_timedjoin.c = -fexceptions -fasynchronous-unwind-tables \
|
||||
-fno-omit-frame-pointer
|
||||
CFLAGS-pthread_once.c = $(uses-callbacks) -fexceptions \
|
||||
-fasynchronous-unwind-tables
|
||||
CFLAGS-pthread_cond_wait.c = -fexceptions -fasynchronous-unwind-tables
|
||||
@@ -222,13 +228,13 @@ tests = tst-typesizes \
|
||||
tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 tst-rwlock9 \
|
||||
tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 tst-rwlock14 \
|
||||
tst-once1 tst-once2 tst-once3 tst-once4 \
|
||||
tst-key1 tst-key2 tst-key3 tst-key4 \
|
||||
tst-key1 tst-key2 tst-key3 tst-key4 tst-key5 \
|
||||
tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
|
||||
tst-sem8 tst-sem9 tst-sem10 tst-sem11 tst-sem12 tst-sem13 tst-sem14 \
|
||||
tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
|
||||
tst-align tst-align2 tst-align3 \
|
||||
tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
|
||||
tst-basic7 \
|
||||
tst-basic7 tst-basic8 \
|
||||
tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
|
||||
tst-raise1 \
|
||||
tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \
|
||||
@@ -293,8 +299,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
|
||||
tst-oncex3 tst-oncex4
|
||||
endif
|
||||
ifeq ($(build-shared),yes)
|
||||
tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-_res1 tst-fini1 \
|
||||
tst-stackguard1
|
||||
tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-tls7 tst-_res1 tst-fini1 \
|
||||
tst-stackguard1 tst-tls77
|
||||
tests-nolibpthread += tst-fini1
|
||||
ifeq ($(have-z-execstack),yes)
|
||||
tests += tst-execstack
|
||||
@@ -304,7 +310,8 @@ endif
|
||||
modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
|
||||
tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
|
||||
tst-tls5modd tst-tls5mode tst-tls5modf \
|
||||
tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
|
||||
tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \
|
||||
tst-tls7mod tst-tls77mod
|
||||
extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
|
||||
test-extras += $(modules-names) tst-cleanup4aux
|
||||
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
||||
@@ -318,6 +325,8 @@ tst-tls5modc.so-no-z-defs = yes
|
||||
tst-tls5modd.so-no-z-defs = yes
|
||||
tst-tls5mode.so-no-z-defs = yes
|
||||
tst-tls5modf.so-no-z-defs = yes
|
||||
tst-tls7mod.so-no-z-defs = yes
|
||||
tst-tls77mod.so-no-z-defs = yes
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
# Build all the modules even when not actually running test programs.
|
||||
@@ -391,8 +400,8 @@ $(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \
|
||||
echo ' Use the shared library, but some functions are only in';\
|
||||
echo ' the static library, so try that secondarily. */';\
|
||||
cat $<; \
|
||||
echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \
|
||||
'$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\
|
||||
echo 'GROUP ( libpthread.so$(libpthread.so-version)' \
|
||||
'$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\
|
||||
')' \
|
||||
) > $@.new
|
||||
mv -f $@.new $@
|
||||
@@ -480,6 +489,12 @@ $(objpfx)tst-tls5: $(objpfx)tst-tls5mod.so $(shared-thread-library)
|
||||
LDFLAGS-tst-tls5 = $(no-as-needed)
|
||||
LDFLAGS-tst-tls5mod.so = -Wl,-soname,tst-tls5mod.so
|
||||
|
||||
# ensure free(malloc()) isn't optimized out
|
||||
CFLAGS-tst-tls7.c = -fno-builtin-malloc -fno-builtin-free
|
||||
$(objpfx)tst-tls7: $(libdl) $(shared-thread-library)
|
||||
$(objpfx)tst-tls7.out: $(objpfx)tst-tls7mod.so
|
||||
$(objpfx)tst-tls7mod.so: $(shared-thread-library)
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests: $(objpfx)tst-tls6.out
|
||||
@@ -492,6 +507,11 @@ $(objpfx)tst-tls6.out: tst-tls6.sh $(objpfx)tst-tls5 \
|
||||
'$(test-wrapper-env)'
|
||||
endif
|
||||
|
||||
$(objpfx)tst-tls77: $(libdl) $(shared-thread-library)
|
||||
LDFLAGS-tst-tls77 = -rdynamic
|
||||
$(objpfx)tst-tls77.out: $(objpfx)tst-tls77mod.so
|
||||
$(objpfx)tst-tls77mod.so: $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-dlsym1: $(libdl) $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-fini1: $(shared-thread-library) $(objpfx)tst-fini1mod.so
|
||||
@@ -589,6 +609,8 @@ $(objpfx)tst-execstack: $(libdl)
|
||||
$(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so
|
||||
LDFLAGS-tst-execstack = -Wl,-z,noexecstack
|
||||
|
||||
$(objpfx)tst-key5: $(librt)
|
||||
|
||||
$(objpfx)tst-fini1mod.so: $(shared-thread-library)
|
||||
|
||||
tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child"
|
||||
|
||||
@@ -258,6 +258,7 @@ libpthread {
|
||||
}
|
||||
|
||||
GLIBC_PRIVATE {
|
||||
__google_pthread_signal_safe_key_create;
|
||||
__pthread_initialize_minimal;
|
||||
__pthread_clock_gettime; __pthread_clock_settime;
|
||||
__pthread_unwind; __pthread_get_minstack;
|
||||
|
||||
+25
-9
@@ -242,11 +242,7 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
|
||||
/* Clear the DTV. */
|
||||
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
if (! dtv[1 + cnt].pointer.is_static
|
||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
free (dtv[1 + cnt].pointer.val);
|
||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||
_dl_clear_dtv (dtv);
|
||||
|
||||
/* Re-initialize the TLS. */
|
||||
_dl_allocate_tls_init (TLS_TPADJ (result));
|
||||
@@ -660,6 +656,21 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
|
||||
return errno;
|
||||
}
|
||||
/* The call to madvise(...MADV_DONTNEED) below will fail if pages
|
||||
are locked. Unlock the guard memory to make sure the
|
||||
madvise function succeeds (memory can be locked if
|
||||
process called mlockall(MCL_FUTURE) at some point in the
|
||||
past).*/
|
||||
munlock (guard, guardsize);
|
||||
/* We've marked this guard region unwritable, but it's
|
||||
possible it already became resident, the most common case
|
||||
being transparent hugepages; if stack + guard (+ adjacent
|
||||
mmap regions) were more than 2MB, the kernel might have
|
||||
filled in a full hugepage when we touched the thread
|
||||
descriptor above. This can waste a lot of memory; mark
|
||||
the guard unused. This shouldn't fail, but if it does,
|
||||
we can't really do anything about it so ignore it. */
|
||||
madvise (guard, guardsize, MADV_DONTNEED);
|
||||
|
||||
pd->guardsize = guardsize;
|
||||
}
|
||||
@@ -1177,13 +1188,18 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
# endif
|
||||
|
||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
|
||||
/* Initialize the memory. */
|
||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
|
||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
/* Pairs against the read barrier in tls_get_attr_tail, guaranteeing
|
||||
any thread waiting for an update to pointer.val sees the
|
||||
initimage write. */
|
||||
atomic_write_barrier ();
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -53,16 +53,10 @@ __pthread_getspecific (key)
|
||||
data = &level2[idx2nd];
|
||||
}
|
||||
|
||||
void *result = data->data;
|
||||
if (result != NULL)
|
||||
{
|
||||
uintptr_t seq = data->seq;
|
||||
if (__builtin_expect (data->seq != __pthread_keys[key].seq, 0))
|
||||
return NULL;
|
||||
|
||||
if (__builtin_expect (seq != __pthread_keys[key].seq, 0))
|
||||
result = data->data = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
return data->data;
|
||||
}
|
||||
strong_alias (__pthread_getspecific, pthread_getspecific)
|
||||
hidden_def (__pthread_getspecific)
|
||||
|
||||
+37
-16
@@ -18,33 +18,54 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include "pthreadP.h"
|
||||
#include <assert.h>
|
||||
#include <atomic.h>
|
||||
|
||||
static int
|
||||
claim_key (pthread_key_t *key, void (*destr) (void *), size_t cnt)
|
||||
{
|
||||
uintptr_t seq = __pthread_keys[cnt].seq;
|
||||
if (KEY_UNUSED (seq) && KEY_USABLE (seq)
|
||||
/* We found an unused slot. Try to allocate it. */
|
||||
&& ! atomic_compare_and_exchange_bool_acq (&__pthread_keys[cnt].seq,
|
||||
seq + 1, seq))
|
||||
{
|
||||
/* Remember the destructor. */
|
||||
__pthread_keys[cnt].destr = destr;
|
||||
|
||||
/* Return the key to the caller. */
|
||||
*key = cnt;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
__pthread_key_create (key, destr)
|
||||
pthread_key_t *key;
|
||||
void (*destr) (void *);
|
||||
{
|
||||
/* Find a slot in __pthread_kyes which is unused. */
|
||||
for (size_t cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt)
|
||||
/* Find a slot in __pthread_keys which is unused. */
|
||||
for (size_t cnt = PTHREAD_SIGNAL_SAFE_KEYS_MAX; cnt < PTHREAD_KEYS_MAX; ++cnt)
|
||||
{
|
||||
uintptr_t seq = __pthread_keys[cnt].seq;
|
||||
if (claim_key (key, destr, cnt) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (KEY_UNUSED (seq) && KEY_USABLE (seq)
|
||||
/* We found an unused slot. Try to allocate it. */
|
||||
&& ! atomic_compare_and_exchange_bool_acq (&__pthread_keys[cnt].seq,
|
||||
seq + 1, seq))
|
||||
{
|
||||
/* Remember the destructor. */
|
||||
__pthread_keys[cnt].destr = destr;
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
/* Return the key to the caller. */
|
||||
*key = cnt;
|
||||
|
||||
/* The call succeeded. */
|
||||
return 0;
|
||||
}
|
||||
int __google_pthread_signal_safe_key_create (
|
||||
pthread_key_t *key, void (*destr) (void *))
|
||||
{
|
||||
/* Our implementation makes signal safe keys easy: they just have to
|
||||
reside in the first (inline) block. */
|
||||
assert (PTHREAD_SIGNAL_SAFE_KEYS_MAX <= PTHREAD_KEY_1STLEVEL_SIZE);
|
||||
/* Find a slot in __pthread_keys which is unused. */
|
||||
for (size_t cnt = 0; cnt < PTHREAD_SIGNAL_SAFE_KEYS_MAX; ++cnt)
|
||||
{
|
||||
if (claim_key (key, destr, cnt) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EAGAIN;
|
||||
|
||||
@@ -1123,6 +1123,20 @@ extern int pthread_key_create (pthread_key_t *__key,
|
||||
void (*__destr_function) (void *))
|
||||
__THROW __nonnull ((1));
|
||||
|
||||
/* Exactly as pthread_key_create, but returns an async-signal-safe key:
|
||||
getspecific, setspecific, and key_delete are async-signal-safe when
|
||||
used with the returned key. The number of signal_safe keys is *extremely*
|
||||
limited (PTHREAD_SIGNAL_SAFE_KEY_MAX); you are highly recommended to use
|
||||
pthread_key_create unless it's absolutely necessary. This function
|
||||
is async-signal-safe. */
|
||||
#if !defined(IS_IN_libpthread)
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
extern int __google_pthread_signal_safe_key_create (pthread_key_t *__key,
|
||||
void (*__destr_function) (void *))
|
||||
__THROW __nonnull ((1));
|
||||
|
||||
|
||||
/* Destroy KEY. */
|
||||
extern int pthread_key_delete (pthread_key_t __key) __THROW;
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <pthreadP.h>
|
||||
#include <sysdep.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
static void *libgcc_s_handle;
|
||||
static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
|
||||
@@ -51,6 +52,10 @@ pthread_cancel_init (void)
|
||||
|
||||
handle = __libc_dlopen (LIBGCC_S_SO);
|
||||
|
||||
/* Google-local: b/5836136 */
|
||||
if (handle == NULL)
|
||||
handle = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
|
||||
if (handle == NULL
|
||||
|| (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
|
||||
|| (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#define _POSIX_THREAD_KEYS_MAX 128
|
||||
/* This is the value this implementation supports. */
|
||||
#define PTHREAD_KEYS_MAX 1024
|
||||
#define PTHREAD_SIGNAL_SAFE_KEYS_MAX 4
|
||||
|
||||
/* Controlling the iterations of destructors for thread-specific data. */
|
||||
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#define _POSIX_THREAD_KEYS_MAX 128
|
||||
/* This is the value this implementation supports. */
|
||||
#define PTHREAD_KEYS_MAX 1024
|
||||
#define PTHREAD_SIGNAL_SAFE_KEYS_MAX 4
|
||||
|
||||
/* Controlling the iterations of destructors for thread-specific data. */
|
||||
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
||||
@@ -112,6 +112,36 @@ void
|
||||
attribute_hidden
|
||||
__linkin_atfork (struct fork_handler *newp)
|
||||
{
|
||||
/* GRTE's patches for async-signal-safe TLS can cause a race
|
||||
condition in which ptmalloc_init is called from more than one
|
||||
thread. (allocate_dtv normally calls calloc which invokes
|
||||
ptmalloc_init via hook while creating the first thread, but our
|
||||
code calls __signal_safe_calloc which does not run hooks.)
|
||||
ptmalloc_init tries to be idempotent in case of multiple threads,
|
||||
but in glibc-2.19, it fills in atfork hooks from an
|
||||
un-lock-protected global static atfork_mem, which is a bad idea;
|
||||
it can result in the same allocated object being passed to this
|
||||
routine more than once. This function then sets the object's next
|
||||
pointer to point to itself, resulting in a hang when the program
|
||||
tries to exit.
|
||||
|
||||
This problem has been (indirectly) resolved in upstream glibc by
|
||||
rewriting the whole thing so that thread setup is not done with
|
||||
atforks or static variables, but the changes are extensive and
|
||||
would not backport reliably. Our race is somewhat difficult to
|
||||
trigger - it requires a program to start creating threads
|
||||
*before* any kind of memory allocation whatsoever. So given all
|
||||
this, the safest route is simply to detect when the fork handler
|
||||
is already present, and skip adding it altogether.
|
||||
|
||||
Note that while it's conceivable that calls to pthread_atfork
|
||||
would result in the atfork_mem object not being at the head of
|
||||
the list, but testing seems unable to generate such a case. */
|
||||
struct fork_handler *scanp;
|
||||
for (scanp = __fork_handlers; scanp != NULL; scanp = scanp->next)
|
||||
if (newp == scanp)
|
||||
return;
|
||||
|
||||
do
|
||||
newp->next = __fork_handlers;
|
||||
while (catomic_compare_and_exchange_bool_acq (&__fork_handlers,
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#define _POSIX_THREAD_KEYS_MAX 128
|
||||
/* This is the value this implementation supports. */
|
||||
#define PTHREAD_KEYS_MAX 1024
|
||||
#define PTHREAD_SIGNAL_SAFE_KEYS_MAX 4
|
||||
|
||||
/* Controlling the iterations of destructors for thread-specific data. */
|
||||
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
/* Test that stack guards do not become resident, even with
|
||||
mlockall(MCL_FUTURE) by verifying that spawning NTHREADS with these
|
||||
stack/guard sizes use a reasonable (<100kb/thread) amount of RSS. */
|
||||
#define NTHREADS 100
|
||||
#define STACKSIZE (64 * 1024)
|
||||
#define GUARDSIZE (1024 * 1024)
|
||||
|
||||
pthread_barrier_t barrier;
|
||||
|
||||
|
||||
static void fail (const char *msg)
|
||||
{
|
||||
puts (msg);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static size_t get_rss_bytes (void)
|
||||
{
|
||||
struct rusage usage;
|
||||
if (getrusage(RUSAGE_SELF, &usage) != 0)
|
||||
fail ("getrusage failed");
|
||||
|
||||
return usage.ru_maxrss * 1024;
|
||||
}
|
||||
|
||||
static void *
|
||||
child (void *arg)
|
||||
{
|
||||
int ret = pthread_barrier_wait(&barrier);
|
||||
if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
fail("pthread_barrier_wait failed");
|
||||
while (1)
|
||||
{
|
||||
sleep (10);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
size_t bytes;
|
||||
char buffer[2048];
|
||||
size_t overhead, count;
|
||||
int fd;
|
||||
mlockall(MCL_CURRENT);
|
||||
overhead = get_rss_bytes();
|
||||
mlockall(MCL_CURRENT|MCL_FUTURE);
|
||||
if (pthread_barrier_init(&barrier, NULL, NTHREADS + 1) != 0)
|
||||
fail("pthread_barrier_init failed");
|
||||
for (i = 0; i < NTHREADS; ++i)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
pthread_attr_init (&attr);
|
||||
pthread_attr_setstacksize (&attr, STACKSIZE + GUARDSIZE);
|
||||
pthread_attr_setguardsize (&attr, GUARDSIZE);
|
||||
err = pthread_create (&tid, &attr, child, NULL);
|
||||
if (err != 0)
|
||||
fail("pthread_create failed");
|
||||
}
|
||||
err = pthread_barrier_wait(&barrier);
|
||||
if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
fail("pthread_barrier_wait failed");
|
||||
bytes = get_rss_bytes ();
|
||||
fd = open("/proc/self/smaps", O_RDONLY);
|
||||
while(0 < (count = read(fd, buffer, 2048)))
|
||||
write(1, buffer, count);
|
||||
close(fd);
|
||||
printf ("%d threads with %d stacks and %d guards using %zu per thread\n",
|
||||
NTHREADS, STACKSIZE, GUARDSIZE, (bytes-overhead)/NTHREADS);
|
||||
if ((bytes-overhead) > (NTHREADS * GUARDSIZE))
|
||||
fail ("memory usage too high");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -28,7 +28,11 @@ do_test (void)
|
||||
{
|
||||
int max;
|
||||
#ifdef PTHREAD_KEYS_MAX
|
||||
#ifdef PTHREAD_SIGNAL_SAFE_KEYS_MAX
|
||||
max = PTHREAD_KEYS_MAX - PTHREAD_SIGNAL_SAFE_KEYS_MAX;
|
||||
#else
|
||||
max = PTHREAD_KEYS_MAX;
|
||||
#endif
|
||||
#else
|
||||
max = _POSIX_THREAD_KEYS_MAX;
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,11 @@
|
||||
|
||||
|
||||
#ifdef PTHREAD_KEYS_MAX
|
||||
#ifdef PTHREAD_SIGNAL_SAFE_KEYS_MAX
|
||||
const int max = PTHREAD_KEYS_MAX - PTHREAD_SIGNAL_SAFE_KEYS_MAX;
|
||||
#else
|
||||
const int max = PTHREAD_KEYS_MAX;
|
||||
#endif
|
||||
#else
|
||||
const int max = _POSIX_THREAD_KEYS_MAX;
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/* Copyright (C) 2014 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 <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
pthread_key_t key;
|
||||
void *value;
|
||||
size_t r;
|
||||
static void
|
||||
handler (int signo)
|
||||
{
|
||||
void *ret = pthread_getspecific (key);
|
||||
/* We race with the setspecific--either result is fine, just not junk. */
|
||||
assert (ret == value || ret == NULL);
|
||||
r++;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
memset (&sa, 0, sizeof (sa));
|
||||
sa.sa_handler = handler;
|
||||
|
||||
assert (0 == sigaction (SIGUSR1, &sa, NULL));
|
||||
|
||||
timer_t timer;
|
||||
struct sigevent sevp;
|
||||
sevp.sigev_notify = SIGEV_SIGNAL;
|
||||
sevp.sigev_signo = SIGUSR1;
|
||||
assert (0 == timer_create(CLOCK_MONOTONIC, &sevp, &timer));
|
||||
struct itimerspec spec;
|
||||
spec.it_value.tv_sec = 0;
|
||||
spec.it_value.tv_nsec = 500;
|
||||
spec.it_interval = spec.it_value;
|
||||
timer_settime(timer, 0, &spec, NULL);
|
||||
#define NITERS (1000 * 1000)
|
||||
for (int i = 0; i < NITERS; ++i)
|
||||
{
|
||||
value = (void *)((intptr_t)i + 1);
|
||||
assert (0 == pthread_key_create(&key, NULL));
|
||||
assert (0 == pthread_setspecific(key, value));
|
||||
if (value != pthread_getspecific(key))
|
||||
{
|
||||
printf ("Lost a value\n");
|
||||
return 1;
|
||||
}
|
||||
assert (0 == pthread_key_delete(key));
|
||||
}
|
||||
timer_delete(timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/* Copyright (C) 2013 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 that TLS in a dlopened object works when first accessed
|
||||
from a signal handler. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <atomic.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void *
|
||||
spin (void *ignored)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
/* busywork */
|
||||
free (malloc (128));
|
||||
}
|
||||
|
||||
/* never reached */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void (*tls7mod_action) (int, siginfo_t *, void *);
|
||||
|
||||
static void
|
||||
action (int signo, siginfo_t *info, void *ignored)
|
||||
{
|
||||
sem_t *sem = info->si_value.sival_ptr;
|
||||
|
||||
atomic_read_barrier ();
|
||||
assert (tls7mod_action != NULL);
|
||||
(*tls7mod_action) (signo, info, ignored);
|
||||
|
||||
/* This sem_post may trigger dlclose, which will invalidate tls7mod_action.
|
||||
It is important to do that only after tls7mod_action is no longer
|
||||
active. */
|
||||
sem_post (sem);
|
||||
}
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
pthread_t th[10];
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
if (pthread_create (&th[i], NULL, spin, NULL))
|
||||
{
|
||||
puts ("pthread_create failed");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
#define NITERS 75
|
||||
|
||||
for (int i = 0; i < NITERS; ++i)
|
||||
{
|
||||
void *h = dlopen ("tst-tls7mod.so", RTLD_LAZY);
|
||||
if (h == NULL)
|
||||
{
|
||||
puts ("dlopen failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
tls7mod_action = dlsym (h, "action");
|
||||
if (tls7mod_action == NULL)
|
||||
{
|
||||
puts ("dlsym for action failed");
|
||||
exit (1);
|
||||
}
|
||||
atomic_write_barrier ();
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = action;
|
||||
sigemptyset (&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
if (sigaction (SIGUSR1, &sa, NULL))
|
||||
{
|
||||
puts ("sigaction failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
sem_t sem;
|
||||
if (sem_init (&sem, 0, 0))
|
||||
{
|
||||
puts ("sem_init failed");
|
||||
}
|
||||
|
||||
sigval_t val;
|
||||
val.sival_ptr = &sem;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
if (pthread_sigqueue (th[i], SIGUSR1, val))
|
||||
{
|
||||
puts ("pthread_sigqueue failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
if (sem_wait (&sem))
|
||||
{
|
||||
puts ("sem_wait failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* Paranoia. */
|
||||
tls7mod_action = NULL;
|
||||
|
||||
if (dlclose (h))
|
||||
{
|
||||
puts ("dlclose failed");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TIMEOUT 8
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -0,0 +1,107 @@
|
||||
/* Copyright (C) 2015 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 <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthreaddef.h>
|
||||
|
||||
static pthread_t th;
|
||||
|
||||
pthread_barrier_t b;
|
||||
|
||||
void *(*dfp)(void*) = NULL;
|
||||
|
||||
void *
|
||||
caller(void *x)
|
||||
{
|
||||
pthread_barrier_wait (&b);
|
||||
|
||||
if (dfp)
|
||||
dfp(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
if (pthread_barrier_init (&b, NULL, 2) != 0)
|
||||
{
|
||||
puts ("barrier_init failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
pthread_attr_t a;
|
||||
|
||||
if (pthread_attr_init (&a) != 0)
|
||||
{
|
||||
puts ("attr_init failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
|
||||
{
|
||||
puts ("attr_setstacksize failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pthread_create (&th, &a, caller, 0) != 0)
|
||||
{
|
||||
puts ("pthread_create failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void *h = dlopen ("tst-tls77mod.so", RTLD_LAZY);
|
||||
if (h == NULL)
|
||||
{
|
||||
puts ("dlopen failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
dfp = dlsym (h, "toucher");
|
||||
if (dfp == NULL)
|
||||
{
|
||||
printf ("dlsym for toucher failed %s\n", dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
pthread_barrier_wait (&b);
|
||||
|
||||
if (pthread_join (th, NULL) != 0)
|
||||
{
|
||||
puts ("join failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (pthread_attr_destroy (&a) != 0)
|
||||
{
|
||||
puts ("attr_destroy failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define TIMEOUT 5
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright (C) 2015 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 <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthreaddef.h>
|
||||
|
||||
__thread int tlsvar;
|
||||
|
||||
__thread int iexecvar __attribute__ ((tls_model ("initial-exec")));
|
||||
|
||||
void *
|
||||
toucher (void *arg)
|
||||
{
|
||||
tlsvar++;
|
||||
|
||||
printf ("tlsvar=%d iexecvar=%d\n", tlsvar, iexecvar);
|
||||
|
||||
iexecvar++;
|
||||
|
||||
printf ("tlsvar=%d iexecvar=%d\n", tlsvar, iexecvar);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2013 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/>. */
|
||||
|
||||
/* Dynamic module with TLS to be accessed by a signal handler to check safety
|
||||
of that mode. */
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* This is an unlikely value to see in incorrectly initialized TLS
|
||||
block -- make sure we're initialized properly. */
|
||||
static __thread intptr_t tls_data = 0xdeadbeef;
|
||||
|
||||
void
|
||||
action (int signo, siginfo_t *info, void *ignored)
|
||||
{
|
||||
if (tls_data != 0xdeadbeef)
|
||||
{
|
||||
write (STDOUT_FILENO, "wrong TLS value\n", 17);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
/* arbitrary choice, just write something unique-ish. */
|
||||
tls_data = (intptr_t) info;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user