Compare commits

..

140 Commits

Author SHA1 Message Date
Colin Cross
635ff5fdac Merge "Add more of the bionic architecture logic" into master-soong 2015-07-10 01:03:44 +00:00
Colin Cross
a56904273c Merge "Add version_script to bionic Blueprints" into master-soong 2015-07-10 01:00:49 +00:00
Colin Cross
f93bddbbd8 Merge "Add translation directives to libc Android.bp" into master-soong 2015-07-10 01:00:41 +00:00
Colin Cross
2803a15d4c Add more of the bionic architecture logic
Change-Id: I8aecabdc7219ad9e9affab1a3e67164352858bf9
2015-07-09 17:42:58 -07:00
Colin Cross
70f11bd69b Add version_script to bionic Blueprints
Change-Id: Ieddd80fa599c21414608e1d1c20ebaa2507a66ef
2015-07-09 17:35:15 -07:00
Colin Cross
8f7a4a3cb5 Add translation directives to libc Android.bp
Add translation directives for the crt*.o files instead of trying
to handle them in the translator.

Change-Id: I44a491f1823f483d9c40368da35d4e0cf16030f2
2015-07-09 17:35:07 -07:00
Dan Willemsen
649a2ea0e2 Merge "Switch libm from thumb to arm" into master-soong 2015-07-09 05:31:41 +00:00
Dan Willemsen
c371306714 Switch libm from thumb to arm
To match the Android.mk file

Change-Id: I02cb5f4b140c03bc8630879f005e027426a5dd99
2015-07-08 19:12:09 -07:00
Dan Willemsen
87e33892fc Merge "Use exclude_srcs instead of "-file"" into master-soong 2015-07-06 19:52:39 +00:00
Dan Willemsen
7454daa97f Use exclude_srcs instead of "-file"
Change-Id: Ie07c5901233d429102f9b6afcef12ea8c4bdda2c
2015-07-01 14:00:21 -07:00
Colin Cross
dab6ead2aa Rename Blueprints to Android.bp
Rename module definition files to Android.bp to avoid conflicts
with another project called Blueprint.

Change-Id: I69cfe9649fe35735dade6416d15b171a5bb2e283
2015-05-20 13:11:07 -07:00
Colin Cross
7d0b7b4ba2 Merge "Remove nonexistant include path" into master-soong 2015-05-12 19:31:16 +00:00
Colin Cross
98f4e07237 Remove nonexistant include path
upstream-freebsd/lib/libc/include doesn't exist, remove it from the
include path.

Change-Id: I0492784db5dc45e4a9a937956d095a147a08e835
2015-05-12 11:35:48 -07:00
Colin Cross
b624072cbd Merge "Export libbenchmark include dir" into master-soong 2015-05-08 00:06:32 +00:00
Colin Cross
0ecd342743 Export libbenchmark include dir
Export the libbenchmark include directory so the build system
doesn't have manually add it for cc_benchmark modules.

Change-Id: I918a2fa5fb3104f4c2d86930ed2b9c5e00820ec6
2015-05-07 15:51:37 -07:00
Colin Cross
faa14d4de8 Merge "Fix Blueprints for building on Darwin" into master-soong 2015-05-07 21:31:49 +00:00
Colin Cross
abc97e2e71 Fix Blueprints for building on Darwin
Change-Id: I252e1b8a9ace397609f056f69aff83331b92aab7
2015-05-05 16:52:38 -07:00
Colin Cross
6549fe249c Update Blueprints files for AOSP changes
Change-Id: I915fc1e00b6e6eb1d6c08233893517b1d56c74fa
2015-04-29 11:34:24 -07:00
Colin Cross
c15e8fdb8d Merge remote-tracking branch 'aosp/master' into aosp 2015-04-29 11:29:05 -07:00
Neil Fuller
fa6f649607 Merge "Update to tzdata 2015d" 2015-04-29 10:42:16 +00:00
Dmitriy Ivanov
e1a61f5e93 Merge "Fix LD_PRELOAD for dlopen()" 2015-04-29 01:59:53 +00:00
Jeff Brown
0bf650373e Merge "Add float support to binary event log." 2015-04-29 01:42:49 +00:00
Jeff Brown
11331f60dd Add float support to binary event log.
Bug: 20664753
Change-Id: I6e43c07daa727c19d87f5192bb719af63dd93654
2015-04-28 18:20:22 -07:00
Dmitriy Ivanov
f8093a9485 Fix LD_PRELOAD for dlopen()
We did not set DF_1_GLOBAL flag for LD_PRELOADed
 libraries which led to the situation when ld_preloads
 where ignored during on dlopen()

Change-Id: I696b3b2506a8ed4c0984ad2c803210a7a4f8e686
2015-04-28 18:09:53 -07:00
Mark Salyzyn
b904afa16e Merge "bionic: add __system_property_area_serial()" 2015-04-28 22:11:52 +00:00
Dmitriy Ivanov
9f0d99d298 Merge "Do not pack relocations for libc.so" 2015-04-28 22:06:43 +00:00
Dmitriy Ivanov
62d6533c1a Do not pack relocations for libc.so
Bug: http://b/20645321
Bug: http://b/20655855
(cherry picked from commit 452742d2bf)

Change-Id: Ic9125cc1bc4c9ba9eb20d030de72e3ce1fb86fa6
2015-04-28 15:05:20 -07:00
Dmitriy Ivanov
bed7a7e5eb Merge "linker: use libc's environ variable to store envp" 2015-04-28 21:35:59 +00:00
Dmitriy Ivanov
a85bcc2e99 linker: use libc's environ variable to store envp
This is to make getenv() work correctly.

Bug: http://b/20567629
Change-Id: I148627e1efea1649fb0822c95876811652fb4082
2015-04-28 14:21:36 -07:00
Christopher Ferris
6fa65e7cd5 Merge "cortex-a9: Fix reference to __memcpy_base_aligned." 2015-04-28 20:28:42 +00:00
Kyle Repinski
e0905c94d3 cortex-a9: Fix reference to __memcpy_base_aligned.
With a different memcpy, __memcpy_base_aligned ceased to exist.
Instead, point to the name defined by whatever includes memcpy_base.S

Change-Id: I242cf49cbada35337ba155d7f170e86a905ff55f
2015-04-28 14:29:15 -05:00
Neil Fuller
520cbf51b1 Update to tzdata 2015d
Changes affecting future time stamps

    Egypt will not observe DST in 2015 and will consider canceling it
    permanently.  For now, assume no DST indefinitely.
    (Thanks to Ahmed Nazmy and Tim Parenti.)

  Changes affecting past time stamps

    America/Whitehorse switched from UTC-9 to UTC-8 on 1967-05-28, not
    1966-07-01.  Also, Yukon's time zone history is documented better.
    (Thanks to Brian Inglis and Dennis Ferguson.)

  Change affecting past and future time zone abbreviations

    The abbreviations for Hawaii-Aleutian standard and daylight times
    have been changed from HAST/HADT to HST/HDT, as per US Government
    Printing Office style.  This affects only America/Adak since 1983,
    as America/Honolulu was already using the new style.

Bug: 20551453
Change-Id: I02364f15ca4ae20ed1a3b327f8517214bee938e5
2015-04-28 17:11:03 +01:00
Dmitriy Ivanov
42d7468f99 Merge "Reduce p_align for program header to page size." 2015-04-28 03:38:27 +00:00
Dmitriy Ivanov
b293969c6d Reduce p_align for program header to page size.
Having p_align > page_size leads to the situation when striping
 packed executables results in unnecessary p_vaddr adjustments.
 And it also may result (with probability 1 - 1/sizeof(uintptr_t)) in
 misaligned segments following .dynstr

Bug: http://b/20629834
Bug: http://b/18051137
Change-Id: I1c5da4911e4409d63cb09f6b6b0a16ef54f6501b
2015-04-27 20:37:17 -07:00
Dmitriy Ivanov
032907d8c7 Merge "Remove outdated warning" 2015-04-27 18:28:31 +00:00
Dmitriy Ivanov
2ea504fed1 Remove outdated warning
It is ok to use malloc in linker.

Bug: http://b/20567629
Change-Id: I54183dbe8ebcd223a44e710e511c339688a65dba
2015-04-27 11:24:36 -07:00
Chih-Hung Hsieh
59bce688c7 Merge "Fix opcode to compile with both gcc and llvm." 2015-04-27 17:17:45 +00:00
Mark Salyzyn
bfd65279a5 bionic: add __system_property_area_serial()
Adds a new _internal_ function. Provide a global serial number to
support more efficient private caching algorithms. This allows
to skip re-running the __system_property_find() call on misses until
there is a global change in the properties. This call is a read
barrier, the property data to be read following this call will be
read sequentially and up to date.

Bug: 19544788
Change-Id: I58e6a92baa0f3e8e7b9ec79b10af6d56407dab48
2015-04-27 07:44:03 -07:00
Neil Fuller
682a240c5d Merge "Update to tzdata 2015c" 2015-04-27 08:19:16 +00:00
Nick Kralevich
1d76f1cc8b Merge "add a fortified implementation of realpath" 2015-04-26 02:23:04 +00:00
Nick Kralevich
42502d702e Merge "add fortified memchr/memrchr implementations" 2015-04-25 21:29:57 +00:00
Dmitriy Ivanov
2eaff07839 Merge "Include pthread_atfork.h to mips64 crtbegin" 2015-04-25 19:20:00 +00:00
Dmitriy Ivanov
f327fae69c Include pthread_atfork.h to mips64 crtbegin
Bug: http://b/20339788
Change-Id: I2a8c7881f90a05ca768cb9b4c2f8b07c74c64469
2015-04-25 11:59:32 -07:00
Elliott Hughes
9a2744df30 Merge "Fix POSIX timer thread naming." 2015-04-25 18:01:18 +00:00
Elliott Hughes
d1aea30b2a Fix POSIX timer thread naming.
Spencer Low points out that we never actually set a name because the constant
part of the string was longer than the kernel's maximum, and the kernel
rejects long names rather than truncate.

Shorten the fixed part of the string while still keeping it meaningful. 9999
POSIX timers should be enough for any process...

Bug: https://code.google.com/p/android/issues/detail?id=170089
Change-Id: Ic05f07584c1eac160743519091a540ebbf8d7eb1
2015-04-25 10:05:24 -07:00
Dmitriy Ivanov
2c256a0f09 Merge "Unregister pthread_atfork handlers on dlclose()" 2015-04-25 05:36:07 +00:00
Dmitriy Ivanov
440242f038 Merge "Use bfd linker for x86/x86_64 targets" 2015-04-25 04:09:43 +00:00
Dmitriy Ivanov
e91e66f223 Use bfd linker for x86/x86_64 targets
ld.gold in current toolchain for x86_64
 does not support -z global.

Change-Id: Iea2b192f0f0aa998a02adb356fd4eec4e10a1739
2015-04-24 21:05:49 -07:00
Dmitriy Ivanov
ea295f68f1 Unregister pthread_atfork handlers on dlclose()
Bug: http://b/20339788
Change-Id: I874c87faa377645fa9e0752f4fc166d81fd9ef7e
2015-04-24 17:57:37 -07:00
Dmitriy Ivanov
ebfb55e4cd Merge "Enable dlsym_df_1_global test for arm/arm64" 2015-04-25 00:50:05 +00:00
Dmitriy Ivanov
6612d7a347 Enable dlsym_df_1_global test for arm/arm64
Change-Id: I1fdebced93175cb14053e2239e79f97239fc2dc2
2015-04-24 16:26:03 -07:00
Dmitriy Ivanov
2bb93482a7 Merge "Exit normally when relocations are already packed." 2015-04-24 19:42:39 +00:00
Dmitriy Ivanov
b0b9338ff8 Exit normally when relocations are already packed.
Bug: http://b/18051137
Change-Id: Idfffac5fe965e3cdeabe6d3b2dcd8c275c6ae5df
2015-04-24 12:39:14 -07:00
Neil Fuller
d2177404e2 Update to tzdata 2015c
Changes affecting future time stamps

    Egypt's spring-forward transition is at 24:00 on April's last Thursday,
    not 00:00 on April's last Friday.  2015's transition will therefore be on
    Thursday, April 30 at 24:00, not Friday, April 24 at 00:00.  Similar fixes
    apply to 2026, 2037, 2043, etc.  (Thanks to Steffen Thorsen.)

  Changes affecting past time stamps

    The following changes affect some pre-1991 Chile-related time stamps
    in America/Santiago, Antarctica/Palmer, and Pacific/Easter.

      The 1910 transition was January 10, not January 1.

      The 1918 transition was September 10, not September 1.

      The UTC-4 time observed from 1932 to 1942 is now considered to be
      standard time, not year-round DST.

      Santiago observed DST (UTC-3) from 1946-07-15 through 1946-08-31,
      then reverted to standard time, then switched its time zone to
      UTC-5 on 1947-04-01.

      Assume transitions before 1968 were at 00:00, since we have no data
      saying otherwise.

      The spring 1988 transition was 1988-10-09, not 1988-10-02.
      The fall 1990 transition was 1990-03-11, not 1990-03-18.

      Assume no UTC offset change for Pacific/Easter on 1890-01-01,
      and omit all transitions on Pacific/Easter from 1942 through 1946
      since we have no data suggesting that they existed.

    One more zone has been turned into a link, as it differed
    from an existing zone only for older time stamps.  As usual,
    this change affects UTC offsets in pre-1970 time stamps only.
    The zone's old contents have been moved to the 'backzone' file.
    The affected zone is America/Montreal.

Bug: 20287125
Change-Id: I8512c4e9ab09725395b256aba59ca34a23d1c995
2015-04-24 13:56:11 +01:00
Dimitry Ivanov
6c63ee41ac Merge "Revert "Unregister pthread_atfork handlers on dlclose()"" 2015-04-24 03:49:30 +00:00
Dimitry Ivanov
094f58fb2a Revert "Unregister pthread_atfork handlers on dlclose()"
The visibility control in pthread_atfork.h is incorrect.
 It breaks 64bit libc.so by hiding pthread_atfork.

 This reverts commit 6df122f852.

Change-Id: I21e4b344d500c6f6de0ccb7420b916c4e233dd34
2015-04-24 03:46:57 +00:00
Dmitriy Ivanov
41ebceaf3a Merge "Exit normally when packing relocs saves no space." 2015-04-23 22:55:34 +00:00
Dmitriy Ivanov
adfcb97317 Exit normally when packing relocs saves no space.
Bug: http://b/18051137
Change-Id: I43ea5678a677e5d39fb54fafcf3a2f3a252c79b0
2015-04-23 22:54:25 +00:00
Dmitriy Ivanov
e3ecedd306 Merge "Remove jemalloc.a from libc_nomalloc.a" 2015-04-23 21:50:15 +00:00
Chih-Hung Hsieh
0a93df369c Fix opcode to compile with both gcc and llvm.
BUG: 17302991

Change-Id: I31febd9ad24312388068803ce247b295bd73b607
2015-04-23 21:40:31 +00:00
Elliott Hughes
3da9373fe0 Merge "Simplify close(2) EINTR handling." 2015-04-23 21:14:25 +00:00
Dmitriy Ivanov
7280e507b6 Remove jemalloc.a from libc_nomalloc.a
Change-Id: I86edc1a6cf3a26c46e6daef2c859459c1b0f29af
2015-04-23 12:24:43 -07:00
Elliott Hughes
3391a9ff13 Simplify close(2) EINTR handling.
This doesn't affect code like Chrome that correctly ignores EINTR on
close, makes code that tries TEMP_FAILURE_RETRY work (where before it might
have closed a different fd and appeared to succeed, or had a bogus EBADF),
and makes "goto fail" code work (instead of mistakenly assuming that EINTR
means that the close failed).

Who loses? Anyone actively trying to detect that they caught a signal while
in close(2). I don't think those people exist, and I think they have better
alternatives available.

Bug: https://code.google.com/p/chromium/issues/detail?id=269623
Bug: http://b/20501816
Change-Id: I11e2f66532fe5d1b0082b2433212e24bdda8219b
2015-04-23 08:41:45 -07:00
Dmitriy Ivanov
dc405b5230 Merge "Unregister pthread_atfork handlers on dlclose()" 2015-04-23 08:05:25 +00:00
Dmitriy Ivanov
6df122f852 Unregister pthread_atfork handlers on dlclose()
Change-Id: I326fdf6bb06bed12743f08980b5c69d849c015b8
2015-04-22 19:19:37 -07:00
Dmitriy Ivanov
ff18108981 Merge "Always use signed leb128 decoder" 2015-04-22 22:16:31 +00:00
Dmitriy Ivanov
18870d350c Always use signed leb128 decoder
Relocation packer no longer encodes relocation tables
  using unsigned leb128: https://android-review.googlesource.com/147745

Bug: http://b/18051137
Change-Id: I620b7188e5f3dd9d5123431aa1fc7feca76be607
2015-04-22 13:29:42 -07:00
Dmitriy Ivanov
9ceec1a75d Merge "Always use signed leb128 encoding" 2015-04-22 20:02:04 +00:00
Dmitriy Ivanov
f15ceeb784 Always use signed leb128 encoding
According to runs on /system/lib there using
 unsigned leb128 does not save us any additional
 space. In order to keep packing as simple as
 possible switch to using signed leb128 for
 everything.

Bug: http://b/18051137
Change-Id: I1a47cb9eb2175895b3c3f7c13b4c6b1060de86c0
2015-04-22 12:58:38 -07:00
Tao Bao
457c34ad84 Merge "Update the search path for libclang.so" 2015-04-22 18:25:45 +00:00
Dmitriy Ivanov
913fe559f6 Merge "Statically link libc++ for prebuilts" 2015-04-22 18:15:27 +00:00
Tao Bao
7592008030 Update the search path for libclang.so
Prebuilt shared libraries (libclang.so, libLLVM.so and etc) have been
moved to prebuilts/sdk/tools/linux/lib64. Update the search path in
cpp.py to match the change.

Bug: 20485471
Change-Id: Ib7784db4d5529d16a1e2bfc07cb0237929bc5a64
2015-04-22 10:47:01 -07:00
Dmitriy Ivanov
2a6342187a Statically link libc++ for prebuilts
Statically link libc++ to relocation_packer in
 order to make it work from prebuilts

Bug: http://b/18051137
Change-Id: I933ed6a0e48780a26b261069eb6a293432824fe7
2015-04-22 10:43:12 -07:00
Chih-Hung Hsieh
a00a9f0b7e Merge "Allow building libc long double code with clang/llvm." 2015-04-21 23:44:59 +00:00
Chih-Hung Hsieh
6fb8e96e5f Allow building libc long double code with clang/llvm.
This requires fix of clang's Android x86 long double size and format.
That bug has been fixed in https://android-review.git.corp.google.com/#/c/146254/

Change-Id: I182c6c493085212f88c694356659f72227c8b8c7
2015-04-21 21:20:37 +00:00
Dmitriy Ivanov
da3c4f2f0d Merge "Adjust DT_VERSYM/VERNEED/VERDEF dynamic sections" 2015-04-21 19:29:19 +00:00
Dmitriy Ivanov
bb25bbe19e Adjust DT_VERSYM/VERNEED/VERDEF dynamic sections
This is recent addition to bionic linker. The symbol
  versioning was not supported before therefore this bug
  went unnoticed.

  Also normal exit when there is not enought relocations
  to pack. This is to enable integration of relocation_packer
  to android build system.

Bug: http://b/20139821
Bug: http://b/18051137
Change-Id: Iaf36ae11c8e4b15cf785b6dd1712a3bdcf47cc45
2015-04-21 12:28:21 -07:00
Dmitriy Ivanov
0776f0f6e2 Merge "Add library name to error message" 2015-04-21 00:51:36 +00:00
Dmitriy Ivanov
3d7bea1fa0 Add library name to error message
Change-Id: I079e6f1dd95fe9cae2135fcd7358c51f8b584ac9
2015-04-20 17:40:39 -07:00
Daniel Micay
3244d9f07f add a fortified implementation of realpath
Change-Id: Icc59eacd1684f7cddd83d7a2b57dad0c7ada5eb7
2015-04-20 17:31:24 -04:00
Yabin Cui
c5bd96efd2 Merge "Fix bug in app_id_from_name in stubs.cpp." 2015-04-18 22:54:35 +00:00
Yabin Cui
72a6fdcdc7 Fix bug in app_id_from_name in stubs.cpp.
It seems that a break statement is missing.

Bug: 19872411
Change-Id: I9362783ab726d01f6eb27418563e716dd95688dc
2015-04-18 14:10:12 -07:00
Nick Kralevich
af7538b496 Merge "add fortified readlink/readlinkat implementations" 2015-04-18 15:30:18 +00:00
Daniel Micay
4ae773633a add fortified memchr/memrchr implementations
Change-Id: I38c473cc0c608b08f971409a95eb8b853cb2ba1c
2015-04-17 21:17:12 -04:00
Dan Albert
7a8c7c48db Merge "Also send bionicbb logs to a file." 2015-04-18 00:58:23 +00:00
Dan Albert
21988a3b16 Also send bionicbb logs to a file.
Change-Id: If9a6fdbe004e3b4bb7d868b7255f83c232759f80
2015-04-17 17:57:15 -07:00
Dan Albert
cb6ae56b3e Merge "Merge the two bionicbb services into one." 2015-04-18 00:55:31 +00:00
Dan Albert
d3fe4f1229 Merge the two bionicbb services into one.
Change-Id: I6490da1ec96b2e24b330296950be84424e11bd35
2015-04-17 17:39:36 -07:00
Daniel Micay
42281880a8 add fortified readlink/readlinkat implementations
Change-Id: Ia4b1824d20cad3a072b9162047492dade8576779
2015-04-17 18:49:12 -04:00
Dmitriy Ivanov
3875744f89 Merge "Support symbol versioning" 2015-04-17 03:57:46 +00:00
Elliott Hughes
fc4850e37b Merge "Fix clang build." 2015-04-17 00:57:52 +00:00
Dmitriy Ivanov
2a81536144 Support symbol versioning
Bug: http://b/20139821
Change-Id: I64122a0fb0960c20b2ce614161b7ab048456b681
2015-04-16 17:57:30 -07:00
Elliott Hughes
a9325133aa Fix clang build.
Change-Id: I70a9ebe806cb4f7e23a7d8e486157ddd70ae3008
2015-04-16 17:56:12 -07:00
Elliott Hughes
31128da28f Merge "add fortified implementations of pread/pread64" 2015-04-17 00:34:26 +00:00
Dan Albert
f84a5c6c5c Merge "Clean up "logging"." 2015-04-16 22:08:39 +00:00
Dan Albert
a4061cddbe Clean up "logging".
Print is bad and I should feel bad. Use the logging module instead.
Will follow up by adding a persistent log destination instead of just
the console.

Change-Id: I396ff10712f88a03f8d8183b6de29ea273815962
2015-04-16 14:20:13 -07:00
Elliott Hughes
14af27a147 Merge "Remove PROP_PATH_SYSTEM_DEFAULT." 2015-04-16 19:58:00 +00:00
Daniel Micay
e7e1c875b0 add fortified implementations of pread/pread64
Change-Id: Iec39c3917e0bc94371bd81541619392f5abe29b9
2015-04-16 10:33:35 -04:00
Dmitriy Ivanov
a40cb0ca7f Merge "Call __cxa_thread_finalize for the main thread." 2015-04-16 08:06:03 +00:00
Christopher Ferris
12d8902745 Merge "Update the number of jemalloc reserved keys." 2015-04-16 04:42:38 +00:00
Yabin Cui
2587c6a2f0 Merge "Change on handling of SIGEV_THREAD timers." 2015-04-16 01:08:25 +00:00
Yabin Cui
95f1ee235a Change on handling of SIGEV_THREAD timers.
1. Don't prevent calling callback when SIGEV_THREAD timers are disarmed by timer_settime.
As in POSIX standard: The effect of disarming or resetting a timer with pending
expiration notifications is unspecified. And glibc didn't prevent in this situation, so I
think it is fine to remove the support.
2. Still prevent calling callback when SIGEV_THREAD timers are deleted by timer_delete.
As in POSIX standard: The disposition of pending signals for the deleted timer is unspecified.
However, glibc handles this (although that is not perfect). And some of our tests in
time_test.cpp depend on this feature as described in b/18039727. so I retain the support.
3. Fix some flaky test in time_test.cpp, and make "time*" test pass on bionic-unit-tests-glibcxx.

Bug: 18263854

Change-Id: I8ced184eacdbfcf433fd81b0c69c38824beb8ebc
2015-04-15 17:36:01 -07:00
Christopher Ferris
c0f89283cc Update the number of jemalloc reserved keys.
jemalloc now uses a single key pointing to a structure rather
than multiple keys.

Change-Id: Ib76185a594ab2cd4dc400d9a7a5bc0a57a7ac92d
2015-04-15 17:20:10 -07:00
Elliott Hughes
43e020ce93 Remove PROP_PATH_SYSTEM_DEFAULT.
Change-Id: Ib01d9c2f9d890eb5e7ba1e15bd11767195e84967
2015-04-15 17:03:43 -07:00
Dmitriy Ivanov
c6ccdfaf1f Merge "Hide emutls* symbols in libc.so" 2015-04-15 23:27:38 +00:00
Dmitriy Ivanov
163ab8ba86 Call __cxa_thread_finalize for the main thread.
Bug: http://b/20231984
Bug: http://b/16696563
Change-Id: I71cfddd0d404d1d4a593ec8d3bca9741de8cb90f
2015-04-15 16:24:21 -07:00
Dmitriy Ivanov
66aa0b61f7 Hide emutls* symbols in libc.so
Also make thread_local in test static to avoid ld.bfd
 warning for arm64.

Change-Id: I09a3f2aa9b73a4fafa3f3bbc64ddc2a128ad50ee
2015-04-15 14:23:00 -07:00
Christopher Ferris
cafc948069 Merge "Fix addition of extra arg to cfi_restore." 2015-04-15 00:07:35 +00:00
Christopher Ferris
940d3122c9 Fix addition of extra arg to cfi_restore.
Change-Id: I8fdcc1ae3e91b69ccbcec756a89e1ccb4fa1be53
2015-04-14 17:02:31 -07:00
Christopher Ferris
a529efac4e Merge "Add missing cfi directives for x86 assembler." 2015-04-14 23:43:09 +00:00
Christopher Ferris
605ee81b06 Add missing cfi directives for x86 assembler.
Change-Id: I80d3e33a71bbaeab5f39b667ebe61e865fd54b80
2015-04-14 16:42:10 -07:00
Yabin Cui
8f3f04184a Merge "Prevent using static-allocated pthread keys before creation." 2015-04-14 20:35:08 +00:00
Yabin Cui
5ddbb3f936 Prevent using static-allocated pthread keys before creation.
Bug: 19993460

Change-Id: I244dea7f5df3c8384f88aa48d635348fafc9cbaf
2015-04-14 13:32:09 -07:00
Dan Albert
447cd19681 Merge "Skip merge-failed messages from Gerrit." 2015-04-14 01:33:35 +00:00
Dan Albert
a0ecd5b2b4 Skip merge-failed messages from Gerrit.
Change-Id: I2d8055a44cd78f95e64d6cf88e9efdd610a4fa88
2015-04-13 17:33:51 -07:00
Dmitriy Ivanov
de88974120 Merge "Fix dl* tests to run-on-host" 2015-04-11 00:28:05 +00:00
Dan Albert
c921eb6770 Merge "Don't build any changes that touch bionicbb." 2015-04-10 00:25:18 +00:00
Dan Albert
d032378790 Don't build any changes that touch bionicbb.
Right now any changes in here would be innocuous because I manually
update bionicbb, but I'd like to check in the various job
configurations. Once I have we don't want anyone to be able to make
the buildbot run any untrusted code.

Change-Id: Ic050859cd5017615f71c75f995ba21bb45407b05
2015-04-09 17:18:53 -07:00
Dmitriy Ivanov
9ce9bf5aec Merge "Add Elfxx_Ver* types" 2015-04-09 22:14:09 +00:00
Dmitriy Ivanov
ef25592f14 Fix dl* tests to run-on-host
Bug: http://b/20121152
Change-Id: I1e1f41d885c75dbb26f91565a53a15d62ef72ce6
2015-04-09 14:56:26 -07:00
Dmitriy Ivanov
c0e7dbb1db Add Elfxx_Ver* types
Bug: http://b/20139821
Change-Id: I7a367b08faa3bf5c005996c066cd35709f533265
2015-04-09 13:58:53 -07:00
Christopher Ferris
0a92ac8848 Merge "Use assembly memmove for all arm32 processors." 2015-04-09 17:41:58 +00:00
Yabin Cui
9f2c2f53d3 Merge "Provide writer preference option in rwlock." 2015-04-09 17:19:44 +00:00
Neil Fuller
f9ff2eeaee Merge "Upgrade timezone data to 2015b" 2015-04-09 13:45:03 +00:00
Neil Fuller
aba687a09c Upgrade timezone data to 2015b
Changes affecting future time stamps

    Mongolia will start observing DST again this year, from the last
    Saturday in March at 02:00 to the last Saturday in September at 00:00.
    (Thanks to Ganbold Tsagaankhuu.)

    Palestine will start DST on March 28, not March 27.  Also,
    correct the fall 2014 transition from September 26 to October 24.
    Adjust future predictions accordingly.  (Thanks to Steffen Thorsen.)

  Changes affecting past time stamps

    The 1982 zone shift in Pacific/Easter has been corrected, fixing a 2015a
    regression.  (Thanks to Stuart Bishop for reporting the problem.)

    Some more zones have been turned into links, when they differed
    from existing zones only for older time stamps.  As usual,
    these changes affect UTC offsets in pre-1970 time stamps only.
    Their old contents have been moved to the 'backzone' file.
    The affected zones are: America/Antigua, America/Cayman,
    Pacific/Midway, and Pacific/Saipan.

  Changes affecting time zone abbreviations

    Correct the 1992-2010 DST abbreviation in Volgograd from "MSK" to "MSD".
    (Thanks to Hank W.)

Bug: 19887183
Change-Id: I1b4bdc5ae5cf778908a77893d7f8db8a4117e1e1
2015-04-09 11:15:27 +01:00
Neil Fuller
694282b172 Merge "Update update-tzdata.py tool to generate ICU4J data jars" 2015-04-09 09:39:57 +00:00
Neil Fuller
4d3abcb033 Update update-tzdata.py tool to generate ICU4J data jars
The ICU4J changes are not necessary for use on Android (since
we use the ICU4C .dat file), but updating them ensures that
the .jars in sync with everything else and the jars are currently
required for host tests.

Change-Id: Ie56b31af87e8fbd27a6489af8287e4b6a7be6b8f
2015-04-09 09:38:31 +00:00
Christopher Ferris
41efc92e35 Use assembly memmove for all arm32 processors.
Bug: 15110993
Change-Id: Ia3dcd6b8c4032f8c72b6f2e628b635ce99667c09
2015-04-08 16:53:16 -07:00
Dan Albert
5cf46f81ea Merge "Reject changes with cleanspecs." 2015-04-08 22:52:44 +00:00
Yabin Cui
76615dae93 Provide writer preference option in rwlock.
Previous implementation of rwlock contains four atomic variables, which
is hard to maintain and change. So I make following changes in this CL:

1. Add pending flags in rwlock.state, so we don't need to synchronize
between different atomic variables. Using compare_and_swap operations
on rwlock.state is enough for all state change.

2. Add pending_lock to protect readers/writers waiting and wake up
operations. As waiting/wakeup is not performance critical, using a
lock is easier to maintain.

3. Add writer preference option.

4. Add unit tests for rwlock.

Bug: 19109156

Change-Id: Idcaa58d695ea401d64445610b465ac5cff23ec7c
2015-04-08 13:11:13 -07:00
Dan Albert
dadac10fcc Reject changes with cleanspecs.
Cleanspecs must not be removed once they have been built. This means
they can't be reverted, or reliably cherry-picked. Just skip any
changes that include them since they make such a mess.

Change-Id: I3df8d81f93651d573485de7a75ecf5c6278c0001
2015-04-06 14:22:37 -07:00
Colin Cross
90d6279802 Merge "Add Blueprints files for remaining bionic modules" into master-soong 2015-03-28 01:15:36 +00:00
Colin Cross
22d8776587 Add Blueprints files for remaining bionic modules
Change-Id: Ic9440fddb44ca1f17aad5b249535d7b96dd8d690
2015-03-27 11:14:39 -07:00
Colin Cross
51b8912253 Merge "Merge remote-tracking branch 'aosp/master' into HEAD" into master-soong 2015-03-17 19:31:44 +00:00
Colin Cross
270f2ea800 Merge remote-tracking branch 'aosp/master' into HEAD
Change-Id: Ia313444a62bcdeb676185b56ce730d0f997c8226
2015-03-17 12:30:41 -07:00
Colin Cross
7357ad0875 Merge "Update bionic Blueprints to match latest AOSP master" into master-soong 2015-03-17 00:44:29 +00:00
Colin Cross
959bc099a3 Merge remote-tracking branch 'aosp/master' into HEAD 2015-03-16 16:54:58 -07:00
Colin Cross
68a3b658b1 Update bionic Blueprints to match latest AOSP master
Change-Id: I90410ec60acfc3dcbdbcd0be6f283a90f4395643
2015-03-16 16:31:26 -07:00
Colin Cross
062d498e28 Merge "Initial bionic Blueprints files" into master-soong 2015-03-14 06:41:45 +00:00
Colin Cross
d2b8741e1b Initial bionic Blueprints files
Change-Id: Iafe8e84e0dc62e7d7c830e2c272ec92abdf6a801
2015-03-10 14:11:55 -07:00
110 changed files with 6332 additions and 1291 deletions

1
Android.bp Normal file
View File

@@ -0,0 +1 @@
subdirs = ["*"]

123
benchmarks/Android.bp Normal file
View File

@@ -0,0 +1,123 @@
//
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// Benchmarks library, usable by projects outside this directory.
// -----------------------------------------------------------------------------
benchmark_cflags = [
"-O2",
"-fno-builtin",
"-Wall",
"-Wextra",
"-Werror",
"-Wunused",
]
benchmark_cppflags = ["-std=gnu++11"]
benchmarklib_src_files = [
"Benchmark.cpp",
"utils.cpp",
"main.cpp",
]
cc_library_static {
name: "libbenchmark",
host_supported: true,
cflags: benchmark_cflags,
cppflags: benchmark_cppflags,
srcs: benchmarklib_src_files,
static_libs: ["libbase"],
export_include_dirs: ["."],
target: {
darwin: {
// Only supported on linux systems.
disabled: true,
},
},
}
// -----------------------------------------------------------------------------
// Benchmarks.
// -----------------------------------------------------------------------------
benchmark_src_files = [
"math_benchmark.cpp",
"property_benchmark.cpp",
"pthread_benchmark.cpp",
"semaphore_benchmark.cpp",
"stdio_benchmark.cpp",
"string_benchmark.cpp",
"time_benchmark.cpp",
"unistd_benchmark.cpp",
]
// Build benchmarks for the device (with bionic's .so). Run with:
// adb shell bionic-benchmarks32
// adb shell bionic-benchmarks64
cc_binary {
name: "bionic-benchmarks",
multilib: {
lib32: {
suffix: "32",
},
lib64: {
suffix: "64",
},
},
compile_multilib: "both",
cflags: benchmark_cflags,
cppflags: benchmark_cppflags,
srcs: benchmark_src_files,
static_libs: [
"libbenchmark",
"libbase",
],
}
// We don't build a static benchmark executable because it's not usually
// useful. If you're trying to run the current benchmarks on an older
// release, it's (so far at least) always because you want to measure the
// performance of the old release's libc, and a static benchmark isn't
// going to let you do that.
// Build benchmarks for the host (against glibc!). Run with:
cc_binary_host {
name: "bionic-benchmarks-glibc",
multilib: {
lib32: {
stem: "bionic-benchmarks-glibc32",
},
lib64: {
stem: "bionic-benchmarks-glibc64",
},
},
compile_multilib: "both",
cflags: benchmark_cflags,
cppflags: benchmark_cppflags,
ldflags: ["-lrt"],
srcs: benchmark_src_files,
static_libs: [
"libbenchmark",
"libbase",
],
target: {
darwin: {
// Only supported on linux systems.
disabled: true,
},
},
}

2261
libc/Android.bp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -63,14 +63,22 @@ libc_common_src_files := \
stdio/sprintf.c \
stdio/stdio.c \
stdio/stdio_ext.cpp \
stdlib/atexit.c \
stdlib/exit.c \
# Fortify implementations of libc functions.
libc_common_src_files += \
bionic/__FD_chk.cpp \
bionic/__fgets_chk.cpp \
bionic/__memchr_chk.cpp \
bionic/__memmove_chk.cpp \
bionic/__memrchr_chk.cpp \
bionic/__poll_chk.cpp \
bionic/__pread64_chk.cpp \
bionic/__pread_chk.cpp \
bionic/__read_chk.cpp \
bionic/__readlink_chk.cpp \
bionic/__readlinkat_chk.cpp \
bionic/__recvfrom_chk.cpp \
bionic/__stpcpy_chk.cpp \
bionic/__stpncpy_chk.cpp \
@@ -104,6 +112,7 @@ libc_bionic_ndk_src_files := \
bionic/clock_getcpuclockid.cpp \
bionic/clock_nanosleep.cpp \
bionic/clone.cpp \
bionic/close.cpp \
bionic/__cmsg_nxthdr.cpp \
bionic/connect.cpp \
bionic/ctype.cpp \
@@ -476,11 +485,9 @@ libc_upstream_openbsd_ndk_src_files := \
upstream-openbsd/lib/libc/stdio/wprintf.c \
upstream-openbsd/lib/libc/stdio/wscanf.c \
upstream-openbsd/lib/libc/stdio/wsetup.c \
upstream-openbsd/lib/libc/stdlib/atexit.c \
upstream-openbsd/lib/libc/stdlib/atoi.c \
upstream-openbsd/lib/libc/stdlib/atol.c \
upstream-openbsd/lib/libc/stdlib/atoll.c \
upstream-openbsd/lib/libc/stdlib/exit.c \
upstream-openbsd/lib/libc/stdlib/getenv.c \
upstream-openbsd/lib/libc/stdlib/insque.c \
upstream-openbsd/lib/libc/stdlib/lsearch.c \
@@ -820,12 +827,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libc_upstream_openbsd_ndk_src_files)
ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
# Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
LOCAL_CLANG := false
else
LOCAL_CLANG := $(use_clang)
endif
LOCAL_CLANG := $(use_clang)
LOCAL_CFLAGS := \
$(libc_common_cflags) \
@@ -863,12 +865,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libc_upstream_openbsd_src_files)
ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
# Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
LOCAL_CLANG := false
else
LOCAL_CLANG := $(use_clang)
endif
LOCAL_CLANG := $(use_clang)
LOCAL_CFLAGS := \
$(libc_common_cflags) \
@@ -908,12 +905,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES_32 := $(libc_upstream_openbsd_gdtoa_src_files_32)
LOCAL_SRC_FILES_64 := $(libc_upstream_openbsd_gdtoa_src_files_64)
ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
# Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
LOCAL_CLANG := false
else
LOCAL_CLANG := $(use_clang)
endif
LOCAL_CLANG := $(use_clang)
LOCAL_CFLAGS := \
$(libc_common_cflags) \
@@ -949,9 +941,6 @@ LOCAL_SRC_FILES := $(libc_bionic_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
# ssse3-strcmp-slm.S does not compile with Clang.
LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
# memcpy.S, memchr.S, etc. do not compile with Clang.
LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
@@ -983,9 +972,6 @@ LOCAL_SRC_FILES := $(libc_bionic_ndk_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
# ssse3-strcmp-slm.S does not compile with Clang.
LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
# memcpy.S, memchr.S, etc. do not compile with Clang.
LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
@@ -1007,7 +993,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libc_thread_atexit_impl_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) -fno-data-sections -Wframe-larger-than=2048
LOCAL_CFLAGS := $(libc_common_cflags) -Wframe-larger-than=2048
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
@@ -1038,9 +1024,6 @@ LOCAL_SRC_FILES := $(libc_pthread_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
# ssse3-strcmp-slm.S does not compile with Clang.
LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
# memcpy.S, memchr.S, etc. do not compile with Clang.
LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
@@ -1232,10 +1215,6 @@ LOCAL_WHOLE_STATIC_LIBRARIES := \
LOCAL_WHOLE_STATIC_LIBRARIES_arm := libc_aeabi
ifneq ($(MALLOC_IMPL),dlmalloc)
LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
endif
LOCAL_CXX_STL := none
LOCAL_SYSTEM_SHARED_LIBRARIES :=
@@ -1328,6 +1307,11 @@ LOCAL_MODULE := libc
LOCAL_CLANG := $(use_clang)
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
ifneq ($(MALLOC_IMPL),dlmalloc)
LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
endif
LOCAL_CXX_STL := none
LOCAL_SYSTEM_SHARED_LIBRARIES :=
LOCAL_ADDRESS_SANITIZER := false
@@ -1349,10 +1333,13 @@ LOCAL_CPPFLAGS := $(libc_common_cppflags)
LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_SRC_FILES := \
arch-common/bionic/crtbegin_so.c \
arch-common/bionic/crtbrand.S \
$(libc_arch_dynamic_src_files) \
bionic/malloc_debug_common.cpp \
bionic/libc_init_dynamic.cpp \
bionic/NetdClient.cpp \
arch-common/bionic/crtend_so.S \
LOCAL_MODULE := libc
LOCAL_CLANG := $(use_clang)
@@ -1365,6 +1352,9 @@ LOCAL_ADDITIONAL_DEPENDENCIES := \
# meaningful name resolution.
LOCAL_STRIP_MODULE := keep_symbols
# Do not pack libc.so relocations; see http://b/20645321 for details.
LOCAL_PACK_MODULE_RELOCATIONS := false
# WARNING: The only library libc.so should depend on is libdl.so! If you add other libraries,
# make sure to add -Wl,--exclude-libs=libgcc.a to the LOCAL_LDFLAGS for those libraries. This
# ensures that symbols that are pulled into those new libraries from libgcc.a are not declared
@@ -1375,6 +1365,11 @@ LOCAL_STRIP_MODULE := keep_symbols
LOCAL_SHARED_LIBRARIES := libdl
LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
ifneq ($(MALLOC_IMPL),dlmalloc)
LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
endif
LOCAL_CXX_STL := none
LOCAL_SYSTEM_SHARED_LIBRARIES :=
@@ -1392,15 +1387,15 @@ LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_arch_dynamic_src_files))
LOCAL_NO_CRT := true
LOCAL_ASFLAGS += $(libc_crt_target_cflags)
# special for arm
LOCAL_NO_CRT_arm := true
LOCAL_CFLAGS_arm += -DCRT_LEGACY_WORKAROUND
LOCAL_ASFLAGS_arm += $(libc_crt_target_cflags)
LOCAL_SRC_FILES_arm += \
arch-common/bionic/crtbegin_so.c \
arch-common/bionic/crtbrand.S \
arch-arm/bionic/atexit_legacy.c \
arch-common/bionic/crtend_so.S
arch-arm/bionic/atexit_legacy.c
LOCAL_ADDRESS_SANITIZER := false
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)

View File

@@ -95,7 +95,7 @@ ssize_t pread64(int, void*, size_t, off64_t) arm,mips,x86
ssize_t pread64|pread(int, void*, size_t, off_t) arm64,mips64,x86_64
ssize_t pwrite64(int, void*, size_t, off64_t) arm,mips,x86
ssize_t pwrite64|pwrite(int, void*, size_t, off_t) arm64,mips64,x86_64
int close(int) all
int ___close:close(int) all
pid_t __getpid:getpid() all
int munmap(void*, size_t) all
void* mremap(void*, size_t, size_t, unsigned long) all

View File

@@ -1,5 +1,4 @@
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
arch-arm/cortex-a15/bionic/memcpy.S \
arch-arm/cortex-a15/bionic/memset.S \
arch-arm/cortex-a15/bionic/stpcpy.S \
@@ -10,5 +9,8 @@ libc_bionic_src_files_arm += \
arch-arm/cortex-a15/bionic/__strcpy_chk.S \
arch-arm/cortex-a15/bionic/strlen.S \
libc_openbsd_src_files_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@@ -44,7 +44,7 @@ ENTRY_PRIVATE(MEMCPY_BASE)
/* check if buffers are aligned. If so, run arm-only version */
eor r3, r0, r1
ands r3, r3, #0x3
beq __memcpy_base_aligned
beq MEMCPY_BASE_ALIGNED
/* Check the upper size limit for Neon unaligned memory access in memcpy */
cmp r2, #224

View File

@@ -1,5 +1,4 @@
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
arch-arm/cortex-a9/bionic/memcpy.S \
arch-arm/cortex-a9/bionic/memset.S \
arch-arm/cortex-a9/bionic/stpcpy.S \
@@ -10,5 +9,8 @@ libc_bionic_src_files_arm += \
arch-arm/cortex-a9/bionic/__strcpy_chk.S \
arch-arm/cortex-a9/bionic/strlen.S \
libc_openbsd_src_files_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@@ -1,5 +1,4 @@
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
arch-arm/krait/bionic/memcpy.S \
arch-arm/krait/bionic/memset.S \
arch-arm/krait/bionic/strcmp.S \
@@ -13,5 +12,8 @@ libc_bionic_src_files_arm += \
arch-arm/cortex-a15/bionic/strcpy.S \
arch-arm/cortex-a15/bionic/strlen.S \
libc_openbsd_src_files_arm += \
upstream-openbsd/lib/libc/string/memmove.c \
libc_bionic_src_files_arm += \
arch-arm/generic/bionic/memcmp.S \
libc_bionic_src_files_arm += \
arch-arm/denver/bionic/memmove.S \

View File

@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
ENTRY(close)
ENTRY(___close)
mov ip, r7
ldr r7, =__NR_close
swi #0
@@ -11,4 +11,5 @@ ENTRY(close)
bxls lr
neg r0, r0
b __set_errno_internal
END(close)
END(___close)
.hidden ___close

View File

@@ -67,3 +67,4 @@ __asm__ (
#include "../../arch-common/bionic/__dso_handle.h"
#include "../../arch-common/bionic/atexit.h"
#include "../../arch-common/bionic/pthread_atfork.h"

View File

@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
ENTRY(close)
ENTRY(___close)
mov x8, __NR_close
svc #0
@@ -11,4 +11,5 @@ ENTRY(close)
b.hi __set_errno_internal
ret
END(close)
END(___close)
.hidden ___close

View File

@@ -59,6 +59,7 @@ void _start() {
#include "__dso_handle.h"
#include "atexit.h"
#include "pthread_atfork.h"
#ifdef __i386__
# include "../../arch-x86/bionic/__stack_chk_fail_local.h"
#endif

View File

@@ -56,6 +56,7 @@ void __on_dlclose() {
# include "__dso_handle_so.h"
# include "atexit.h"
#endif
#include "pthread_atfork.h"
#ifdef __i386__
# include "../../arch-x86/bionic/__stack_chk_fail_local.h"
#endif

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern void* __dso_handle;
extern int __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void), void* dso);
#ifndef _LIBC
// Libc used to export this in previous versions, therefore it needs
// to remain global for binary compatibility.
__attribute__ ((visibility ("hidden")))
#endif
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) {
return __register_atfork(prepare, parent, child, &__dso_handle);
}

View File

@@ -92,3 +92,4 @@ __asm__ (
#include "../../arch-common/bionic/__dso_handle.h"
#include "../../arch-common/bionic/atexit.h"
#include "../../arch-common/bionic/pthread_atfork.h"

View File

@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
ENTRY(close)
ENTRY(___close)
.set noreorder
.cpload t9
li v0, __NR_close
@@ -16,4 +16,5 @@ ENTRY(close)
j t9
nop
.set reorder
END(close)
END(___close)
.hidden ___close

View File

@@ -92,3 +92,4 @@ __asm__ (
#include "../../arch-common/bionic/__dso_handle.h"
#include "../../arch-common/bionic/atexit.h"
#include "../../arch-common/bionic/pthread_atfork.h"

View File

@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
ENTRY(close)
ENTRY(___close)
.set push
.set noreorder
li v0, __NR_close
@@ -22,4 +22,5 @@ ENTRY(close)
j t9
move ra, t0
.set pop
END(close)
END(___close)
.hidden ___close

View File

@@ -3,8 +3,14 @@
// pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg);
ENTRY(__bionic_clone)
pushl %ebx
.cfi_adjust_cfa_offset 4
.cfi_rel_offset ebx, 0
pushl %esi
.cfi_adjust_cfa_offset 4
.cfi_rel_offset esi, 0
pushl %edi
.cfi_adjust_cfa_offset 4
.cfi_rel_offset edi, 0
# Load system call arguments into registers.
movl 16(%esp), %ebx # flags
@@ -46,8 +52,14 @@ ENTRY(__bionic_clone)
# We're the parent; nothing to do.
.L_bc_return:
popl %edi
.cfi_adjust_cfa_offset -4
.cfi_restore edi
popl %esi
.cfi_adjust_cfa_offset -4
.cfi_restore esi
popl %ebx
.cfi_adjust_cfa_offset -4
.cfi_restore ebx
ret
END(__bionic_clone)
.hidden __bionic_clone

View File

@@ -15,9 +15,17 @@
ENTRY(syscall)
# Push the callee save registers.
push %ebx
.cfi_adjust_cfa_offset 4
.cfi_rel_offset ebx, 0
push %esi
.cfi_adjust_cfa_offset 4
.cfi_rel_offset esi, 0
push %edi
.cfi_adjust_cfa_offset 4
.cfi_rel_offset edi, 0
push %ebp
.cfi_adjust_cfa_offset 4
.cfi_rel_offset ebp, 0
# Load all the arguments from the calling frame.
# (Not all will be valid, depending on the syscall.)
@@ -43,8 +51,16 @@ ENTRY(syscall)
1:
# Restore the callee save registers.
pop %ebp
.cfi_adjust_cfa_offset -4
.cfi_restore ebp
pop %edi
.cfi_adjust_cfa_offset -4
.cfi_restore edi
pop %esi
.cfi_adjust_cfa_offset -4
.cfi_restore esi
pop %ebx
.cfi_adjust_cfa_offset -4
.cfi_restore ebx
ret
END(syscall)

View File

@@ -32,6 +32,8 @@
ENTRY(vfork)
popl %ecx // Grab the return address.
.cfi_adjust_cfa_offset 4
.cfi_rel_offset ecx, 0
movl $__NR_vfork, %eax
int $0x80
cmpl $-MAX_ERRNO, %eax

View File

@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
ENTRY(close)
ENTRY(___close)
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_rel_offset ebx, 0
@@ -18,4 +18,5 @@ ENTRY(close)
1:
popl %ebx
ret
END(close)
END(___close)
.hidden ___close

View File

@@ -1897,8 +1897,8 @@ L(strcmp_exitz):
.p2align 4
L(Byte0):
movzx (%rsi), %ecx
movzx (%rdi), %eax
movzbl (%rsi), %ecx
movzbl (%rdi), %eax
sub %ecx, %eax
ret

View File

@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
ENTRY(close)
ENTRY(___close)
movl $__NR_close, %eax
syscall
cmpq $-MAX_ERRNO, %rax
@@ -12,4 +12,5 @@ ENTRY(close)
call __set_errno_internal
1:
ret
END(close)
END(___close)
.hidden ___close

View File

@@ -22,7 +22,7 @@ struct thread_local_dtor {
thread_local_dtor* next;
};
__thread thread_local_dtor* thread_local_dtors = nullptr;
static __thread thread_local_dtor* thread_local_dtors = nullptr;
extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
thread_local_dtor* dtor = new thread_local_dtor();

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <string.h>
#include "private/libc_logging.h"
extern "C" void* __memchr_chk(const void* s, int c, size_t n, size_t buf_size) {
if (__predict_false(n > buf_size)) {
__fortify_chk_fail("memchr: prevented read past end of buffer", 0);
}
return memchr(s, c, n);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <string.h>
#include "private/libc_logging.h"
extern "C" void* __memrchr_chk(const void* s, int c, size_t n, size_t buf_size) {
if (__predict_false(n > buf_size)) {
__fortify_chk_fail("memrchr: prevented read past end of buffer", 0);
}
return memrchr(s, c, n);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <unistd.h>
#include "private/libc_logging.h"
extern "C" ssize_t __pread64_chk(int fd, void* buf, size_t count, off64_t offset, size_t buf_size) {
if (__predict_false(count > buf_size)) {
__fortify_chk_fail("pread64: prevented write past end of buffer", 0);
}
if (__predict_false(count > SSIZE_MAX)) {
__fortify_chk_fail("pread64: count > SSIZE_MAX", 0);
}
return pread64(fd, buf, count, offset);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <unistd.h>
#include "private/libc_logging.h"
extern "C" ssize_t __pread_chk(int fd, void* buf, size_t count, off_t offset, size_t buf_size) {
if (__predict_false(count > buf_size)) {
__fortify_chk_fail("pread: prevented write past end of buffer", 0);
}
if (__predict_false(count > SSIZE_MAX)) {
__fortify_chk_fail("pread: count > SSIZE_MAX", 0);
}
return pread(fd, buf, count, offset);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <unistd.h>
#include "private/libc_logging.h"
extern "C" ssize_t __readlink_chk(const char* path, char* buf, size_t size, size_t buf_size) {
if (__predict_false(size > buf_size)) {
__fortify_chk_fail("readlink: prevented write past end of buffer", 0);
}
if (__predict_false(size > SSIZE_MAX)) {
__fortify_chk_fail("readlink: size > SSIZE_MAX", 0);
}
return readlink(path, buf, size);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <unistd.h>
#include "private/libc_logging.h"
extern "C" ssize_t __readlinkat_chk(int dirfd, const char* path, char* buf, size_t size, size_t buf_size) {
if (__predict_false(size > buf_size)) {
__fortify_chk_fail("readlinkat: prevented write past end of buffer", 0);
}
if (__predict_false(size > SSIZE_MAX)) {
__fortify_chk_fail("readlinkat: size > SSIZE_MAX", 0);
}
return readlinkat(dirfd, path, buf, size);
}

56
libc/bionic/close.cpp Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <unistd.h>
extern "C" int ___close(int);
int close(int fd) {
int rc = ___close(fd);
if (rc == -1 && errno == EINTR) {
// POSIX says that if close returns with EINTR, the fd must not be closed.
// Linus disagrees: http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
// The future POSIX solution is posix_close (http://austingroupbugs.net/view.php?id=529),
// with the state after EINTR being undefined, and EINPROGRESS for the case where close
// was interrupted by a signal but the file descriptor was actually closed.
// My concern with that future behavior is that it breaks existing code that assumes
// that close only returns -1 if it failed. Unlike other system calls, I have real
// difficulty even imagining a caller that would need to know that close was interrupted
// but succeeded. So returning EINTR is wrong (because Linux always closes) and EINPROGRESS
// is harmful because callers need to be rewritten to understand that EINPROGRESS isn't
// actually a failure, but will be reported as one.
// We don't restore errno because that would incur a cost (the TLS read) for every caller.
// Since callers don't know ahead of time whether close will legitimately fail, they need
// to have stashed the old errno value anyway if they plan on using it afterwards, so
// us clobbering errno here doesn't change anything in that respect.
return 0;
}
return rc;
}

View File

@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>

View File

@@ -56,6 +56,7 @@ enum AndroidEventLogType {
EVENT_TYPE_LONG = 1,
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
EVENT_TYPE_FLOAT = 4,
};
struct BufferOutputStream {

View File

@@ -26,14 +26,15 @@
* SUCH DAMAGE.
*/
#include "pthread_internal.h"
#include "private/bionic_futex.h"
#include "private/kernel_sigset_t.h"
#include <errno.h>
#include <malloc.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
// System calls.
extern "C" int __rt_sigtimedwait(const sigset_t*, siginfo_t*, const struct timespec*, size_t);
@@ -59,11 +60,11 @@ struct PosixTimer {
int sigev_notify;
// These fields are only needed for a SIGEV_THREAD timer.
// The fields below are only needed for a SIGEV_THREAD timer.
pthread_t callback_thread;
void (*callback)(sigval_t);
sigval_t callback_argument;
volatile bool armed;
atomic_bool deleted; // Set when the timer is deleted, to prevent further calling of callback.
};
static __kernel_timer_t to_kernel_timer_id(timer_t timer) {
@@ -85,8 +86,13 @@ static void* __timer_thread_start(void* arg) {
continue;
}
if (si.si_code == SI_TIMER && timer->armed) {
if (si.si_code == SI_TIMER) {
// This signal was sent because a timer fired, so call the callback.
// All events to the callback will be ignored when the timer is deleted.
if (atomic_load(&timer->deleted) == true) {
continue;
}
timer->callback(timer->callback_argument);
} else if (si.si_code == SI_TKILL) {
// This signal was sent because someone wants us to exit.
@@ -97,9 +103,7 @@ static void* __timer_thread_start(void* arg) {
}
static void __timer_thread_stop(PosixTimer* timer) {
// Immediately mark the timer as disarmed so even if some events
// continue to happen, the callback won't be called.
timer->armed = false;
atomic_store(&timer->deleted, true);
pthread_kill(timer->callback_thread, TIMER_SIGNAL);
}
@@ -126,7 +130,7 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) {
// Otherwise, this must be SIGEV_THREAD timer...
timer->callback = evp->sigev_notify_function;
timer->callback_argument = evp->sigev_value;
timer->armed = false;
atomic_init(&timer->deleted, false);
// Check arguments that the kernel doesn't care about but we do.
if (timer->callback == NULL) {
@@ -170,10 +174,10 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) {
return -1;
}
// Give the thread a meaningful name.
// Give the thread a specific meaningful name.
// It can't do this itself because the kernel timer isn't created until after it's running.
char name[32];
snprintf(name, sizeof(name), "POSIX interval timer %d", to_kernel_timer_id(timer));
char name[16]; // 16 is the kernel-imposed limit.
snprintf(name, sizeof(name), "POSIX timer %d", to_kernel_timer_id(timer));
pthread_setname_np(timer->callback_thread, name);
*timer_id = timer;
@@ -199,25 +203,19 @@ int timer_delete(timer_t id) {
return 0;
}
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_gettime.html
int timer_gettime(timer_t id, itimerspec* ts) {
return __timer_gettime(to_kernel_timer_id(id), ts);
}
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_settime.html
// When using timer_settime to disarm a repeatable SIGEV_THREAD timer with a very small
// period (like below 1ms), the kernel may continue to send events to the callback thread
// for a few extra times. This behavior is fine because in POSIX standard: The effect of
// disarming or resetting a timer with pending expiration notifications is unspecified.
int timer_settime(timer_t id, int flags, const itimerspec* ts, itimerspec* ots) {
PosixTimer* timer= reinterpret_cast<PosixTimer*>(id);
int rc = __timer_settime(timer->kernel_timer_id, flags, ts, ots);
if (rc == 0) {
// Mark the timer as either being armed or disarmed. This avoids the
// callback being called after the disarm for SIGEV_THREAD timers only.
if (ts->it_value.tv_sec != 0 || ts->it_value.tv_nsec != 0) {
timer->armed = true;
} else {
timer->armed = false;
}
}
return rc;
return __timer_settime(timer->kernel_timer_id, flags, ts, ots);
}
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html

View File

@@ -30,6 +30,8 @@
#include <pthread.h>
#include <stdlib.h>
#include "private/bionic_macros.h"
struct atfork_t {
atfork_t* next;
atfork_t* prev;
@@ -37,79 +39,143 @@ struct atfork_t {
void (*prepare)(void);
void (*child)(void);
void (*parent)(void);
void* dso_handle;
};
struct atfork_list_t {
atfork_t* first;
atfork_t* last;
class atfork_list_t {
public:
atfork_list_t() : first_(nullptr), last_(nullptr) {}
template<typename F>
void walk_forward(F f) {
for (atfork_t* it = first_; it != nullptr; it = it->next) {
f(it);
}
}
template<typename F>
void walk_backwards(F f) {
for (atfork_t* it = last_; it != nullptr; it = it->prev) {
f(it);
}
}
void push_back(atfork_t* entry) {
entry->next = nullptr;
entry->prev = last_;
if (entry->prev != nullptr) {
entry->prev->next = entry;
}
if (first_ == nullptr) {
first_ = entry;
}
last_ = entry;
}
template<typename F>
void remove_if(F predicate) {
atfork_t* it = first_;
while (it != nullptr) {
if (predicate(it)) {
atfork_t* entry = it;
it = it->next;
remove(entry);
} else {
it = it->next;
}
}
}
private:
void remove(atfork_t* entry) {
if (entry->prev != nullptr) {
entry->prev->next = entry->next;
} else {
first_ = entry->next;
}
if (entry->next != nullptr) {
entry->next->prev = entry->prev;
} else {
last_ = entry->prev;
}
free(entry);
}
atfork_t* first_;
atfork_t* last_;
DISALLOW_COPY_AND_ASSIGN(atfork_list_t);
};
static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static atfork_list_t g_atfork_list = { NULL, NULL };
static atfork_list_t g_atfork_list;
void __bionic_atfork_run_prepare() {
// We lock the atfork list here, unlock it in the parent, and reset it in the child.
// This ensures that nobody can modify the handler array between the calls
// to the prepare and parent/child handlers.
//
// TODO: If a handler tries to mutate the list, they'll block. We should probably copy
// the list before forking, and have prepare, parent, and child all work on the consistent copy.
pthread_mutex_lock(&g_atfork_list_mutex);
// Call pthread_atfork() prepare handlers. POSIX states that the prepare
// handlers should be called in the reverse order of the parent/child
// handlers, so we iterate backwards.
for (atfork_t* it = g_atfork_list.last; it != NULL; it = it->prev) {
if (it->prepare != NULL) {
g_atfork_list.walk_backwards([](atfork_t* it) {
if (it->prepare != nullptr) {
it->prepare();
}
}
});
}
void __bionic_atfork_run_child() {
for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) {
if (it->child != NULL) {
g_atfork_list.walk_forward([](atfork_t* it) {
if (it->child != nullptr) {
it->child();
}
}
});
g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
}
void __bionic_atfork_run_parent() {
for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) {
if (it->parent != NULL) {
g_atfork_list.walk_forward([](atfork_t* it) {
if (it->parent != nullptr) {
it->parent();
}
}
});
pthread_mutex_unlock(&g_atfork_list_mutex);
}
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)) {
// __register_atfork is the name used by glibc
extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
void(*child)(void), void* dso) {
atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t)));
if (entry == NULL) {
if (entry == nullptr) {
return ENOMEM;
}
entry->prepare = prepare;
entry->parent = parent;
entry->child = child;
entry->dso_handle = dso;
pthread_mutex_lock(&g_atfork_list_mutex);
// Append 'entry' to the list.
entry->next = NULL;
entry->prev = g_atfork_list.last;
if (entry->prev != NULL) {
entry->prev->next = entry;
}
if (g_atfork_list.first == NULL) {
g_atfork_list.first = entry;
}
g_atfork_list.last = entry;
g_atfork_list.push_back(entry);
pthread_mutex_unlock(&g_atfork_list_mutex);
return 0;
}
extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) {
pthread_mutex_lock(&g_atfork_list_mutex);
g_atfork_list.remove_if([&](const atfork_t* entry) {
return entry->dso_handle == dso;
});
pthread_mutex_unlock(&g_atfork_list_mutex);
}

View File

@@ -57,8 +57,15 @@ static inline bool SeqOfKeyInUse(uintptr_t seq) {
return seq & (1 << SEQ_KEY_IN_USE_BIT);
}
#define KEY_VALID_FLAG (1 << 31)
static_assert(sizeof(pthread_key_t) == sizeof(int) && static_cast<pthread_key_t>(-1) < 0,
"pthread_key_t should be typedef to int");
static inline bool KeyInValidRange(pthread_key_t key) {
return key >= 0 && key < BIONIC_PTHREAD_KEY_COUNT;
// key < 0 means bit 31 is set.
// Then key < (2^31 | BIONIC_PTHREAD_KEY_COUNT) means the index part of key < BIONIC_PTHREAD_KEY_COUNT.
return (key < (KEY_VALID_FLAG | BIONIC_PTHREAD_KEY_COUNT));
}
// Called from pthread_exit() to remove all pthread keys. This must call the destructor of
@@ -114,7 +121,7 @@ int pthread_key_create(pthread_key_t* key, void (*key_destructor)(void*)) {
while (!SeqOfKeyInUse(seq)) {
if (atomic_compare_exchange_weak(&key_map[i].seq, &seq, seq + SEQ_INCREMENT_STEP)) {
atomic_store(&key_map[i].key_destructor, reinterpret_cast<uintptr_t>(key_destructor));
*key = i;
*key = i | KEY_VALID_FLAG;
return 0;
}
}
@@ -127,9 +134,10 @@ int pthread_key_create(pthread_key_t* key, void (*key_destructor)(void*)) {
// responsibility of the caller to properly dispose of the corresponding data
// and resources, using any means it finds suitable.
int pthread_key_delete(pthread_key_t key) {
if (!KeyInValidRange(key)) {
if (__predict_false(!KeyInValidRange(key))) {
return EINVAL;
}
key &= ~KEY_VALID_FLAG;
// Increase seq to invalidate values in all threads.
uintptr_t seq = atomic_load_explicit(&key_map[key].seq, memory_order_relaxed);
if (SeqOfKeyInUse(seq)) {
@@ -141,9 +149,10 @@ int pthread_key_delete(pthread_key_t key) {
}
void* pthread_getspecific(pthread_key_t key) {
if (!KeyInValidRange(key)) {
if (__predict_false(!KeyInValidRange(key))) {
return NULL;
}
key &= ~KEY_VALID_FLAG;
uintptr_t seq = atomic_load_explicit(&key_map[key].seq, memory_order_relaxed);
pthread_key_data_t* data = &(__get_thread()->key_data[key]);
// It is user's responsibility to synchornize between the creation and use of pthread keys,
@@ -151,16 +160,19 @@ void* pthread_getspecific(pthread_key_t key) {
if (__predict_true(SeqOfKeyInUse(seq) && data->seq == seq)) {
return data->data;
}
// We arrive here when current thread holds the seq of an deleted pthread key. So the
// data is for the deleted pthread key, and should be cleared.
data->data = NULL;
return NULL;
}
int pthread_setspecific(pthread_key_t key, const void* ptr) {
if (!KeyInValidRange(key)) {
if (__predict_false(!KeyInValidRange(key))) {
return EINVAL;
}
key &= ~KEY_VALID_FLAG;
uintptr_t seq = atomic_load_explicit(&key_map[key].seq, memory_order_relaxed);
if (SeqOfKeyInUse(seq)) {
if (__predict_true(SeqOfKeyInUse(seq))) {
pthread_key_data_t* data = &(__get_thread()->key_data[key]);
data->seq = seq;
data->data = const_cast<void*>(ptr);

View File

@@ -28,9 +28,11 @@
#include <errno.h>
#include <stdatomic.h>
#include <string.h>
#include "pthread_internal.h"
#include "private/bionic_futex.h"
#include "private/bionic_lock.h"
#include "private/bionic_time_conversions.h"
/* Technical note:
@@ -53,18 +55,39 @@
* - This implementation will return EDEADLK in "write after write" and "read after
* write" cases and will deadlock in write after read case.
*
* TODO: As it stands now, pending_readers and pending_writers could be merged into a
* a single waiters variable. Keeping them separate adds a bit of clarity and keeps
* the door open for a writer-biased implementation.
*
*/
#define RWLOCKATTR_DEFAULT 0
#define RWLOCKATTR_SHARED_MASK 0x0010
// A rwlockattr is implemented as a 32-bit integer which has following fields:
// bits name description
// 1 rwlock_kind have rwlock preference like PTHREAD_RWLOCK_PREFER_READER_NP.
// 0 process_shared set to 1 if the rwlock is shared between processes.
#define RWLOCKATTR_PSHARED_SHIFT 0
#define RWLOCKATTR_KIND_SHIFT 1
#define RWLOCKATTR_PSHARED_MASK 1
#define RWLOCKATTR_KIND_MASK 2
#define RWLOCKATTR_RESERVED_MASK (~3)
static inline __always_inline __always_inline bool __rwlockattr_getpshared(const pthread_rwlockattr_t* attr) {
return (*attr & RWLOCKATTR_PSHARED_MASK) >> RWLOCKATTR_PSHARED_SHIFT;
}
static inline __always_inline __always_inline void __rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared) {
*attr = (*attr & ~RWLOCKATTR_PSHARED_MASK) | (pshared << RWLOCKATTR_PSHARED_SHIFT);
}
static inline __always_inline int __rwlockattr_getkind(const pthread_rwlockattr_t* attr) {
return (*attr & RWLOCKATTR_KIND_MASK) >> RWLOCKATTR_KIND_SHIFT;
}
static inline __always_inline void __rwlockattr_setkind(pthread_rwlockattr_t* attr, int kind) {
*attr = (*attr & ~RWLOCKATTR_KIND_MASK) | (kind << RWLOCKATTR_KIND_SHIFT);
}
int pthread_rwlockattr_init(pthread_rwlockattr_t* attr) {
*attr = PTHREAD_PROCESS_PRIVATE;
*attr = 0;
return 0;
}
@@ -73,40 +96,121 @@ int pthread_rwlockattr_destroy(pthread_rwlockattr_t* attr) {
return 0;
}
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t* attr, int* pshared) {
if (__rwlockattr_getpshared(attr)) {
*pshared = PTHREAD_PROCESS_SHARED;
} else {
*pshared = PTHREAD_PROCESS_PRIVATE;
}
return 0;
}
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared) {
switch (pshared) {
case PTHREAD_PROCESS_PRIVATE:
__rwlockattr_setpshared(attr, 0);
return 0;
case PTHREAD_PROCESS_SHARED:
*attr = pshared;
__rwlockattr_setpshared(attr, 1);
return 0;
default:
return EINVAL;
}
}
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t* attr, int* pshared) {
*pshared = *attr;
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t* attr, int* pref) {
*pref = __rwlockattr_getkind(attr);
return 0;
}
struct pthread_rwlock_internal_t {
atomic_int state; // 0=unlock, -1=writer lock, +n=reader lock
atomic_int writer_thread_id;
atomic_uint pending_readers;
atomic_uint pending_writers;
int32_t attr;
bool process_shared() const {
return attr == PTHREAD_PROCESS_SHARED;
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr, int pref) {
switch (pref) {
case PTHREAD_RWLOCK_PREFER_READER_NP: // Fall through.
case PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP:
__rwlockattr_setkind(attr, pref);
return 0;
default:
return EINVAL;
}
}
// A rwlock state is implemented as a 32-bit integer which has following rules:
// bits name description
// 31 owned_by_writer_flag set to 1 if the lock is owned by a writer now.
// 30-2 reader_count the count of readers holding the lock.
// 1 have_pending_writers set to 1 if having pending writers.
// 0 have_pending_readers set to 1 if having pending readers.
#define STATE_HAVE_PENDING_READERS_SHIFT 0
#define STATE_HAVE_PENDING_WRITERS_SHIFT 1
#define STATE_READER_COUNT_SHIFT 2
#define STATE_OWNED_BY_WRITER_SHIFT 31
#define STATE_HAVE_PENDING_READERS_FLAG (1 << STATE_HAVE_PENDING_READERS_SHIFT)
#define STATE_HAVE_PENDING_WRITERS_FLAG (1 << STATE_HAVE_PENDING_WRITERS_SHIFT)
#define STATE_READER_COUNT_CHANGE_STEP (1 << STATE_READER_COUNT_SHIFT)
#define STATE_OWNED_BY_WRITER_FLAG (1 << STATE_OWNED_BY_WRITER_SHIFT)
#define STATE_HAVE_PENDING_READERS_OR_WRITERS_FLAG \
(STATE_HAVE_PENDING_READERS_FLAG | STATE_HAVE_PENDING_WRITERS_FLAG)
struct pthread_rwlock_internal_t {
atomic_int state;
atomic_int writer_tid;
bool pshared;
bool writer_nonrecursive_preferred;
uint16_t __pad;
// When a reader thread plans to suspend on the rwlock, it will add STATE_HAVE_PENDING_READERS_FLAG
// in state, increase pending_reader_count, and wait on pending_reader_wakeup_serial. After woken
// up, the reader thread decreases pending_reader_count, and the last pending reader thread should
// remove STATE_HAVE_PENDING_READERS_FLAG in state. A pending writer thread works in a similar way,
// except that it uses flag and members for writer threads.
Lock pending_lock; // All pending members below are protected by pending_lock.
uint32_t pending_reader_count; // Count of pending reader threads.
uint32_t pending_writer_count; // Count of pending writer threads.
uint32_t pending_reader_wakeup_serial; // Pending reader threads wait on this address by futex_wait.
uint32_t pending_writer_wakeup_serial; // Pending writer threads wait on this address by futex_wait.
#if defined(__LP64__)
char __reserved[36];
#else
char __reserved[20];
#else
char __reserved[4];
#endif
};
static inline __always_inline bool __state_owned_by_writer(int state) {
return state < 0;
}
static inline __always_inline bool __state_owned_by_readers(int state) {
// If state >= 0, the owned_by_writer_flag is not set.
// And if state >= STATE_READER_COUNT_CHANGE_STEP, the reader_count field is not empty.
return state >= STATE_READER_COUNT_CHANGE_STEP;
}
static inline __always_inline bool __state_owned_by_readers_or_writer(int state) {
return state < 0 || state >= STATE_READER_COUNT_CHANGE_STEP;
}
static inline __always_inline int __state_add_writer_flag(int state) {
return state | STATE_OWNED_BY_WRITER_FLAG;
}
static inline __always_inline bool __state_is_last_reader(int state) {
return (state >> STATE_READER_COUNT_SHIFT) == 1;
}
static inline __always_inline bool __state_have_pending_writers(int state) {
return state & STATE_HAVE_PENDING_WRITERS_FLAG;
}
static inline __always_inline bool __state_have_pending_readers_or_writers(int state) {
return state & STATE_HAVE_PENDING_READERS_OR_WRITERS_FLAG;
}
static_assert(sizeof(pthread_rwlock_t) == sizeof(pthread_rwlock_internal_t),
"pthread_rwlock_t should actually be pthread_rwlock_internal_t in implementation.");
@@ -115,31 +219,35 @@ static_assert(sizeof(pthread_rwlock_t) == sizeof(pthread_rwlock_internal_t),
static_assert(alignof(pthread_rwlock_t) == 4,
"pthread_rwlock_t should fulfill the alignment requirement of pthread_rwlock_internal_t.");
static inline pthread_rwlock_internal_t* __get_internal_rwlock(pthread_rwlock_t* rwlock_interface) {
static inline __always_inline pthread_rwlock_internal_t* __get_internal_rwlock(pthread_rwlock_t* rwlock_interface) {
return reinterpret_cast<pthread_rwlock_internal_t*>(rwlock_interface);
}
int pthread_rwlock_init(pthread_rwlock_t* rwlock_interface, const pthread_rwlockattr_t* attr) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
if (__predict_true(attr == NULL)) {
rwlock->attr = 0;
} else {
switch (*attr) {
case PTHREAD_PROCESS_SHARED:
case PTHREAD_PROCESS_PRIVATE:
rwlock->attr= *attr;
memset(rwlock, 0, sizeof(pthread_rwlock_internal_t));
if (__predict_false(attr != NULL)) {
rwlock->pshared = __rwlockattr_getpshared(attr);
int kind = __rwlockattr_getkind(attr);
switch (kind) {
case PTHREAD_RWLOCK_PREFER_READER_NP:
rwlock->writer_nonrecursive_preferred = false;
break;
case PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP:
rwlock->writer_nonrecursive_preferred = true;
break;
default:
return EINVAL;
}
if ((*attr & RWLOCKATTR_RESERVED_MASK) != 0) {
return EINVAL;
}
}
atomic_init(&rwlock->state, 0);
atomic_init(&rwlock->writer_thread_id, 0);
atomic_init(&rwlock->pending_readers, 0);
atomic_init(&rwlock->pending_writers, 0);
rwlock->pending_lock.init(rwlock->pshared);
return 0;
}
@@ -152,105 +260,173 @@ int pthread_rwlock_destroy(pthread_rwlock_t* rwlock_interface) {
return 0;
}
static inline __always_inline bool __can_acquire_read_lock(int old_state,
bool writer_nonrecursive_preferred) {
// If writer is preferred with nonrecursive reader, we prevent further readers from acquiring
// the lock when there are writers waiting for the lock.
bool cannot_apply = __state_owned_by_writer(old_state) ||
(writer_nonrecursive_preferred && __state_have_pending_writers(old_state));
return !cannot_apply;
}
static inline __always_inline int __pthread_rwlock_tryrdlock(pthread_rwlock_internal_t* rwlock) {
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
while (__predict_true(__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred))) {
int new_state = old_state + STATE_READER_COUNT_CHANGE_STEP;
if (__predict_false(!__state_owned_by_readers(new_state))) { // Happens when reader count overflows.
return EAGAIN;
}
if (__predict_true(atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state, new_state,
memory_order_acquire, memory_order_relaxed))) {
return 0;
}
}
return EBUSY;
}
static int __pthread_rwlock_timedrdlock(pthread_rwlock_internal_t* rwlock,
const timespec* abs_timeout_or_null) {
if (__predict_false(__get_thread()->tid == atomic_load_explicit(&rwlock->writer_thread_id,
memory_order_relaxed))) {
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) {
return EDEADLK;
}
while (true) {
int ret = __pthread_rwlock_tryrdlock(rwlock);
if (ret == 0 || ret == EAGAIN) {
return ret;
}
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
if (__predict_true(old_state >= 0)) {
if (atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state, old_state + 1,
memory_order_acquire, memory_order_relaxed)) {
return 0;
}
} else {
timespec ts;
timespec* rel_timeout = NULL;
if (__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
continue;
}
if (abs_timeout_or_null != NULL) {
rel_timeout = &ts;
if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
return ETIMEDOUT;
}
}
timespec ts;
timespec* rel_timeout = NULL;
// To avoid losing wake ups, the pending_readers increment should be observed before
// futex_wait by all threads. A seq_cst fence instead of a seq_cst operation is used
// here. Because only a seq_cst fence can ensure sequential consistency for non-atomic
// operations in futex_wait.
atomic_fetch_add_explicit(&rwlock->pending_readers, 1, memory_order_relaxed);
atomic_thread_fence(memory_order_seq_cst);
int ret = __futex_wait_ex(&rwlock->state, rwlock->process_shared(), old_state,
rel_timeout);
atomic_fetch_sub_explicit(&rwlock->pending_readers, 1, memory_order_relaxed);
if (ret == -ETIMEDOUT) {
if (abs_timeout_or_null != NULL) {
rel_timeout = &ts;
if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
return ETIMEDOUT;
}
}
rwlock->pending_lock.lock();
rwlock->pending_reader_count++;
// We rely on the fact that all atomic exchange operations on the same object (here it is
// rwlock->state) always appear to occur in a single total order. If the pending flag is added
// before unlocking, the unlocking thread will wakeup the waiter. Otherwise, we will see the
// state is unlocked and will not wait anymore.
old_state = atomic_fetch_or_explicit(&rwlock->state, STATE_HAVE_PENDING_READERS_FLAG,
memory_order_relaxed);
int old_serial = rwlock->pending_reader_wakeup_serial;
rwlock->pending_lock.unlock();
int futex_ret = 0;
if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
futex_ret = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
old_serial, rel_timeout);
}
rwlock->pending_lock.lock();
rwlock->pending_reader_count--;
if (rwlock->pending_reader_count == 0) {
atomic_fetch_and_explicit(&rwlock->state, ~STATE_HAVE_PENDING_READERS_FLAG,
memory_order_relaxed);
}
rwlock->pending_lock.unlock();
if (futex_ret == -ETIMEDOUT) {
return ETIMEDOUT;
}
}
}
static inline __always_inline bool __can_acquire_write_lock(int old_state) {
return !__state_owned_by_readers_or_writer(old_state);
}
static inline __always_inline int __pthread_rwlock_trywrlock(pthread_rwlock_internal_t* rwlock) {
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
while (__predict_true(__can_acquire_write_lock(old_state))) {
if (__predict_true(atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state,
__state_add_writer_flag(old_state), memory_order_acquire, memory_order_relaxed))) {
atomic_store_explicit(&rwlock->writer_tid, __get_thread()->tid, memory_order_relaxed);
return 0;
}
}
return EBUSY;
}
static int __pthread_rwlock_timedwrlock(pthread_rwlock_internal_t* rwlock,
const timespec* abs_timeout_or_null) {
if (__predict_false(__get_thread()->tid == atomic_load_explicit(&rwlock->writer_thread_id,
memory_order_relaxed))) {
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) {
return EDEADLK;
}
while (true) {
int ret = __pthread_rwlock_trywrlock(rwlock);
if (ret == 0) {
return ret;
}
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
if (__predict_true(old_state == 0)) {
if (atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state, -1,
memory_order_acquire, memory_order_relaxed)) {
// writer_thread_id is protected by rwlock and can only be modified in rwlock write
// owner thread. Other threads may read it for EDEADLK error checking, atomic operation
// is safe enough for it.
atomic_store_explicit(&rwlock->writer_thread_id, __get_thread()->tid, memory_order_relaxed);
return 0;
}
} else {
timespec ts;
timespec* rel_timeout = NULL;
if (__can_acquire_write_lock(old_state)) {
continue;
}
if (abs_timeout_or_null != NULL) {
rel_timeout = &ts;
if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
return ETIMEDOUT;
}
}
timespec ts;
timespec* rel_timeout = NULL;
// To avoid losing wake ups, the pending_writers increment should be observed before
// futex_wait by all threads. A seq_cst fence instead of a seq_cst operation is used
// here. Because only a seq_cst fence can ensure sequential consistency for non-atomic
// operations in futex_wait.
atomic_fetch_add_explicit(&rwlock->pending_writers, 1, memory_order_relaxed);
atomic_thread_fence(memory_order_seq_cst);
int ret = __futex_wait_ex(&rwlock->state, rwlock->process_shared(), old_state,
rel_timeout);
atomic_fetch_sub_explicit(&rwlock->pending_writers, 1, memory_order_relaxed);
if (ret == -ETIMEDOUT) {
if (abs_timeout_or_null != NULL) {
rel_timeout = &ts;
if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
return ETIMEDOUT;
}
}
rwlock->pending_lock.lock();
rwlock->pending_writer_count++;
old_state = atomic_fetch_or_explicit(&rwlock->state, STATE_HAVE_PENDING_WRITERS_FLAG,
memory_order_relaxed);
int old_serial = rwlock->pending_writer_wakeup_serial;
rwlock->pending_lock.unlock();
int futex_ret = 0;
if (!__can_acquire_write_lock(old_state)) {
futex_ret = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
old_serial, rel_timeout);
}
rwlock->pending_lock.lock();
rwlock->pending_writer_count--;
if (rwlock->pending_writer_count == 0) {
atomic_fetch_and_explicit(&rwlock->state, ~STATE_HAVE_PENDING_WRITERS_FLAG,
memory_order_relaxed);
}
rwlock->pending_lock.unlock();
if (futex_ret == -ETIMEDOUT) {
return ETIMEDOUT;
}
}
}
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock_interface) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
// Avoid slowing down fast path of rdlock.
if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) {
return 0;
}
return __pthread_rwlock_timedrdlock(rwlock, NULL);
}
@@ -261,19 +437,15 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespe
}
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock_interface) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
while (old_state >= 0 && !atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state,
old_state + 1, memory_order_acquire, memory_order_relaxed)) {
}
return (old_state >= 0) ? 0 : EBUSY;
return __pthread_rwlock_tryrdlock(__get_internal_rwlock(rwlock_interface));
}
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock_interface) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
// Avoid slowing down fast path of wrlock.
if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) {
return 0;
}
return __pthread_rwlock_timedwrlock(rwlock, NULL);
}
@@ -284,65 +456,52 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespe
}
int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock_interface) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
while (old_state == 0 && !atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state, -1,
memory_order_acquire, memory_order_relaxed)) {
}
if (old_state == 0) {
atomic_store_explicit(&rwlock->writer_thread_id, __get_thread()->tid, memory_order_relaxed);
return 0;
}
return EBUSY;
return __pthread_rwlock_trywrlock(__get_internal_rwlock(rwlock_interface));
}
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock_interface) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
if (__predict_false(old_state == 0)) {
return EPERM;
} else if (old_state == -1) {
if (atomic_load_explicit(&rwlock->writer_thread_id, memory_order_relaxed) != __get_thread()->tid) {
if (__state_owned_by_writer(old_state)) {
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) != __get_thread()->tid) {
return EPERM;
}
// We're no longer the owner.
atomic_store_explicit(&rwlock->writer_thread_id, 0, memory_order_relaxed);
// Change state from -1 to 0.
atomic_store_explicit(&rwlock->state, 0, memory_order_release);
} else { // old_state > 0
// Reduce state by 1.
while (old_state > 0 && !atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state,
old_state - 1, memory_order_release, memory_order_relaxed)) {
}
if (old_state <= 0) {
return EPERM;
} else if (old_state > 1) {
atomic_store_explicit(&rwlock->writer_tid, 0, memory_order_relaxed);
old_state = atomic_fetch_and_explicit(&rwlock->state, ~STATE_OWNED_BY_WRITER_FLAG,
memory_order_release);
if (!__state_have_pending_readers_or_writers(old_state)) {
return 0;
}
// old_state = 1, which means the last reader calling unlock. It has to wake up waiters.
} else if (__state_owned_by_readers(old_state)) {
old_state = atomic_fetch_sub_explicit(&rwlock->state, STATE_READER_COUNT_CHANGE_STEP,
memory_order_release);
if (!__state_is_last_reader(old_state) || !__state_have_pending_readers_or_writers(old_state)) {
return 0;
}
} else {
return EPERM;
}
// If having waiters, wake up them.
// To avoid losing wake ups, the update of state should be observed before reading
// pending_readers/pending_writers by all threads. Use read locking as an example:
// read locking thread unlocking thread
// pending_readers++; state = 0;
// seq_cst fence seq_cst fence
// read state for futex_wait read pending_readers for futex_wake
//
// So when locking and unlocking threads are running in parallel, we will not get
// in a situation that the locking thread reads state as negative and needs to wait,
// while the unlocking thread reads pending_readers as zero and doesn't need to wake up waiters.
atomic_thread_fence(memory_order_seq_cst);
if (__predict_false(atomic_load_explicit(&rwlock->pending_readers, memory_order_relaxed) > 0 ||
atomic_load_explicit(&rwlock->pending_writers, memory_order_relaxed) > 0)) {
__futex_wake_ex(&rwlock->state, rwlock->process_shared(), INT_MAX);
// Wake up pending readers or writers.
rwlock->pending_lock.lock();
if (rwlock->pending_writer_count != 0) {
rwlock->pending_writer_wakeup_serial++;
rwlock->pending_lock.unlock();
__futex_wake_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared, 1);
} else if (rwlock->pending_reader_count != 0) {
rwlock->pending_reader_wakeup_serial++;
rwlock->pending_lock.unlock();
__futex_wake_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared, INT_MAX);
} else {
// It happens when waiters are woken up by timeout.
rwlock->pending_lock.unlock();
}
return 0;
}

View File

@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
#undef _FORTIFY_SOURCE
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

View File

@@ -245,6 +245,7 @@ static id_t app_id_from_name(const char* name, bool is_group) {
appid = android_ids[n].aid;
// Move the end pointer to the null terminator.
end += strlen(android_ids[n].name) + 1;
break;
}
}
}

View File

@@ -598,6 +598,16 @@ int __system_property_area_init()
return map_prop_area_rw();
}
unsigned int __system_property_area_serial()
{
prop_area *pa = __system_property_area__;
if (!pa) {
return -1;
}
// Make sure this read fulfilled before __system_property_serial
return atomic_load_explicit(&(pa->serial), memory_order_acquire);
}
const prop_info *__system_property_find(const char *name)
{
if (__predict_false(compat_mode)) {

View File

@@ -48,6 +48,71 @@ typedef struct {
} a_un;
} Elf64_auxv_t;
typedef Elf32_Half Elf32_Versym;
typedef Elf64_Half Elf64_Versym;
typedef struct {
Elf32_Half vd_version;
Elf32_Half vd_flags;
Elf32_Half vd_ndx;
Elf32_Half vd_cnt;
Elf32_Word vd_hash;
Elf32_Word vd_aux;
Elf32_Word vd_next;
} Elf32_Verdef;
typedef struct {
Elf32_Word vda_name;
Elf32_Word vda_next;
} Elf32_Verdaux;
typedef struct {
Elf64_Half vd_version;
Elf64_Half vd_flags;
Elf64_Half vd_ndx;
Elf64_Half vd_cnt;
Elf64_Word vd_hash;
Elf64_Word vd_aux;
Elf64_Word vd_next;
} Elf64_Verdef;
typedef struct {
Elf64_Word vda_name;
Elf64_Word vda_next;
} Elf64_Verdaux;
typedef struct {
Elf32_Half vn_version;
Elf32_Half vn_cnt;
Elf32_Word vn_file;
Elf32_Word vn_aux;
Elf32_Word vn_next;
} Elf32_Verneed;
typedef struct {
Elf32_Word vna_hash;
Elf32_Half vna_flags;
Elf32_Half vna_other;
Elf32_Word vna_name;
Elf32_Word vna_next;
} Elf32_Vernaux;
typedef struct {
Elf64_Half vn_version;
Elf64_Half vn_cnt;
Elf64_Word vn_file;
Elf64_Word vn_aux;
Elf64_Word vn_next;
} Elf64_Verneed;
typedef struct {
Elf64_Word vna_hash;
Elf64_Half vna_flags;
Elf64_Half vna_other;
Elf64_Word vna_name;
Elf64_Word vna_next;
} Elf64_Vernaux;
#define DF_ORIGIN 0x00000001
#define DF_SYMBOLIC 0x00000002
#define DF_TEXTREL 0x00000004
@@ -129,4 +194,10 @@ typedef struct {
#define NT_GNU_BUILD_ID 3
#define VER_FLG_BASE 0x1
#define VER_FLG_WEAK 0x2
#define VER_NDX_LOCAL 0
#define VER_NDX_GLOBAL 1
#endif /* _ELF_H */

View File

@@ -85,6 +85,11 @@ typedef long pthread_rwlockattr_t;
#define PTHREAD_RWLOCK_INITIALIZER { { 0 } }
enum {
PTHREAD_RWLOCK_PREFER_READER_NP = 0,
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP = 1,
};
typedef int pthread_key_t;
typedef int pthread_once_t;
@@ -178,10 +183,12 @@ int pthread_mutex_unlock(pthread_mutex_t*) __nonnull((1));
int pthread_once(pthread_once_t*, void (*)(void)) __nonnull((1, 2));
int pthread_rwlockattr_init(pthread_rwlockattr_t*) __nonnull((1));
int pthread_rwlockattr_destroy(pthread_rwlockattr_t*) __nonnull((1));
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t*, int*) __nonnull((1, 2));
int pthread_rwlockattr_init(pthread_rwlockattr_t*) __nonnull((1));
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int) __nonnull((1));
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t*, int*) __nonnull((1, 2));
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t*, int) __nonnull((1));
int pthread_rwlock_destroy(pthread_rwlock_t*) __nonnull((1));
int pthread_rwlock_init(pthread_rwlock_t*, const pthread_rwlockattr_t*) __nonnull((1));

View File

@@ -176,6 +176,27 @@ extern size_t __ctype_get_mb_cur_max(void);
#include <android/legacy_stdlib_inlines.h>
#endif
#if defined(__BIONIC_FORTIFY)
extern char* __realpath_real(const char*, char*) __RENAME(realpath);
__errordecl(__realpath_size_error, "realpath output parameter must be NULL or a >= PATH_MAX bytes buffer");
#if !defined(__clang__)
__BIONIC_FORTIFY_INLINE
char* realpath(const char* path, char* resolved) {
size_t bos = __bos(resolved);
/* PATH_MAX is unavailable without polluting the namespace, but it's always 4096 on Linux */
if (bos != __BIONIC_FORTIFY_UNKNOWN_SIZE && bos < 4096) {
__realpath_size_error();
}
return __realpath_real(path, resolved);
}
#endif
#endif /* defined(__BIONIC_FORTIFY) */
__END_DECLS
#endif /* _STDLIB_H */

View File

@@ -121,6 +121,13 @@ extern char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
#define __bionic_using_gnu_basename
#endif
extern void* __memchr_chk(const void*, int, size_t, size_t);
__errordecl(__memchr_buf_size_error, "memchr called with size bigger than buffer");
extern void* __memrchr_chk(const void*, int, size_t, size_t);
__errordecl(__memrchr_buf_size_error, "memrchr called with size bigger than buffer");
extern void* __memrchr_real(const void*, int, size_t) __RENAME(memrchr);
extern char* __stpncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t);
extern char* __strncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t);
extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy);
@@ -130,6 +137,48 @@ extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, si
#if defined(__BIONIC_FORTIFY)
__BIONIC_FORTIFY_INLINE
void* memchr(const void *s, int c, size_t n) {
size_t bos = __bos(s);
#if !defined(__clang__)
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __builtin_memchr(s, c, n);
}
if (__builtin_constant_p(n) && (n > bos)) {
__memchr_buf_size_error();
}
if (__builtin_constant_p(n) && (n <= bos)) {
return __builtin_memchr(s, c, n);
}
#endif
return __memchr_chk(s, c, n, bos);
}
__BIONIC_FORTIFY_INLINE
void* memrchr(const void *s, int c, size_t n) {
size_t bos = __bos(s);
#if !defined(__clang__)
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __memrchr_real(s, c, n);
}
if (__builtin_constant_p(n) && (n > bos)) {
__memrchr_buf_size_error();
}
if (__builtin_constant_p(n) && (n <= bos)) {
return __memrchr_real(s, c, n);
}
#endif
return __memrchr_chk(s, c, n, bos);
}
__BIONIC_FORTIFY_INLINE
void* memcpy(void* __restrict dest, const void* __restrict src, size_t copy_amount) {
return __builtin___memcpy_chk(dest, src, copy_amount, __bos0(dest));

View File

@@ -80,7 +80,6 @@ struct prop_msg
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop"
#define PROP_PATH_BOOTIMAGE_BUILD "/build.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
@@ -99,6 +98,24 @@ int __system_property_set_filename(const char *filename);
*/
int __system_property_area_init();
/* Read the global serial number of the system properties
**
** Called to predict if a series of cached __system_property_find
** objects will have seen __system_property_serial values change.
** But also aids the converse, as changes in the global serial can
** also be used to predict if a failed __system_property_find
** could in-turn now find an new object; thus preventing the
** cycles of effort to poll __system_property_find.
**
** Called at the beginning of a cache cycle to signal _any_ possible
** changes have occurred since last. If there is, check each individual
** __system_property_serial to confirm dirty, or __system_property_find
** to check if the property now exists.
**
** Returns the serial number on success, -1 on error.
*/
unsigned int __system_property_area_serial();
/* Add a new system property. Can only be done by a single
** process that has write access to the property area, and
** that process must handle sequencing to ensure the property

View File

@@ -224,13 +224,89 @@ extern int tcsetpgrp(int fd, pid_t _pid);
} while (_rc == -1 && errno == EINTR); \
_rc; })
extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
extern ssize_t __pread_real(int, void*, size_t, off_t) __RENAME(pread);
extern ssize_t __pread64_chk(int, void*, size_t, off64_t, size_t);
__errordecl(__pread64_dest_size_error, "pread64 called with size bigger than destination");
__errordecl(__pread64_count_toobig_error, "pread64 called with count > SSIZE_MAX");
extern ssize_t __pread64_real(int, void*, size_t, off64_t) __RENAME(pread64);
extern ssize_t __read_chk(int, void*, size_t, size_t);
__errordecl(__read_dest_size_error, "read called with size bigger than destination");
__errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
extern ssize_t __read_real(int, void*, size_t) __RENAME(read);
extern ssize_t __readlink_chk(const char*, char*, size_t, size_t);
__errordecl(__readlink_dest_size_error, "readlink called with size bigger than destination");
__errordecl(__readlink_size_toobig_error, "readlink called with size > SSIZE_MAX");
extern ssize_t __readlink_real(const char*, char*, size_t) __RENAME(readlink);
extern ssize_t __readlinkat_chk(int dirfd, const char*, char*, size_t, size_t);
__errordecl(__readlinkat_dest_size_error, "readlinkat called with size bigger than destination");
__errordecl(__readlinkat_size_toobig_error, "readlinkat called with size > SSIZE_MAX");
extern ssize_t __readlinkat_real(int dirfd, const char*, char*, size_t) __RENAME(readlinkat);
#if defined(__BIONIC_FORTIFY)
#if defined(__USE_FILE_OFFSET64)
#define __PREAD_PREFIX(x) __pread64_ ## x
#else
#define __PREAD_PREFIX(x) __pread_ ## x
#endif
__BIONIC_FORTIFY_INLINE
ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
size_t bos = __bos0(buf);
#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__PREAD_PREFIX(count_toobig_error)();
}
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __PREAD_PREFIX(real)(fd, buf, count, offset);
}
if (__builtin_constant_p(count) && (count > bos)) {
__PREAD_PREFIX(dest_size_error)();
}
if (__builtin_constant_p(count) && (count <= bos)) {
return __PREAD_PREFIX(real)(fd, buf, count, offset);
}
#endif
return __PREAD_PREFIX(chk)(fd, buf, count, offset, bos);
}
__BIONIC_FORTIFY_INLINE
ssize_t pread64(int fd, void* buf, size_t count, off64_t offset) {
size_t bos = __bos0(buf);
#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__pread64_count_toobig_error();
}
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __pread64_real(fd, buf, count, offset);
}
if (__builtin_constant_p(count) && (count > bos)) {
__pread64_dest_size_error();
}
if (__builtin_constant_p(count) && (count <= bos)) {
return __pread64_real(fd, buf, count, offset);
}
#endif
return __pread64_chk(fd, buf, count, offset, bos);
}
__BIONIC_FORTIFY_INLINE
ssize_t read(int fd, void* buf, size_t count) {
size_t bos = __bos0(buf);
@@ -255,6 +331,57 @@ ssize_t read(int fd, void* buf, size_t count) {
return __read_chk(fd, buf, count, bos);
}
__BIONIC_FORTIFY_INLINE
ssize_t readlink(const char* path, char* buf, size_t size) {
size_t bos = __bos(buf);
#if !defined(__clang__)
if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
__readlink_size_toobig_error();
}
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __readlink_real(path, buf, size);
}
if (__builtin_constant_p(size) && (size > bos)) {
__readlink_dest_size_error();
}
if (__builtin_constant_p(size) && (size <= bos)) {
return __readlink_real(path, buf, size);
}
#endif
return __readlink_chk(path, buf, size, bos);
}
__BIONIC_FORTIFY_INLINE
ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t size) {
size_t bos = __bos(buf);
#if !defined(__clang__)
if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
__readlinkat_size_toobig_error();
}
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __readlinkat_real(dirfd, path, buf, size);
}
if (__builtin_constant_p(size) && (size > bos)) {
__readlinkat_dest_size_error();
}
if (__builtin_constant_p(size) && (size <= bos)) {
return __readlinkat_real(dirfd, path, buf, size);
}
#endif
return __readlinkat_chk(dirfd, path, buf, size, bos);
}
#endif /* defined(__BIONIC_FORTIFY) */
__END_DECLS

View File

@@ -14,7 +14,6 @@ if top is None:
# Set up the env vars for libclang.
site.addsitedir(os.path.join(top, 'external/clang/bindings/python'))
os.putenv('LD_LIBRARY_PATH', os.path.join(top, 'prebuilts/sdk/tools/linux'))
import clang.cindex
from clang.cindex import conf
@@ -26,6 +25,10 @@ from clang.cindex import TokenGroup
from clang.cindex import TokenKind
from clang.cindex import TranslationUnit
# Set up LD_LIBRARY_PATH to include libclang.so, libLLVM.so, and etc.
# Note that setting LD_LIBRARY_PATH with os.putenv() sometimes doesn't help.
clang.cindex.Config.set_library_path(os.path.join(top, 'prebuilts/sdk/tools/linux/lib64'))
from defaults import kCppUndefinedMacro
from defaults import kernel_remove_config_macros
from defaults import kernel_token_replacements

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _BIONIC_LOCK_H
#define _BIONIC_LOCK_H
#include <stdatomic.h>
#include "private/bionic_futex.h"
class Lock {
private:
enum LockState {
Unlocked = 0,
LockedWithoutWaiter,
LockedWithWaiter,
};
_Atomic(LockState) state;
bool process_shared;
public:
Lock(bool process_shared = false) {
init(process_shared);
}
void init(bool process_shared) {
atomic_init(&state, Unlocked);
this->process_shared = process_shared;
}
void lock() {
LockState old_state = Unlocked;
if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed))) {
return;
}
while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
__futex_wait_ex(&state, process_shared, LockedWithWaiter, NULL);
}
return;
}
void unlock() {
if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
__futex_wake_ex(&state, process_shared, 1);
}
}
};
#endif // _BIONIC_LOCK_H

View File

@@ -97,14 +97,8 @@ enum {
#define LIBC_PTHREAD_KEY_RESERVED_COUNT 12
#if defined(USE_JEMALLOC)
/* Following are current pthread keys used internally by jemalloc:
* je_thread_allocated_tsd jemalloc
* je_arenas_tsd jemalloc
* je_tcache_tsd jemalloc
* je_tcache_enabled_tsd jemalloc
* je_quarantine_tsd jemalloc
*/
#define JEMALLOC_PTHREAD_KEY_RESERVED_COUNT 5
/* Internally, jemalloc uses a single key for per thread data. */
#define JEMALLOC_PTHREAD_KEY_RESERVED_COUNT 1
#define BIONIC_PTHREAD_KEY_RESERVED_COUNT (LIBC_PTHREAD_KEY_RESERVED_COUNT + JEMALLOC_PTHREAD_KEY_RESERVED_COUNT)
#else
#define BIONIC_PTHREAD_KEY_RESERVED_COUNT LIBC_PTHREAD_KEY_RESERVED_COUNT

View File

@@ -35,11 +35,15 @@
#include <string.h>
#include <unistd.h>
#include "atexit.h"
#include "thread_private.h"
#include "private/thread_private.h"
struct atexit *__atexit;
static int restartloop;
/* BEGIN android-changed: __unregister_atfork is used by __cxa_finalize */
extern void __unregister_atfork(void* dso);
/* END android-changed */
/*
* Function pointers are stored in a linked list of pages. The list
* is initially empty, and pages are allocated on demand. The first
@@ -62,7 +66,7 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso)
{
struct atexit *p = __atexit;
struct atexit_fn *fnp;
int pgsize = getpagesize();
size_t pgsize = getpagesize();
int ret = -1;
if (pgsize < sizeof(*p))
@@ -161,6 +165,12 @@ restart:
__atexit = NULL;
}
_ATEXIT_UNLOCK();
/* BEGIN android-changed: call __unregister_atfork if dso is not null */
if (dso != NULL) {
__unregister_atfork(dso);
}
/* END android-changed */
}
/*
@@ -170,7 +180,7 @@ void
__atexit_register_cleanup(void (*func)(void))
{
struct atexit *p;
int pgsize = getpagesize();
size_t pgsize = getpagesize();
if (pgsize < sizeof(*p))
return;

View File

@@ -32,8 +32,6 @@
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include "atexit.h"
#include "thread_private.h"
/*
* This variable is zero until a process has created a thread.
@@ -44,12 +42,21 @@
*/
int __isthreaded = 0;
/* BEGIN android-added: using __cxa_finalize and __cxa_thread_finalize */
extern void __cxa_finalize(void* dso_handle);
extern void __cxa_thread_finalize();
/* END android-added */
/*
* Exit, flushing stdio buffers if necessary.
*/
void
exit(int status)
{
/* BEGIN android-added: call thread_local d-tors */
__cxa_thread_finalize();
/* END android-added */
/*
* Call functions registered by atexit() or _cxa_atexit()
* (including the stdio cleanup routine) and then _exit().

View File

@@ -33,9 +33,12 @@ CheckDirExists(bionic_libc_zoneinfo_dir, 'bionic/libc/zoneinfo')
CheckDirExists(bionic_libc_tools_zoneinfo_dir, 'bionic/libc/tools/zoneinfo')
print 'Found bionic in %s ...' % bionic_dir
# Find the icu4c directory.
icu_dir = os.path.realpath('%s/../external/icu/icu4c/source' % bionic_dir)
CheckDirExists(icu_dir, 'external/icu/icu4c/source')
# Find the icu directory.
icu_dir = os.path.realpath('%s/../external/icu' % bionic_dir)
icu4c_dir = os.path.realpath('%s/icu4c/source' % icu_dir)
icu4j_dir = os.path.realpath('%s/icu4j' % icu_dir)
CheckDirExists(icu4c_dir, 'external/icu/icu4c/source')
CheckDirExists(icu4j_dir, 'external/icu/icu4j')
print 'Found icu in %s ...' % icu_dir
@@ -116,14 +119,14 @@ def BuildIcuToolsAndData(data_filename):
# Build the ICU tools.
print 'Configuring ICU tools...'
subprocess.check_call(['%s/runConfigureICU' % icu_dir, 'Linux'])
subprocess.check_call(['%s/runConfigureICU' % icu4c_dir, 'Linux'])
# Run the ICU tools.
os.chdir('tools/tzcode')
# The tz2icu tool only picks up icuregions and icuzones in they are in the CWD
for icu_data_file in [ 'icuregions', 'icuzones']:
icu_data_file_source = '%s/tools/tzcode/%s' % (icu_dir, icu_data_file)
icu_data_file_source = '%s/tools/tzcode/%s' % (icu4c_dir, icu_data_file)
icu_data_file_symlink = './%s' % icu_data_file
os.symlink(icu_data_file_source, icu_data_file_symlink)
@@ -134,7 +137,7 @@ def BuildIcuToolsAndData(data_filename):
subprocess.check_call(['make'])
# Copy the source file to its ultimate destination.
icu_txt_data_dir = '%s/data/misc' % icu_dir
icu_txt_data_dir = '%s/data/misc' % icu4c_dir
print 'Copying zoneinfo64.txt to %s ...' % icu_txt_data_dir
shutil.copy('zoneinfo64.txt', icu_txt_data_dir)
@@ -143,7 +146,7 @@ def BuildIcuToolsAndData(data_filename):
subprocess.check_call(['make', 'INCLUDE_UNI_CORE_DATA=1', '-j32'])
# Copy the .dat file to its ultimate destination.
icu_dat_data_dir = '%s/stubdata' % icu_dir
icu_dat_data_dir = '%s/stubdata' % icu4c_dir
datfiles = glob.glob('data/out/tmp/icudt??l.dat')
if len(datfiles) != 1:
print 'ERROR: Unexpectedly found %d .dat files (%s). Halting.' % (len(datfiles), datfiles)
@@ -152,6 +155,20 @@ def BuildIcuToolsAndData(data_filename):
print 'Copying %s to %s ...' % (datfile, icu_dat_data_dir)
shutil.copy(datfile, icu_dat_data_dir)
# Generate the ICU4J .jar files
os.chdir('%s/data' % icu_working_dir)
subprocess.check_call(['make', 'icu4j-data'])
# Copy the ICU4J .jar files to their ultimate destination.
icu_jar_data_dir = '%s/main/shared/data' % icu4j_dir
jarfiles = glob.glob('out/icu4j/*.jar')
if len(jarfiles) != 2:
print 'ERROR: Unexpectedly found %d .jar files (%s). Halting.' % (len(jarfiles), jarfiles)
sys.exit(1)
for jarfile in jarfiles:
print 'Copying %s to %s ...' % (jarfile, icu_jar_data_dir)
shutil.copy(jarfile, icu_jar_data_dir)
# Switch back to the original working cwd.
os.chdir(original_working_dir)

Binary file not shown.

46
libdl/Android.bp Normal file
View File

@@ -0,0 +1,46 @@
//
// libdl
//
cc_library {
// NOTE: --exclude-libs=libgcc.a makes sure that any symbols libdl.so pulls from
// libgcc.a are made static to libdl.so. This in turn ensures that libraries that
// a) pull symbols from libgcc.a and b) depend on libdl.so will not rely on libdl.so
// to provide those symbols, but will instead pull them from libgcc.a. Specifically,
// we use this property to make sure libc.so has its own copy of the code from
// libgcc.a it uses.
//
// DO NOT REMOVE --exclude-libs!
ldflags: ["-Wl,--exclude-libs=libgcc.a"],
// for x86, exclude libgcc_eh.a for the same reasons as above
arch: {
x86: {
ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
},
x86_64: {
ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
},
},
srcs: ["libdl.c"],
cflags: [
"-Wall",
"-Wextra",
"-Wunused",
"-Werror",
],
stl: "none",
name: "libdl",
// NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
// few symbols from libc. Using --no-undefined here results in having to link
// against libc creating a circular dependency which is removed and we end up
// with missing symbols. Since this library is just a bunch of stubs, we set
// LOCAL_ALLOW_UNDEFINED_SYMBOLS to remove --no-undefined from the linker flags.
allow_undefined_symbols: true,
system_shared_libs: [],
asan: false,
}

381
libm/Android.bp Normal file
View File

@@ -0,0 +1,381 @@
// ANDROIDMK TRANSLATION ERROR: unsupported directive
// ifneq ($(TARGET_USE_PRIVATE_LIBM),true)
bionic_coverage = false
// TODO: this comes from from upstream's libc, not libm, but it's an
// implementation detail that should have hidden visibility, so it needs
// to be in whatever library the math code is in.
libm_common_src_files = ["digittoint.c"]
// TODO: this is not in the BSDs.
libm_common_src_files += [
"significandl.c",
"sincos.c",
]
libm_common_src_files += [
"upstream-freebsd/lib/msun/bsdsrc/b_exp.c",
"upstream-freebsd/lib/msun/bsdsrc/b_log.c",
"upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c",
"upstream-freebsd/lib/msun/src/catrig.c",
"upstream-freebsd/lib/msun/src/catrigf.c",
"upstream-freebsd/lib/msun/src/e_acos.c",
"upstream-freebsd/lib/msun/src/e_acosf.c",
"upstream-freebsd/lib/msun/src/e_acosh.c",
"upstream-freebsd/lib/msun/src/e_acoshf.c",
"upstream-freebsd/lib/msun/src/e_asin.c",
"upstream-freebsd/lib/msun/src/e_asinf.c",
"upstream-freebsd/lib/msun/src/e_atan2.c",
"upstream-freebsd/lib/msun/src/e_atan2f.c",
"upstream-freebsd/lib/msun/src/e_atanh.c",
"upstream-freebsd/lib/msun/src/e_atanhf.c",
"upstream-freebsd/lib/msun/src/e_cosh.c",
"upstream-freebsd/lib/msun/src/e_coshf.c",
"upstream-freebsd/lib/msun/src/e_exp.c",
"upstream-freebsd/lib/msun/src/e_expf.c",
"upstream-freebsd/lib/msun/src/e_fmod.c",
"upstream-freebsd/lib/msun/src/e_fmodf.c",
"upstream-freebsd/lib/msun/src/e_gamma.c",
"upstream-freebsd/lib/msun/src/e_gammaf.c",
"upstream-freebsd/lib/msun/src/e_gammaf_r.c",
"upstream-freebsd/lib/msun/src/e_gamma_r.c",
"upstream-freebsd/lib/msun/src/e_hypot.c",
"upstream-freebsd/lib/msun/src/e_hypotf.c",
"upstream-freebsd/lib/msun/src/e_j0.c",
"upstream-freebsd/lib/msun/src/e_j0f.c",
"upstream-freebsd/lib/msun/src/e_j1.c",
"upstream-freebsd/lib/msun/src/e_j1f.c",
"upstream-freebsd/lib/msun/src/e_jn.c",
"upstream-freebsd/lib/msun/src/e_jnf.c",
"upstream-freebsd/lib/msun/src/e_lgamma.c",
"upstream-freebsd/lib/msun/src/e_lgammaf.c",
"upstream-freebsd/lib/msun/src/e_lgammaf_r.c",
"upstream-freebsd/lib/msun/src/e_lgamma_r.c",
"upstream-freebsd/lib/msun/src/e_log10.c",
"upstream-freebsd/lib/msun/src/e_log10f.c",
"upstream-freebsd/lib/msun/src/e_log2.c",
"upstream-freebsd/lib/msun/src/e_log2f.c",
"upstream-freebsd/lib/msun/src/e_log.c",
"upstream-freebsd/lib/msun/src/e_logf.c",
"upstream-freebsd/lib/msun/src/e_pow.c",
"upstream-freebsd/lib/msun/src/e_powf.c",
"upstream-freebsd/lib/msun/src/e_remainder.c",
"upstream-freebsd/lib/msun/src/e_remainderf.c",
"upstream-freebsd/lib/msun/src/e_rem_pio2.c",
"upstream-freebsd/lib/msun/src/e_rem_pio2f.c",
"upstream-freebsd/lib/msun/src/e_scalb.c",
"upstream-freebsd/lib/msun/src/e_scalbf.c",
"upstream-freebsd/lib/msun/src/e_sinh.c",
"upstream-freebsd/lib/msun/src/e_sinhf.c",
"upstream-freebsd/lib/msun/src/e_sqrt.c",
"upstream-freebsd/lib/msun/src/e_sqrtf.c",
"upstream-freebsd/lib/msun/src/imprecise.c",
"upstream-freebsd/lib/msun/src/k_cos.c",
"upstream-freebsd/lib/msun/src/k_cosf.c",
"upstream-freebsd/lib/msun/src/k_exp.c",
"upstream-freebsd/lib/msun/src/k_expf.c",
"upstream-freebsd/lib/msun/src/k_rem_pio2.c",
"upstream-freebsd/lib/msun/src/k_sin.c",
"upstream-freebsd/lib/msun/src/k_sinf.c",
"upstream-freebsd/lib/msun/src/k_tan.c",
"upstream-freebsd/lib/msun/src/k_tanf.c",
"upstream-freebsd/lib/msun/src/s_asinh.c",
"upstream-freebsd/lib/msun/src/s_asinhf.c",
"upstream-freebsd/lib/msun/src/s_atan.c",
"upstream-freebsd/lib/msun/src/s_atanf.c",
"upstream-freebsd/lib/msun/src/s_carg.c",
"upstream-freebsd/lib/msun/src/s_cargf.c",
"upstream-freebsd/lib/msun/src/s_cargl.c",
"upstream-freebsd/lib/msun/src/s_cbrt.c",
"upstream-freebsd/lib/msun/src/s_cbrtf.c",
"upstream-freebsd/lib/msun/src/s_ccosh.c",
"upstream-freebsd/lib/msun/src/s_ccoshf.c",
"upstream-freebsd/lib/msun/src/s_ceil.c",
"upstream-freebsd/lib/msun/src/s_ceilf.c",
"upstream-freebsd/lib/msun/src/s_cexp.c",
"upstream-freebsd/lib/msun/src/s_cexpf.c",
"upstream-freebsd/lib/msun/src/s_cimag.c",
"upstream-freebsd/lib/msun/src/s_cimagf.c",
"upstream-freebsd/lib/msun/src/s_cimagl.c",
"upstream-freebsd/lib/msun/src/s_conj.c",
"upstream-freebsd/lib/msun/src/s_conjf.c",
"upstream-freebsd/lib/msun/src/s_conjl.c",
"upstream-freebsd/lib/msun/src/s_copysign.c",
"upstream-freebsd/lib/msun/src/s_copysignf.c",
"upstream-freebsd/lib/msun/src/s_cos.c",
"upstream-freebsd/lib/msun/src/s_cosf.c",
"upstream-freebsd/lib/msun/src/s_cproj.c",
"upstream-freebsd/lib/msun/src/s_cprojf.c",
"upstream-freebsd/lib/msun/src/s_cprojl.c",
"upstream-freebsd/lib/msun/src/s_creal.c",
"upstream-freebsd/lib/msun/src/s_crealf.c",
"upstream-freebsd/lib/msun/src/s_creall.c",
"upstream-freebsd/lib/msun/src/s_csinh.c",
"upstream-freebsd/lib/msun/src/s_csinhf.c",
"upstream-freebsd/lib/msun/src/s_csqrt.c",
"upstream-freebsd/lib/msun/src/s_csqrtf.c",
"upstream-freebsd/lib/msun/src/s_csqrtl.c",
"upstream-freebsd/lib/msun/src/s_ctanh.c",
"upstream-freebsd/lib/msun/src/s_ctanhf.c",
"upstream-freebsd/lib/msun/src/s_erf.c",
"upstream-freebsd/lib/msun/src/s_erff.c",
"upstream-freebsd/lib/msun/src/s_exp2.c",
"upstream-freebsd/lib/msun/src/s_exp2f.c",
"upstream-freebsd/lib/msun/src/s_expm1.c",
"upstream-freebsd/lib/msun/src/s_expm1f.c",
"upstream-freebsd/lib/msun/src/s_fabs.c",
"upstream-freebsd/lib/msun/src/s_fabsf.c",
"upstream-freebsd/lib/msun/src/s_fdim.c",
"upstream-freebsd/lib/msun/src/s_finite.c",
"upstream-freebsd/lib/msun/src/s_finitef.c",
"upstream-freebsd/lib/msun/src/s_floor.c",
"upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_fma.c",
"upstream-freebsd/lib/msun/src/s_fmaf.c",
"upstream-freebsd/lib/msun/src/s_fmax.c",
"upstream-freebsd/lib/msun/src/s_fmaxf.c",
"upstream-freebsd/lib/msun/src/s_fmin.c",
"upstream-freebsd/lib/msun/src/s_fminf.c",
"upstream-freebsd/lib/msun/src/s_frexp.c",
"upstream-freebsd/lib/msun/src/s_frexpf.c",
"upstream-freebsd/lib/msun/src/s_ilogb.c",
"upstream-freebsd/lib/msun/src/s_ilogbf.c",
"upstream-freebsd/lib/msun/src/s_llrint.c",
"upstream-freebsd/lib/msun/src/s_llrintf.c",
"upstream-freebsd/lib/msun/src/s_llround.c",
"upstream-freebsd/lib/msun/src/s_llroundf.c",
"upstream-freebsd/lib/msun/src/s_log1p.c",
"upstream-freebsd/lib/msun/src/s_log1pf.c",
"upstream-freebsd/lib/msun/src/s_logb.c",
"upstream-freebsd/lib/msun/src/s_logbf.c",
"upstream-freebsd/lib/msun/src/s_lrint.c",
"upstream-freebsd/lib/msun/src/s_lrintf.c",
"upstream-freebsd/lib/msun/src/s_lround.c",
"upstream-freebsd/lib/msun/src/s_lroundf.c",
"upstream-freebsd/lib/msun/src/s_modf.c",
"upstream-freebsd/lib/msun/src/s_modff.c",
"upstream-freebsd/lib/msun/src/s_nan.c",
"upstream-freebsd/lib/msun/src/s_nearbyint.c",
"upstream-freebsd/lib/msun/src/s_nextafter.c",
"upstream-freebsd/lib/msun/src/s_nextafterf.c",
"upstream-freebsd/lib/msun/src/s_remquo.c",
"upstream-freebsd/lib/msun/src/s_remquof.c",
"upstream-freebsd/lib/msun/src/s_rint.c",
"upstream-freebsd/lib/msun/src/s_rintf.c",
"upstream-freebsd/lib/msun/src/s_round.c",
"upstream-freebsd/lib/msun/src/s_roundf.c",
"upstream-freebsd/lib/msun/src/s_scalbln.c",
"upstream-freebsd/lib/msun/src/s_scalbn.c",
"upstream-freebsd/lib/msun/src/s_scalbnf.c",
"upstream-freebsd/lib/msun/src/s_signgam.c",
"upstream-freebsd/lib/msun/src/s_significand.c",
"upstream-freebsd/lib/msun/src/s_significandf.c",
"upstream-freebsd/lib/msun/src/s_sin.c",
"upstream-freebsd/lib/msun/src/s_sinf.c",
"upstream-freebsd/lib/msun/src/s_tan.c",
"upstream-freebsd/lib/msun/src/s_tanf.c",
"upstream-freebsd/lib/msun/src/s_tanh.c",
"upstream-freebsd/lib/msun/src/s_tanhf.c",
"upstream-freebsd/lib/msun/src/s_tgammaf.c",
"upstream-freebsd/lib/msun/src/s_trunc.c",
"upstream-freebsd/lib/msun/src/s_truncf.c",
"upstream-freebsd/lib/msun/src/w_cabs.c",
"upstream-freebsd/lib/msun/src/w_cabsf.c",
"upstream-freebsd/lib/msun/src/w_cabsl.c",
"upstream-freebsd/lib/msun/src/w_drem.c",
"upstream-freebsd/lib/msun/src/w_dremf.c",
]
libm_common_src_files += [
"fake_long_double.c",
"signbit.c",
]
libm_ld128_src_files = [
"upstream-freebsd/lib/msun/src/e_acosl.c",
"upstream-freebsd/lib/msun/src/e_acoshl.c",
"upstream-freebsd/lib/msun/src/e_asinl.c",
"upstream-freebsd/lib/msun/src/e_atan2l.c",
"upstream-freebsd/lib/msun/src/e_atanhl.c",
"upstream-freebsd/lib/msun/src/e_fmodl.c",
"upstream-freebsd/lib/msun/src/e_hypotl.c",
"upstream-freebsd/lib/msun/src/e_lgammal.c",
"upstream-freebsd/lib/msun/src/e_remainderl.c",
"upstream-freebsd/lib/msun/src/e_sqrtl.c",
"upstream-freebsd/lib/msun/src/s_asinhl.c",
"upstream-freebsd/lib/msun/src/s_atanl.c",
"upstream-freebsd/lib/msun/src/s_cbrtl.c",
"upstream-freebsd/lib/msun/src/s_ceill.c",
"upstream-freebsd/lib/msun/src/s_copysignl.c",
"upstream-freebsd/lib/msun/src/e_coshl.c",
"upstream-freebsd/lib/msun/src/s_cosl.c",
"upstream-freebsd/lib/msun/src/s_fabsl.c",
"upstream-freebsd/lib/msun/src/s_floorl.c",
"upstream-freebsd/lib/msun/src/s_fmal.c",
"upstream-freebsd/lib/msun/src/s_fmaxl.c",
"upstream-freebsd/lib/msun/src/s_fminl.c",
"upstream-freebsd/lib/msun/src/s_modfl.c",
"upstream-freebsd/lib/msun/src/s_frexpl.c",
"upstream-freebsd/lib/msun/src/s_ilogbl.c",
"upstream-freebsd/lib/msun/src/s_llrintl.c",
"upstream-freebsd/lib/msun/src/s_llroundl.c",
"upstream-freebsd/lib/msun/src/s_logbl.c",
"upstream-freebsd/lib/msun/src/s_lrintl.c",
"upstream-freebsd/lib/msun/src/s_lroundl.c",
"upstream-freebsd/lib/msun/src/s_nextafterl.c",
"upstream-freebsd/lib/msun/src/s_nexttoward.c",
"upstream-freebsd/lib/msun/src/s_nexttowardf.c",
"upstream-freebsd/lib/msun/src/s_remquol.c",
"upstream-freebsd/lib/msun/src/s_rintl.c",
"upstream-freebsd/lib/msun/src/s_roundl.c",
"upstream-freebsd/lib/msun/src/s_scalbnl.c",
"upstream-freebsd/lib/msun/src/e_sinhl.c",
"upstream-freebsd/lib/msun/src/s_sinl.c",
"upstream-freebsd/lib/msun/src/s_tanhl.c",
"upstream-freebsd/lib/msun/src/s_tanl.c",
"upstream-freebsd/lib/msun/src/s_truncl.c",
]
libm_ld128_src_files += [
"upstream-freebsd/lib/msun/ld128/invtrig.c",
"upstream-freebsd/lib/msun/ld128/e_lgammal_r.c",
"upstream-freebsd/lib/msun/ld128/k_cosl.c",
"upstream-freebsd/lib/msun/ld128/k_sinl.c",
"upstream-freebsd/lib/msun/ld128/k_tanl.c",
"upstream-freebsd/lib/msun/ld128/s_erfl.c",
"upstream-freebsd/lib/msun/ld128/s_exp2l.c",
"upstream-freebsd/lib/msun/ld128/s_expl.c",
"upstream-freebsd/lib/msun/ld128/s_logl.c",
"upstream-freebsd/lib/msun/ld128/s_nanl.c",
]
// TODO: re-enable i387/e_sqrtf.S for x86, and maybe others.
libm_common_cflags = [
"-DFLT_EVAL_METHOD=0",
"-std=c99",
"-include freebsd-compat.h",
"-Wno-missing-braces",
"-Wno-parentheses",
"-Wno-sign-compare",
"-Wno-uninitialized",
"-Wno-unknown-pragmas",
"-fvisibility=hidden",
]
// Workaround the GCC "(long)fn -> lfn" optimization bug which will result in
// self recursions for lrint, lrintf, and lrintl.
// BUG: 14225968
libm_common_cflags += [
"-fno-builtin-rint",
"-fno-builtin-rintf",
"-fno-builtin-rintl",
]
libm_common_local_includes = ["upstream-freebsd/lib/msun/src/"]
libm_ld_local_includes = ["upstream-freebsd/lib/msun/ld128/"]
//
// libm.so and libm.a for target.
//
cc_library {
name: "libm",
cflags: libm_common_cflags,
include_dirs: ["bionic/libc"],
local_include_dirs: libm_common_local_includes,
srcs: libm_common_src_files,
system_shared_libs: ["libc"],
native_coverage: bionic_coverage,
asan: false,
multilib: {
lib64: {
srcs: libm_ld128_src_files,
local_include_dirs: libm_ld_local_includes,
// We'd really like to do this for all architectures, but since this wasn't done
// before, these symbols must continue to be exported on LP32 for binary
// compatibility.
ldflags: ["-Wl,--exclude-libs,libgcc.a"],
},
},
// arch-specific settings
arch: {
arm: {
srcs: [
"arm/fenv.c",
"arm/e_sqrt.S",
"arm/e_sqrtf.S",
"arm/s_floor.S",
],
exclude_srcs: [
// TODO: these require neon not available in arm
"upstream-freebsd/lib/msun/src/e_sqrt.c",
"upstream-freebsd/lib/msun/src/e_sqrtf.c",
"upstream-freebsd/lib/msun/src/s_floor.c",
],
instruction_set: "arm",
},
arm64: {
srcs: [
"arm64/fenv.c",
"arm64/ceil.S",
"arm64/fma.S",
"arm64/floor.S",
"arm64/lrint.S",
"arm64/rint.S",
"arm64/sqrt.S",
"arm64/trunc.S",
],
exclude_srcs: [
"upstream-freebsd/lib/msun/src/s_ceil.c",
"upstream-freebsd/lib/msun/src/s_ceilf.c",
"upstream-freebsd/lib/msun/src/s_fma.c",
"upstream-freebsd/lib/msun/src/s_fmaf.c",
"upstream-freebsd/lib/msun/src/s_floor.c",
"upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_llrint.c",
"upstream-freebsd/lib/msun/src/s_llrintf.c",
"upstream-freebsd/lib/msun/src/s_lrint.c",
"upstream-freebsd/lib/msun/src/s_lrintf.c",
"upstream-freebsd/lib/msun/src/s_rint.c",
"upstream-freebsd/lib/msun/src/s_rintf.c",
"upstream-freebsd/lib/msun/src/e_sqrt.c",
"upstream-freebsd/lib/msun/src/e_sqrtf.c",
"upstream-freebsd/lib/msun/src/s_trunc.c",
"upstream-freebsd/lib/msun/src/s_truncf.c",
],
},
mips: {
srcs: ["mips/fenv.c"],
},
mips64: {
srcs: ["mips/fenv.c"],
},
x86: {
local_include_dirs: ["i387"],
srcs: ["i387/fenv.c"],
// Clang has wrong long double sizes for x86.
clang: false,
},
x86_64: {
srcs: ["amd64/fenv.c"],
// Clang has wrong long double sizes for x86.
clang: false,
},
},
stl: "none",
}
// ANDROIDMK TRANSLATION ERROR: unsupported directive
// endif

117
linker/Android.bp Normal file
View File

@@ -0,0 +1,117 @@
linker_cflags = [
"-fno-stack-protector",
"-Wstrict-overflow=5",
"-fvisibility=hidden",
"-Wall",
"-Wextra",
"-Wunused",
"-Werror",
]
cc_binary {
srcs: [
"debugger.cpp",
"dlfcn.cpp",
"linker.cpp",
"linker_allocator.cpp",
"linker_block_allocator.cpp",
"linker_environ.cpp",
"linker_libc_support.c",
"linker_memory.cpp",
"linker_phdr.cpp",
"rt.cpp",
],
arch: {
arm: {
srcs: ["arch/arm/begin.S"],
},
arm64: {
srcs: ["arch/arm64/begin.S"],
},
x86: {
srcs: ["arch/x86/begin.c"],
},
x86_64: {
srcs: ["arch/x86_64/begin.S"],
},
mips: {
srcs: [
"arch/mips/begin.S",
"linker_mips.cpp",
],
},
mips64: {
srcs: [
"arch/mips64/begin.S",
"linker_mips.cpp",
],
},
},
// -shared is used to overwrite the -Bstatic and -static
// flags triggered by LOCAL_FORCE_STATIC_EXECUTABLE.
// This dynamic linker is actually a shared object linked with static
// libraries.
ldflags: [
"-shared",
"-Wl,-Bsymbolic",
"-Wl,--exclude-libs,ALL",
],
cflags: linker_cflags,
// TODO: split out the asflags.
asflags: linker_cflags,
target: {
android64: {
cflags: ["-DTARGET_IS_64_BIT"],
},
},
// We need to access Bionic private headers in the linker.
local_include_dirs: ["../libc/"],
conlyflags: ["-std=gnu99"],
cppflags: [
"-std=gnu++11",
"-Wold-style-cast",
],
// we don't want crtbegin.o (because we have begin.o), so unset it
// just for this module
nocrt: true,
static_libs: [
"libc_nomalloc",
"libziparchive",
"libutils",
"libz",
"liblog",
],
static_executable: true,
name: "linker",
multilib: {
lib32: {
stem: "linker",
},
lib64: {
stem: "linker64",
},
},
compile_multilib: "both",
// Leave the symbols in the shared library so that stack unwinders can
// produce meaningful name resolution.
strip: "keep_symbols",
// Insert an extra objcopy step to add prefix to symbols. This is needed to
// prevent gdb looking up symbols in the linker by mistake.
prefix_symbols: "__dl_",
}
subdirs = ["tests"]

View File

@@ -100,7 +100,7 @@ void* dlsym(void* handle, const char* symbol) {
}
soinfo* found = nullptr;
ElfW(Sym)* sym = nullptr;
const ElfW(Sym)* sym = nullptr;
void* caller_addr = __builtin_return_address(0);
soinfo* caller = find_containing_library(caller_addr);

View File

@@ -136,6 +136,17 @@ class LinkedList {
}
}
template<typename F>
T* find_if(F predicate) const {
for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
if (predicate(e->element)) {
return e->element;
}
}
return nullptr;
}
size_t copy_to_array(T* array[], size_t array_length) const {
size_t sz = 0;
for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, 2009 The Android Open Source Project
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,27 +55,12 @@
#include "linker_block_allocator.h"
#include "linker_debug.h"
#include "linker_environ.h"
#include "linker_leb128.h"
#include "linker_sleb128.h"
#include "linker_phdr.h"
#include "linker_relocs.h"
#include "linker_reloc_iterators.h"
#include "ziparchive/zip_archive.h"
/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
*
* Do NOT use malloc() and friends or pthread_*() code here.
* Don't use printf() either; it's caused mysterious memory
* corruption in the past.
* The linker runs before we bring up libc and it's easiest
* to make sure it does not depend on any complex libc features
*
* open issues / todo:
*
* - cleaner error reporting
* - after linking, set as much stuff as possible to READONLY
* and NOEXEC
*/
// Override macros to use C++ style casts
#undef ELF_ST_TYPE
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
@@ -100,6 +85,9 @@ static const char* const kDefaultLdPaths[] = {
nullptr
};
static const ElfW(Versym) kVersymNotNeeded = 0;
static const ElfW(Versym) kVersymGlobal = 1;
static std::vector<std::string> g_ld_library_paths;
static std::vector<std::string> g_ld_preload_names;
@@ -379,8 +367,129 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void
return rv;
}
ElfW(Sym)* soinfo::find_symbol_by_name(SymbolName& symbol_name) {
return is_gnu_hash() ? gnu_lookup(symbol_name) : elf_lookup(symbol_name);
const ElfW(Versym)* soinfo::get_versym(size_t n) const {
if (has_min_version(2) && versym_ != nullptr) {
return versym_ + n;
}
return nullptr;
}
ElfW(Addr) soinfo::get_verneed_ptr() const {
if (has_min_version(2)) {
return verneed_ptr_;
}
return 0;
}
size_t soinfo::get_verneed_cnt() const {
if (has_min_version(2)) {
return verneed_cnt_;
}
return 0;
}
ElfW(Addr) soinfo::get_verdef_ptr() const {
if (has_min_version(2)) {
return verdef_ptr_;
}
return 0;
}
size_t soinfo::get_verdef_cnt() const {
if (has_min_version(2)) {
return verdef_cnt_;
}
return 0;
}
template<typename F>
static bool for_each_verdef(const soinfo* si, F functor) {
if (!si->has_min_version(2)) {
return true;
}
uintptr_t verdef_ptr = si->get_verdef_ptr();
if (verdef_ptr == 0) {
return true;
}
size_t offset = 0;
size_t verdef_cnt = si->get_verdef_cnt();
for (size_t i = 0; i<verdef_cnt; ++i) {
const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
size_t verdaux_offset = offset + verdef->vd_aux;
offset += verdef->vd_next;
if (verdef->vd_version != 1) {
DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
i, verdef->vd_version, si->get_soname());
return false;
}
if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
// "this is the version of the file itself. It must not be used for
// matching a symbol. It can be used to match references."
//
// http://www.akkadia.org/drepper/symbol-versioning
continue;
}
if (verdef->vd_cnt == 0) {
DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
return false;
}
const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
if (functor(i, verdef, verdaux) == true) {
break;
}
}
return true;
}
bool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const {
if (vi == nullptr) {
*versym = kVersymNotNeeded;
return true;
}
*versym = kVersymGlobal;
return for_each_verdef(this,
[&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
if (verdef->vd_hash == vi->elf_hash &&
strcmp(vi->name, get_string(verdaux->vda_name)) == 0) {
*versym = verdef->vd_ndx;
return true;
}
return false;
}
);
}
bool soinfo::find_symbol_by_name(SymbolName& symbol_name,
const version_info* vi,
const ElfW(Sym)** symbol) const {
uint32_t symbol_index;
bool success =
is_gnu_hash() ?
gnu_lookup(symbol_name, vi, &symbol_index) :
elf_lookup(symbol_name, vi, &symbol_index);
if (success) {
*symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
}
return success;
}
static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
@@ -395,7 +504,23 @@ static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
return false;
}
ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name) {
static const ElfW(Versym) kVersymHiddenBit = 0x8000;
static inline bool is_versym_hidden(const ElfW(Versym)* versym) {
// the symbol is hidden if bit 15 of versym is set.
return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
}
static inline bool check_symbol_version(const ElfW(Versym) verneed,
const ElfW(Versym)* verdef) {
return verneed == kVersymNotNeeded ||
verdef == nullptr ||
verneed == (*verdef & ~kVersymHiddenBit);
}
bool soinfo::gnu_lookup(SymbolName& symbol_name,
const version_info* vi,
uint32_t* symbol_index) const {
uint32_t hash = symbol_name.gnu_hash();
uint32_t h2 = hash >> gnu_shift2_;
@@ -403,6 +528,8 @@ ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name) {
uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
*symbol_index = 0;
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
@@ -411,7 +538,7 @@ ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name) {
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
return nullptr;
return true;
}
// bloom test says "probably yes"...
@@ -421,43 +548,77 @@ ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name) {
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
return nullptr;
return true;
}
// lookup versym for the version definition in this library
// note the difference between "version is not requested" (vi == nullptr)
// and "version not found". In the first case verneed is kVersymNotNeeded
// which implies that the default version can be accepted; the second case results in
// verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
// for this library and consider only *global* ones.
ElfW(Versym) verneed = 0;
if (!find_verdef_version_index(vi, &verneed)) {
return false;
}
do {
ElfW(Sym)* s = symtab_ + n;
const ElfW(Versym)* verdef = get_versym(n);
// skip hidden versions when verneed == kVersymNotNeeded (0)
if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
continue;
}
if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
check_symbol_version(verneed, verdef) &&
strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
is_symbol_global_and_defined(this, s)) {
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(s->st_value),
static_cast<size_t>(s->st_size));
return s;
*symbol_index = n;
return true;
}
} while ((gnu_chain_[n++] & 1) == 0);
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
return nullptr;
return true;
}
ElfW(Sym)* soinfo::elf_lookup(SymbolName& symbol_name) {
bool soinfo::elf_lookup(SymbolName& symbol_name,
const version_info* vi,
uint32_t* symbol_index) const {
uint32_t hash = symbol_name.elf_hash();
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
symbol_name.get_name(), get_soname(),
reinterpret_cast<void*>(base), hash, hash % nbucket_);
ElfW(Versym) verneed = 0;
if (!find_verdef_version_index(vi, &verneed)) {
return false;
}
for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
ElfW(Sym)* s = symtab_ + n;
if (strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
const ElfW(Versym)* verdef = get_versym(n);
// skip hidden versions when verneed == 0
if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
continue;
}
if (check_symbol_version(verneed, verdef) &&
strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
is_symbol_global_and_defined(this, s)) {
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
symbol_name.get_name(), get_soname(),
reinterpret_cast<void*>(s->st_value),
static_cast<size_t>(s->st_size));
return s;
*symbol_index = n;
return true;
}
}
@@ -465,7 +626,8 @@ ElfW(Sym)* soinfo::elf_lookup(SymbolName& symbol_name) {
symbol_name.get_name(), get_soname(),
reinterpret_cast<void*>(base), hash, hash % nbucket_);
return nullptr;
*symbol_index = 0;
return true;
}
soinfo::soinfo(const char* realpath, const struct stat* file_stat,
@@ -523,10 +685,11 @@ uint32_t SymbolName::gnu_hash() {
return gnu_hash_;
}
ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) {
bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
SymbolName symbol_name(name);
ElfW(Sym)* s = nullptr;
const ElfW(Sym)* s = nullptr;
/* "This element's presence in a shared object library alters the dynamic linker's
* symbol resolution algorithm for references within the library. Instead of starting
@@ -541,7 +704,10 @@ ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found
*/
if (si_from->has_DT_SYMBOLIC) {
DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_soname(), name);
s = si_from->find_symbol_by_name(symbol_name);
if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
return false;
}
if (s != nullptr) {
*si_found_in = si_from;
}
@@ -549,10 +715,15 @@ ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found
// 1. Look for it in global_group
if (s == nullptr) {
bool error = false;
global_group.visit([&](soinfo* global_si) {
DEBUG("%s: looking up %s in %s (from global group)",
si_from->get_soname(), name, global_si->get_soname());
s = global_si->find_symbol_by_name(symbol_name);
if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
error = true;
return false;
}
if (s != nullptr) {
*si_found_in = global_si;
return false;
@@ -560,10 +731,15 @@ ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found
return true;
});
if (error) {
return false;
}
}
// 2. Look for it in the local group
if (s == nullptr) {
bool error = false;
local_group.visit([&](soinfo* local_si) {
if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
// we already did this - skip
@@ -572,7 +748,11 @@ ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found
DEBUG("%s: looking up %s in %s (from local group)",
si_from->get_soname(), name, local_si->get_soname());
s = local_si->find_symbol_by_name(symbol_name);
if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
error = true;
return false;
}
if (s != nullptr) {
*si_found_in = local_si;
return false;
@@ -580,6 +760,10 @@ ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found
return true;
});
if (error) {
return false;
}
}
if (s != nullptr) {
@@ -590,7 +774,8 @@ ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found
reinterpret_cast<void*>((*si_found_in)->load_bias));
}
return s;
*symbol = s;
return true;
}
class ProtectedDataGuard {
@@ -735,13 +920,16 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
// This is used by dlsym(3). It performs symbol lookup only within the
// specified soinfo object and its dependencies in breadth first order.
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
ElfW(Sym)* result = nullptr;
const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
const ElfW(Sym)* result = nullptr;
SymbolName symbol_name(name);
walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) {
result = current_soinfo->find_symbol_by_name(symbol_name);
if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
result = nullptr;
return false;
}
if (result != nullptr) {
*found = current_soinfo;
return false;
@@ -758,7 +946,10 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
beginning of the global solist. Otherwise the search starts at the
specified soinfo (for RTLD_NEXT).
*/
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle) {
const ElfW(Sym)* dlsym_linear_lookup(const char* name,
soinfo** found,
soinfo* caller,
void* handle) {
SymbolName symbol_name(name);
soinfo* start = solist;
@@ -771,13 +962,16 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller,
}
}
ElfW(Sym)* s = nullptr;
const ElfW(Sym)* s = nullptr;
for (soinfo* si = start; si != nullptr; si = si->next) {
if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
continue;
}
s = si->find_symbol_by_name(symbol_name);
if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
return nullptr;
}
if (s != nullptr) {
*found = si;
break;
@@ -800,7 +994,10 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller,
break;
}
s = si->find_symbol_by_name(symbol_name);
if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
return nullptr;
}
if (s != nullptr) {
*found = si;
break;
@@ -1444,6 +1641,93 @@ static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
return ifunc_addr;
}
const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
if (source_symver < 2 ||
source_symver >= version_infos.size() ||
version_infos[source_symver].name == nullptr) {
return nullptr;
}
return &version_infos[source_symver];
}
void VersionTracker::add_version_info(size_t source_index,
ElfW(Word) elf_hash,
const char* ver_name,
const soinfo* target_si) {
if (source_index >= version_infos.size()) {
version_infos.resize(source_index+1);
}
version_infos[source_index].elf_hash = elf_hash;
version_infos[source_index].name = ver_name;
version_infos[source_index].target_si = target_si;
}
bool VersionTracker::init_verneed(const soinfo* si_from) {
uintptr_t verneed_ptr = si_from->get_verneed_ptr();
if (verneed_ptr == 0) {
return true;
}
size_t verneed_cnt = si_from->get_verneed_cnt();
for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
size_t vernaux_offset = offset + verneed->vn_aux;
offset += verneed->vn_next;
if (verneed->vn_version != 1) {
DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
return false;
}
const char* target_soname = si_from->get_string(verneed->vn_file);
// find it in dependencies
soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
return strcmp(si->get_soname(), target_soname) == 0;
});
if (target_si == nullptr) {
DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
target_soname, i, si_from->get_soname());
return false;
}
for (size_t j = 0; j<verneed->vn_cnt; ++j) {
const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
vernaux_offset += vernaux->vna_next;
const ElfW(Word) elf_hash = vernaux->vna_hash;
const char* ver_name = si_from->get_string(vernaux->vna_name);
ElfW(Half) source_index = vernaux->vna_other;
add_version_info(source_index, elf_hash, ver_name, target_si);
}
}
return true;
}
bool VersionTracker::init_verdef(const soinfo* si_from) {
return for_each_verdef(si_from,
[&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
add_version_info(verdef->vd_ndx, verdef->vd_hash,
si_from->get_string(verdaux->vda_name), si_from);
return false;
}
);
}
bool VersionTracker::init(const soinfo* si_from) {
if (!si_from->has_min_version(2)) {
return true;
}
return init_verneed(si_from) && init_verdef(si_from);
}
#if !defined(__mips__)
#if defined(USE_RELA)
static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
@@ -1462,6 +1746,12 @@ static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
template<typename ElfRelIteratorT>
bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
const soinfo_list_t& local_group) {
VersionTracker version_tracker;
if (!version_tracker.init(this)) {
return false;
}
for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
const auto rel = rel_iterator.next();
if (rel == nullptr) {
@@ -1481,12 +1771,32 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
continue;
}
ElfW(Sym)* s = nullptr;
const ElfW(Sym)* s = nullptr;
soinfo* lsi = nullptr;
if (sym != 0) {
sym_name = get_string(symtab_[sym].st_name);
s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group);
const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) {
// there is no version info for this one
if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
return false;
}
} else {
const version_info* vi = version_tracker.get_version_info(sym_ver);
if (vi == nullptr) {
DL_ERR("cannot find verneed/verdef for version index=%d "
"referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname());
return false;
}
if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
return false;
}
}
if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference...
s = &symtab_[sym];
@@ -1977,6 +2287,14 @@ soinfo::soinfo_list_t& soinfo::get_children() {
return g_empty_list;
}
const soinfo::soinfo_list_t& soinfo::get_children() const {
if (has_min_version(0)) {
return children_;
}
return g_empty_list;
}
soinfo::soinfo_list_t& soinfo::get_parents() {
if (has_min_version(0)) {
return parents_;
@@ -1985,7 +2303,7 @@ soinfo::soinfo_list_t& soinfo::get_parents() {
return g_empty_list;
}
ElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) {
ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
return call_ifunc_resolver(s->st_value + load_bias);
}
@@ -2111,7 +2429,7 @@ bool soinfo::prelink_image() {
/* We can't log anything until the linker is relocated */
bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
if (!relocating_linker) {
INFO("[ linking %s ]", get_soname());
INFO("[ linking %s ]", get_realpath());
DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
}
@@ -2452,12 +2770,23 @@ bool soinfo::prelink_image() {
case DT_BIND_NOW:
break;
// Ignore: bionic does not support symbol versioning...
case DT_VERSYM:
versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
break;
case DT_VERDEF:
verdef_ptr_ = load_bias + d->d_un.d_ptr;
break;
case DT_VERDEFNUM:
verdef_cnt_ = d->d_un.d_val;
break;
case DT_VERNEED:
verneed_ptr_ = load_bias + d->d_un.d_ptr;
break;
case DT_VERNEEDNUM:
verneed_cnt_ = d->d_un.d_val;
break;
default:
@@ -2531,7 +2860,7 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
if (android_relocs_size_ > 3 &&
android_relocs_[0] == 'A' &&
android_relocs_[1] == 'P' &&
(android_relocs_[2] == 'U' || android_relocs_[2] == 'S') &&
android_relocs_[2] == 'S' &&
android_relocs_[3] == '2') {
DEBUG("[ android relocating %s ]", get_soname());
@@ -2539,17 +2868,10 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
const uint8_t* packed_relocs = android_relocs_ + 4;
const size_t packed_relocs_size = android_relocs_size_ - 4;
if (android_relocs_[2] == 'U') {
relocated = relocate(
packed_reloc_iterator<leb128_decoder>(
leb128_decoder(packed_relocs, packed_relocs_size)),
global_group, local_group);
} else { // android_relocs_[2] == 'S'
relocated = relocate(
packed_reloc_iterator<sleb128_decoder>(
sleb128_decoder(packed_relocs, packed_relocs_size)),
global_group, local_group);
}
relocated = relocate(
packed_reloc_iterator<sleb128_decoder>(
sleb128_decoder(packed_relocs, packed_relocs_size)),
global_group, local_group);
if (!relocated) {
return false;
@@ -2813,6 +3135,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
for (const auto& ld_preload_name : g_ld_preload_names) {
needed_library_name_list.push_back(ld_preload_name.c_str());
++needed_libraries_count;
++ld_preloads_count;
}
for_each_dt_needed(si, [&](const char* name) {

View File

@@ -40,6 +40,7 @@
#include "linked_list.h"
#include <string>
#include <vector>
#define DL_ERR(fmt, x...) \
do { \
@@ -142,6 +143,32 @@ class SymbolName {
DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolName);
};
struct version_info {
version_info() : elf_hash(0), name(nullptr), target_si(nullptr) {}
uint32_t elf_hash;
const char* name;
const soinfo* target_si;
};
// Class used construct version dependency graph.
class VersionTracker {
public:
VersionTracker() = default;
bool init(const soinfo* si_from);
const version_info* get_version_info(ElfW(Versym) source_symver) const;
private:
bool init_verneed(const soinfo* si_from);
bool init_verdef(const soinfo* si_from);
void add_version_info(size_t source_index, ElfW(Word) elf_hash,
const char* ver_name, const soinfo* target_si);
std::vector<version_info> version_infos;
DISALLOW_COPY_AND_ASSIGN(VersionTracker);
};
struct soinfo {
public:
typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
@@ -260,11 +287,16 @@ struct soinfo {
void set_dt_flags_1(uint32_t dt_flags_1);
soinfo_list_t& get_children();
const soinfo_list_t& get_children() const;
soinfo_list_t& get_parents();
ElfW(Sym)* find_symbol_by_name(SymbolName& symbol_name);
bool find_symbol_by_name(SymbolName& symbol_name,
const version_info* vi,
const ElfW(Sym)** symbol) const;
ElfW(Sym)* find_symbol_by_address(const void* addr);
ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s);
ElfW(Addr) resolve_symbol_address(const ElfW(Sym)* s) const;
const char* get_string(ElfW(Word) index) const;
bool can_unload() const;
@@ -292,11 +324,18 @@ struct soinfo {
const char* get_soname() const;
const char* get_realpath() const;
const ElfW(Versym)* get_versym(size_t n) const;
ElfW(Addr) get_verneed_ptr() const;
size_t get_verneed_cnt() const;
ElfW(Addr) get_verdef_ptr() const;
size_t get_verdef_cnt() const;
bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
private:
ElfW(Sym)* elf_lookup(SymbolName& symbol_name);
bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
ElfW(Sym)* elf_addr_lookup(const void* addr);
ElfW(Sym)* gnu_lookup(SymbolName& symbol_name);
bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
ElfW(Sym)* gnu_addr_lookup(const void* addr);
void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
@@ -341,11 +380,20 @@ struct soinfo {
const char* soname_;
std::string realpath_;
const ElfW(Versym)* versym_;
ElfW(Addr) verdef_ptr_;
size_t verdef_cnt_;
ElfW(Addr) verneed_ptr_;
size_t verneed_cnt_;
friend soinfo* get_libdl_info();
};
ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group);
bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol);
enum RelocationKind {
kRelocAbsolute = 0,
@@ -364,10 +412,10 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
void do_dlclose(soinfo* si);
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
const ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
soinfo* find_containing_library(const void* addr);
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
void debuggerd_init();
extern "C" abort_msg_t* g_abort_message;

View File

@@ -36,7 +36,6 @@
#include "private/KernelArgumentBlock.h"
static char** _envp;
static bool _AT_SECURE_value = true;
bool get_AT_SECURE() {
@@ -150,8 +149,8 @@ static bool __is_unsafe_environment_variable(const char* name) {
}
static void __sanitize_environment_variables() {
char** src = _envp;
char** dst = _envp;
char** src = environ;
char** dst = environ;
for (; src[0] != nullptr; ++src) {
if (!__is_valid_environment_variable(src[0])) {
continue;
@@ -168,7 +167,7 @@ static void __sanitize_environment_variables() {
void linker_env_init(KernelArgumentBlock& args) {
// Store environment pointer - can't be null.
_envp = args.envp;
environ = args.envp;
__init_AT_SECURE(args);
__sanitize_environment_variables();
@@ -179,7 +178,7 @@ const char* linker_env_get(const char* name) {
return nullptr;
}
for (char** p = _envp; p[0] != nullptr; ++p) {
for (char** p = environ; p[0] != nullptr; ++p) {
const char* val = env_match(p[0], name);
if (val != nullptr) {
if (val[0] == '\0') {

View File

@@ -30,7 +30,7 @@
#include "linker_debug.h"
#include "linker_relocs.h"
#include "linker_reloc_iterators.h"
#include "linker_leb128.h"
#include "linker_sleb128.h"
template bool soinfo::relocate<plain_reloc_iterator>(plain_reloc_iterator&& rel_iterator,
const soinfo_list_t& global_group,
@@ -41,15 +41,16 @@ template bool soinfo::relocate<packed_reloc_iterator<sleb128_decoder>>(
const soinfo_list_t& global_group,
const soinfo_list_t& local_group);
template bool soinfo::relocate<packed_reloc_iterator<leb128_decoder>>(
packed_reloc_iterator<leb128_decoder>&& rel_iterator,
const soinfo_list_t& global_group,
const soinfo_list_t& local_group);
template <typename ElfRelIteratorT>
bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group,
const soinfo_list_t& local_group) {
VersionTracker version_tracker;
if (!version_tracker.init(this)) {
return false;
}
for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
const auto rel = rel_iterator.next();
@@ -69,12 +70,33 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
continue;
}
ElfW(Sym)* s = nullptr;
const ElfW(Sym)* s = nullptr;
soinfo* lsi = nullptr;
if (sym != 0) {
sym_name = get_string(symtab_[sym].st_name);
s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group);
const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) {
// there is no version info for this one
if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
return false;
}
} else {
const version_info* vi = version_tracker.get_version_info(sym_ver);
if (vi == nullptr) {
DL_ERR("cannot find verneed/verdef for version index=%d "
"referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname());
return false;
}
if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
return false;
}
}
if (s == nullptr) {
// mips does not support relocation with weak-undefined symbols
DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_soname());
@@ -147,7 +169,11 @@ bool soinfo::mips_relocate_got(const soinfo_list_t& global_group,
// This is an undefined reference... try to locate it.
const char* sym_name = get_string(sym->st_name);
soinfo* lsi = nullptr;
ElfW(Sym)* s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group);
const ElfW(Sym)* s = nullptr;
if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
return false;
}
if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference.
s = &symtab_[g];

View File

@@ -14,42 +14,14 @@
* limitations under the License.
*/
#ifndef _LINKER_LEB128_H
#define _LINKER_LEB128_H
#ifndef _LINKER_SLEB128_H
#define _LINKER_SLEB128_H
#include <stdint.h>
// Helper classes for decoding LEB128, used in packed relocation data.
// http://en.wikipedia.org/wiki/LEB128
class leb128_decoder {
public:
leb128_decoder(const uint8_t* buffer, size_t count)
: current_(buffer), end_(buffer + count) { }
size_t pop_front() {
size_t value = 0;
size_t shift = 0;
uint8_t byte;
do {
if (current_ >= end_) {
__libc_fatal("leb128_decoder ran out of bounds");
}
byte = *current_++;
value |= static_cast<size_t>(byte & 127) << shift;
shift += 7;
} while (byte & 128);
return value;
}
private:
const uint8_t* current_;
const uint8_t* const end_;
};
class sleb128_decoder {
public:
sleb128_decoder(const uint8_t* buffer, size_t count)
@@ -64,7 +36,7 @@ class sleb128_decoder {
do {
if (current_ >= end_) {
__libc_fatal("leb128_decoder ran out of bounds");
__libc_fatal("sleb128_decoder ran out of bounds");
}
byte = *current_++;
value |= (static_cast<size_t>(byte & 127) << shift);
@@ -83,5 +55,4 @@ class sleb128_decoder {
const uint8_t* const end_;
};
#endif // __LINKER_LEB128_H
#endif // __LINKER_SLEB128_H

47
linker/tests/Android.bp Normal file
View File

@@ -0,0 +1,47 @@
//
// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
cc_test {
name: "linker-unit-tests",
multilib: {
lib32: {
stem: "linker-unit-tests32",
},
lib64: {
stem: "linker-unit-tests64",
},
},
cflags: [
"-g",
"-Wall",
"-Wextra",
"-Wunused",
"-Werror",
"-std=gnu++11",
],
local_include_dirs: ["/../../libc/"],
srcs: [
"linked_list_test.cpp",
"linker_block_allocator_test.cpp",
"../linker_block_allocator.cpp",
"linker_memory_allocator_test.cpp",
"../linker_allocator.cpp",
// for __libc_fatal
"../../libc/bionic/libc_logging.cpp",
],
}

View File

@@ -295,9 +295,7 @@ bionic-unit-tests_shared_libraries_target := \
# which bionic does not support. Reenable this once this question is resolved.
bionic-unit-tests_clang_target := false
ifneq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH))
bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global
endif
module := bionic-unit-tests
module_tag := optional

View File

@@ -35,7 +35,7 @@ class ClassWithDtor {
std::string message;
};
thread_local ClassWithDtor class_with_dtor;
static thread_local ClassWithDtor class_with_dtor;
static void* thread_nop(void* arg) {
class_with_dtor.set_message(*static_cast<std::string*>(arg));
@@ -50,6 +50,29 @@ TEST(thread_local, smoke) {
ASSERT_EQ("dtor called.", class_with_dtor_output);
}
class ClassWithDtorForMainThread {
public:
void set_message(const std::string& msg) {
message = msg;
}
~ClassWithDtorForMainThread() {
fprintf(stderr, "%s", message.c_str());
}
private:
std::string message;
};
static void thread_atexit_main() {
static thread_local ClassWithDtorForMainThread class_with_dtor_for_main_thread;
class_with_dtor_for_main_thread.set_message("d-tor for main thread called.");
exit(0);
}
TEST(thread_local, dtor_for_main_thread) {
ASSERT_EXIT(thread_atexit_main(), testing::ExitedWithCode(0), "d-tor for main thread called.");
}
extern "C" int __cxa_thread_atexit_impl(void (*fn)(void*), void* arg, void* dso_handle);
static void thread_atexit_fn1(void* arg) {

View File

@@ -134,6 +134,10 @@ TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
// lib_path is relative when $ANDROID_DATA is relative
char lib_realpath_buf[PATH_MAX];
ASSERT_TRUE(realpath(lib_path.c_str(), lib_realpath_buf) == lib_realpath_buf);
const std::string lib_realpath = std::string(lib_realpath_buf);
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
@@ -158,7 +162,7 @@ TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
extinfo.library_fd_offset = PAGE_SIZE;
handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
ASSERT_TRUE(handle_ == nullptr);
ASSERT_EQ("dlopen failed: \"" + lib_path + "\" has bad ELF magic", dlerror());
ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror());
close(extinfo.library_fd);
}

View File

@@ -626,7 +626,6 @@ TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
}
TEST(dlfcn, dlsym_df_1_global) {
#if !defined(__arm__) && !defined(__aarch64__)
void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
int (*get_answer)();
@@ -634,9 +633,6 @@ TEST(dlfcn, dlsym_df_1_global) {
ASSERT_TRUE(get_answer != nullptr) << dlerror();
ASSERT_EQ(42, get_answer());
ASSERT_EQ(0, dlclose(handle));
#else
GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n";
#endif
}
TEST(dlfcn, dlopen_failure) {
@@ -764,7 +760,11 @@ TEST(dlfcn, dladdr_libc) {
void* addr = reinterpret_cast<void*>(puts); // well-known libc function
ASSERT_TRUE(dladdr(addr, &info) != 0);
ASSERT_STREQ(BIONIC_PATH_TO_LIBC, info.dli_fname);
// /system/lib is symlink when this test is executed on host.
char libc_realpath[PATH_MAX];
ASSERT_TRUE(realpath(BIONIC_PATH_TO_LIBC, libc_realpath) == libc_realpath);
ASSERT_STREQ(libc_realpath, info.dli_fname);
// TODO: add check for dfi_fbase
ASSERT_STREQ("puts", info.dli_sname);
ASSERT_EQ(addr, info.dli_saddr);
@@ -921,3 +921,63 @@ TEST(dlfcn, dlopen_dlopen_from_ctor) {
GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
#endif
}
TEST(dlfcn, symbol_versioning_use_v1) {
void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*fn_t)();
fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
ASSERT_TRUE(fn != nullptr) << dlerror();
ASSERT_EQ(1, fn());
dlclose(handle);
}
TEST(dlfcn, symbol_versioning_use_v2) {
void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*fn_t)();
fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
ASSERT_TRUE(fn != nullptr) << dlerror();
ASSERT_EQ(2, fn());
dlclose(handle);
}
TEST(dlfcn, symbol_versioning_use_other_v2) {
void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*fn_t)();
fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
ASSERT_TRUE(fn != nullptr) << dlerror();
ASSERT_EQ(20, fn());
dlclose(handle);
}
TEST(dlfcn, symbol_versioning_use_other_v3) {
void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*fn_t)();
fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
ASSERT_TRUE(fn != nullptr) << dlerror();
ASSERT_EQ(3, fn());
dlclose(handle);
}
TEST(dlfcn, symbol_versioning_default_via_dlsym) {
void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*fn_t)();
fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
ASSERT_TRUE(fn != nullptr) << dlerror();
ASSERT_EQ(3, fn()); // the default version is 3
dlclose(handle);
}
// This preempts the implementation from libtest_versioned_lib.so
extern "C" int version_zero_function() {
return 0;
}
// This preempts the implementation from libtest_versioned_uselibv*.so
extern "C" int version_zero_function2() {
return 0;
}

View File

@@ -623,6 +623,22 @@ TEST_F(DEATHTEST, FD_ISSET_2_fortified) {
ASSERT_FORTIFY(FD_ISSET(0, set));
}
TEST_F(DEATHTEST, pread_fortified) {
char buf[1];
size_t ct = atoi("2"); // prevent optimizations
int fd = open("/dev/null", O_RDONLY);
ASSERT_FORTIFY(pread(fd, buf, ct, 0));
close(fd);
}
TEST_F(DEATHTEST, pread64_fortified) {
char buf[1];
size_t ct = atoi("2"); // prevent optimizations
int fd = open("/dev/null", O_RDONLY);
ASSERT_FORTIFY(pread64(fd, buf, ct, 0));
close(fd);
}
TEST_F(DEATHTEST, read_fortified) {
char buf[1];
size_t ct = atoi("2"); // prevent optimizations
@@ -631,6 +647,18 @@ TEST_F(DEATHTEST, read_fortified) {
close(fd);
}
TEST_F(DEATHTEST, readlink_fortified) {
char buf[1];
size_t ct = atoi("2"); // prevent optimizations
ASSERT_FORTIFY(readlink("/dev/null", buf, ct));
}
TEST_F(DEATHTEST, readlinkat_fortified) {
char buf[1];
size_t ct = atoi("2"); // prevent optimizations
ASSERT_FORTIFY(readlinkat(AT_FDCWD, "/dev/null", buf, ct));
}
extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
extern "C" char* __strcat_chk(char*, const char*, size_t);

View File

@@ -0,0 +1,25 @@
#
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# -----------------------------------------------------------------------------
# This library used to test phtread_atfork handler behaviour
# during/after dlclose.
# -----------------------------------------------------------------------------
libtest_pthread_atfork_src_files := pthread_atfork.cpp
module := libtest_pthread_atfork
include $(LOCAL_PATH)/Android.build.testlib.mk

View File

@@ -0,0 +1,120 @@
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# -----------------------------------------------------------------------------
# Libraries used to test versioned symbols
# -----------------------------------------------------------------------------
libtest_versioned_uselibv1_src_files := versioned_uselib.cpp
libtest_versioned_uselibv1_shared_libraries := \
libtest_versioned_libv1
module := libtest_versioned_uselibv1
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
libtest_versioned_uselibv2_src_files := \
versioned_uselib.cpp
libtest_versioned_uselibv2_shared_libraries := \
libtest_versioned_libv2
libtest_versioned_uselibv2_ldflags := \
-Wl,--version-script,$(LOCAL_PATH)/versioned_uselib.map
module := libtest_versioned_uselibv2
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
libtest_versioned_uselibv2_other_src_files := \
versioned_uselib.cpp
libtest_versioned_uselibv2_other_shared_libraries := \
libtest_versioned_otherlib_empty libtest_versioned_libv2
module := libtest_versioned_uselibv2_other
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
libtest_versioned_uselibv3_other_src_files := \
versioned_uselib.cpp
libtest_versioned_uselibv3_other_shared_libraries := \
libtest_versioned_otherlib_empty libtest_versioned_lib
module := libtest_versioned_uselibv3_other
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
# lib v1 - this one used during static linking but never used at runtime
# which forces libtest_versioned_uselibv1 to use function v1 from
# libtest_versioned_lib.so
# -----------------------------------------------------------------------------
libtest_versioned_libv1_src_files := \
versioned_lib_v1.cpp
libtest_versioned_libv1_ldflags := \
-Wl,--version-script,$(LOCAL_PATH)/versioned_lib_v1.map \
-Wl,-soname,libtest_versioned_lib.so
module := libtest_versioned_libv1
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
# lib v2 - to make libtest_versioned_uselibv2.so use version 2 of versioned_function()
# -----------------------------------------------------------------------------
libtest_versioned_libv2_src_files := \
versioned_lib_v2.cpp
libtest_versioned_libv2_ldflags := \
-Wl,--version-script,$(LOCAL_PATH)/versioned_lib_v2.map \
-Wl,-soname,libtest_versioned_lib.so
module := libtest_versioned_libv2
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
# last version - this one is used at the runtime and exports 3 versions
# of versioned_symbol().
# -----------------------------------------------------------------------------
libtest_versioned_lib_src_files := \
versioned_lib_v3.cpp
libtest_versioned_lib_ldflags := \
-Wl,--version-script,$(LOCAL_PATH)/versioned_lib_v3.map
module := libtest_versioned_lib
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
# This library is empty, the actual implementation will provide an unversioned
# symbol for versioned_function().
# -----------------------------------------------------------------------------
libtest_versioned_otherlib_empty_src_files := empty.cpp
libtest_versioned_otherlib_empty_ldflags := -Wl,-soname,libtest_versioned_otherlib.so
module := libtest_versioned_otherlib_empty
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
libtest_versioned_otherlib_src_files := versioned_lib_other.cpp
libtest_versioned_otherlib_ldflags := \
-Wl,--version-script,$(LOCAL_PATH)/versioned_lib_other.map
module := libtest_versioned_otherlib
include $(LOCAL_PATH)/Android.build.testlib.mk

View File

@@ -25,7 +25,9 @@ common_additional_dependencies := \
$(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \
$(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \
$(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \
$(LOCAL_PATH)/Android.build.pthread_atfork.mk \
$(LOCAL_PATH)/Android.build.testlib.mk \
$(LOCAL_PATH)/Android.build.versioned_lib.mk \
$(TEST_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
@@ -197,6 +199,16 @@ include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk
# -----------------------------------------------------------------------------
include $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk
# -----------------------------------------------------------------------------
# Build libtest_versioned_lib.so with its dependencies.
# -----------------------------------------------------------------------------
include $(LOCAL_PATH)/Android.build.versioned_lib.mk
# -----------------------------------------------------------------------------
# Build libraries needed by pthread_atfork tests
# -----------------------------------------------------------------------------
include $(LOCAL_PATH)/Android.build.pthread_atfork.mk
# -----------------------------------------------------------------------------
# Library with dependency loop used by dlfcn tests
#
@@ -342,17 +354,17 @@ include $(LOCAL_PATH)/Android.build.testlib.mk
# Library with DF_1_GLOBAL
# -----------------------------------------------------------------------------
libdl_test_df_1_global_src_files := dl_df_1_global.cpp
libdl_test_df_1_global_ldflags := -fuse-ld=bfd -Wl,-z,global
module := libdl_test_df_1_global
# TODO: re-enable arm once b/18137520 or b/18130452 are fixed
ifeq ($(filter $(TARGET_ARCH),arm arm64),)
include $(LOCAL_PATH)/Android.build.testlib.mk
else
# build it for host only
build_target := SHARED_LIBRARY
build_type := host
include $(TEST_PATH)/Android.build.mk
libdl_test_df_1_global_ldflags := -Wl,-z,global
# TODO (dimitry): x86* toolchain does not support -z global - switch to bfd
ifeq ($(filter $(TARGET_ARCH),x86 x86_64),$(TARGET_ARCH))
libdl_test_df_1_global_ldflags_target := -fuse-ld=bfd
endif
# TODO (dimitry): host ld.gold does not yet support -z global
# remove this line once it is updated.
libdl_test_df_1_global_ldflags_host := -fuse-ld=bfd
module := libdl_test_df_1_global
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
# Library using symbol from libdl_test_df_1_global

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pthread.h>
extern "C" int proxy_pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) {
return pthread_atfork(prepare, parent, child);
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" int versioned_function_v2() {
return 20;
}
__asm__(".symver versioned_function_v2,versioned_function@@TESTLIB_V2");

View File

@@ -0,0 +1,9 @@
TESTLIB_V0 {
local:
versioned_function_v*;
};
TESTLIB_V2 {
global:
versioned_function;
} TESTLIB_V0;

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" {
int versioned_function_v1(); // __attribute__((visibility("hidden")));
int version_zero_function();
}
int versioned_function_v1() {
return 1;
}
int version_zero_function() {
return 100;
}
__asm__(".symver versioned_function_v1,versioned_function@@TESTLIB_V1");

View File

@@ -0,0 +1,12 @@
TESTLIB_V0 {
global:
version_zero_function;
local:
versioned_function_v*;
};
TESTLIB_V1 {
global:
versioned_function;
} TESTLIB_V0;

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" {
int versioned_function_v1(); // __attribute__((visibility("hidden")));
int versioned_function_v2(); // __attribute__((visibility("hidden")));
int version_zero_function();
}
int versioned_function_v1() {
return 1;
}
int versioned_function_v2() {
return 2;
}
int version_zero_function() {
return 200;
}
__asm__(".symver versioned_function_v1,versioned_function@TESTLIB_V1");
__asm__(".symver versioned_function_v2,versioned_function@@TESTLIB_V2");

View File

@@ -0,0 +1,16 @@
TESTLIB_V0 {
global:
version_zero_function;
local:
versioned_function_v*;
};
TESTLIB_V1 {
global:
versioned_function;
} TESTLIB_V0;
TESTLIB_V2 {
global:
versioned_function;
} TESTLIB_V1;

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" {
int versioned_function_v1(); // __attribute__((visibility("hidden")));
int versioned_function_v2(); // __attribute__((visibility("hidden")));
int versioned_function_v3(); // __attribute__((visibility("hidden")));
int version_zero_function();
}
int versioned_function_v1() {
return 1;
}
int versioned_function_v2() {
return 2;
}
int versioned_function_v3() {
return 3;
}
int version_zero_function() {
return 1000;
}
__asm__(".symver versioned_function_v1,versioned_function@TESTLIB_V1");
__asm__(".symver versioned_function_v2,versioned_function@TESTLIB_V2");
__asm__(".symver versioned_function_v3,versioned_function@@TESTLIB_V3");

View File

@@ -0,0 +1,21 @@
TESTLIB_V0 {
global:
version_zero_function;
local:
versioned_function_v*;
};
TESTLIB_V1 {
global:
versioned_function;
} TESTLIB_V0;
TESTLIB_V2 {
global:
versioned_function;
} TESTLIB_V1;
TESTLIB_V3 {
global:
versioned_function;
} TESTLIB_V2;

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" {
int versioned_function();
int get_function_version();
int version_zero_function();
int version_zero_function2() __attribute__((weak));
}
int get_function_version() {
return version_zero_function2() + version_zero_function() + versioned_function();
}
// we expect this function to be preempted by main executable.
int version_zero_function2() {
return 40000;
}

View File

@@ -0,0 +1,9 @@
TESTLIB_NONE {
global:
get_function_version;
};
TESTLIB_ZERO {
global:
version_zero_function2;
} TESTLIB_NONE;

View File

@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
#include <dlfcn.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
@@ -181,6 +182,19 @@ TEST(pthread, pthread_key_dirty) {
ASSERT_EQ(0, pthread_key_delete(key));
}
TEST(pthread, static_pthread_key_used_before_creation) {
#if defined(__BIONIC__)
// See http://b/19625804. The bug is about a static/global pthread key being used before creation.
// So here tests if the static/global default value 0 can be detected as invalid key.
static pthread_key_t key;
ASSERT_EQ(nullptr, pthread_getspecific(key));
ASSERT_EQ(EINVAL, pthread_setspecific(key, nullptr));
ASSERT_EQ(EINVAL, pthread_key_delete(key));
#else
GTEST_LOG_(INFO) << "This test tests bionic pthread key implementation detail.\n";
#endif
}
static void* IdFn(void* arg) {
return arg;
}
@@ -390,7 +404,9 @@ TEST(pthread, pthread_sigmask) {
}
TEST(pthread, pthread_setname_np__too_long) {
ASSERT_EQ(ERANGE, pthread_setname_np(pthread_self(), "this name is far too long for linux"));
// The limit is 15 characters --- the kernel's buffer is 16, but includes a NUL.
ASSERT_EQ(0, pthread_setname_np(pthread_self(), "123456789012345"));
ASSERT_EQ(ERANGE, pthread_setname_np(pthread_self(), "1234567890123456"));
}
TEST(pthread, pthread_setname_np__self) {
@@ -660,6 +676,37 @@ TEST(pthread, pthread_attr_setstacksize) {
#endif // __BIONIC__
}
TEST(pthread, pthread_rwlockattr_smoke) {
pthread_rwlockattr_t attr;
ASSERT_EQ(0, pthread_rwlockattr_init(&attr));
int pshared_value_array[] = {PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED};
for (size_t i = 0; i < sizeof(pshared_value_array) / sizeof(pshared_value_array[0]); ++i) {
ASSERT_EQ(0, pthread_rwlockattr_setpshared(&attr, pshared_value_array[i]));
int pshared;
ASSERT_EQ(0, pthread_rwlockattr_getpshared(&attr, &pshared));
ASSERT_EQ(pshared_value_array[i], pshared);
}
int kind_array[] = {PTHREAD_RWLOCK_PREFER_READER_NP,
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP};
for (size_t i = 0; i < sizeof(kind_array) / sizeof(kind_array[0]); ++i) {
ASSERT_EQ(0, pthread_rwlockattr_setkind_np(&attr, kind_array[i]));
int kind;
ASSERT_EQ(0, pthread_rwlockattr_getkind_np(&attr, &kind));
ASSERT_EQ(kind_array[i], kind);
}
ASSERT_EQ(0, pthread_rwlockattr_destroy(&attr));
}
TEST(pthread, pthread_rwlock_init_same_as_PTHREAD_RWLOCK_INITIALIZER) {
pthread_rwlock_t lock1 = PTHREAD_RWLOCK_INITIALIZER;
pthread_rwlock_t lock2;
ASSERT_EQ(0, pthread_rwlock_init(&lock2, NULL));
ASSERT_EQ(0, memcmp(&lock1, &lock2, sizeof(lock1)));
}
TEST(pthread, pthread_rwlock_smoke) {
pthread_rwlock_t l;
ASSERT_EQ(0, pthread_rwlock_init(&l, NULL));
@@ -695,7 +742,6 @@ TEST(pthread, pthread_rwlock_smoke) {
ASSERT_EQ(0, pthread_rwlock_wrlock(&l));
ASSERT_EQ(0, pthread_rwlock_unlock(&l));
#ifdef __BIONIC__
// EDEADLK in "read after write"
ASSERT_EQ(0, pthread_rwlock_wrlock(&l));
ASSERT_EQ(EDEADLK, pthread_rwlock_rdlock(&l));
@@ -705,7 +751,6 @@ TEST(pthread, pthread_rwlock_smoke) {
ASSERT_EQ(0, pthread_rwlock_wrlock(&l));
ASSERT_EQ(EDEADLK, pthread_rwlock_wrlock(&l));
ASSERT_EQ(0, pthread_rwlock_unlock(&l));
#endif
ASSERT_EQ(0, pthread_rwlock_destroy(&l));
}
@@ -807,6 +852,111 @@ TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
}
class RwlockKindTestHelper {
private:
struct ThreadArg {
RwlockKindTestHelper* helper;
std::atomic<pid_t>& tid;
ThreadArg(RwlockKindTestHelper* helper, std::atomic<pid_t>& tid)
: helper(helper), tid(tid) { }
};
public:
pthread_rwlock_t lock;
public:
RwlockKindTestHelper(int kind_type) {
InitRwlock(kind_type);
}
~RwlockKindTestHelper() {
DestroyRwlock();
}
void CreateWriterThread(pthread_t& thread, std::atomic<pid_t>& tid) {
tid = 0;
ThreadArg* arg = new ThreadArg(this, tid);
ASSERT_EQ(0, pthread_create(&thread, NULL,
reinterpret_cast<void* (*)(void*)>(WriterThreadFn), arg));
}
void CreateReaderThread(pthread_t& thread, std::atomic<pid_t>& tid) {
tid = 0;
ThreadArg* arg = new ThreadArg(this, tid);
ASSERT_EQ(0, pthread_create(&thread, NULL,
reinterpret_cast<void* (*)(void*)>(ReaderThreadFn), arg));
}
private:
void InitRwlock(int kind_type) {
pthread_rwlockattr_t attr;
ASSERT_EQ(0, pthread_rwlockattr_init(&attr));
ASSERT_EQ(0, pthread_rwlockattr_setkind_np(&attr, kind_type));
ASSERT_EQ(0, pthread_rwlock_init(&lock, &attr));
ASSERT_EQ(0, pthread_rwlockattr_destroy(&attr));
}
void DestroyRwlock() {
ASSERT_EQ(0, pthread_rwlock_destroy(&lock));
}
static void WriterThreadFn(ThreadArg* arg) {
arg->tid = gettid();
RwlockKindTestHelper* helper = arg->helper;
ASSERT_EQ(0, pthread_rwlock_wrlock(&helper->lock));
ASSERT_EQ(0, pthread_rwlock_unlock(&helper->lock));
delete arg;
}
static void ReaderThreadFn(ThreadArg* arg) {
arg->tid = gettid();
RwlockKindTestHelper* helper = arg->helper;
ASSERT_EQ(0, pthread_rwlock_rdlock(&helper->lock));
ASSERT_EQ(0, pthread_rwlock_unlock(&helper->lock));
delete arg;
}
};
TEST(pthread, pthread_rwlock_kind_PTHREAD_RWLOCK_PREFER_READER_NP) {
RwlockKindTestHelper helper(PTHREAD_RWLOCK_PREFER_READER_NP);
ASSERT_EQ(0, pthread_rwlock_rdlock(&helper.lock));
pthread_t writer_thread;
std::atomic<pid_t> writer_tid;
helper.CreateWriterThread(writer_thread, writer_tid);
WaitUntilThreadSleep(writer_tid);
pthread_t reader_thread;
std::atomic<pid_t> reader_tid;
helper.CreateReaderThread(reader_thread, reader_tid);
ASSERT_EQ(0, pthread_join(reader_thread, NULL));
ASSERT_EQ(0, pthread_rwlock_unlock(&helper.lock));
ASSERT_EQ(0, pthread_join(writer_thread, NULL));
}
TEST(pthread, pthread_rwlock_kind_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) {
RwlockKindTestHelper helper(PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
ASSERT_EQ(0, pthread_rwlock_rdlock(&helper.lock));
pthread_t writer_thread;
std::atomic<pid_t> writer_tid;
helper.CreateWriterThread(writer_thread, writer_tid);
WaitUntilThreadSleep(writer_tid);
pthread_t reader_thread;
std::atomic<pid_t> reader_tid;
helper.CreateReaderThread(reader_thread, reader_tid);
WaitUntilThreadSleep(reader_tid);
ASSERT_EQ(0, pthread_rwlock_unlock(&helper.lock));
ASSERT_EQ(0, pthread_join(writer_thread, NULL));
ASSERT_EQ(0, pthread_join(reader_thread, NULL));
}
static int g_once_fn_call_count = 0;
static void OnceFn() {
++g_once_fn_call_count;
@@ -840,14 +990,14 @@ TEST(pthread, pthread_once_1934122) {
}
static int g_atfork_prepare_calls = 0;
static void AtForkPrepare1() { g_atfork_prepare_calls = (g_atfork_prepare_calls << 4) | 1; }
static void AtForkPrepare2() { g_atfork_prepare_calls = (g_atfork_prepare_calls << 4) | 2; }
static void AtForkPrepare1() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 1; }
static void AtForkPrepare2() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 2; }
static int g_atfork_parent_calls = 0;
static void AtForkParent1() { g_atfork_parent_calls = (g_atfork_parent_calls << 4) | 1; }
static void AtForkParent2() { g_atfork_parent_calls = (g_atfork_parent_calls << 4) | 2; }
static void AtForkParent1() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 1; }
static void AtForkParent2() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 2; }
static int g_atfork_child_calls = 0;
static void AtForkChild1() { g_atfork_child_calls = (g_atfork_child_calls << 4) | 1; }
static void AtForkChild2() { g_atfork_child_calls = (g_atfork_child_calls << 4) | 2; }
static void AtForkChild1() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 1; }
static void AtForkChild2() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 2; }
TEST(pthread, pthread_atfork_smoke) {
ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
@@ -858,13 +1008,71 @@ TEST(pthread, pthread_atfork_smoke) {
// Child and parent calls are made in the order they were registered.
if (pid == 0) {
ASSERT_EQ(0x12, g_atfork_child_calls);
ASSERT_EQ(12, g_atfork_child_calls);
_exit(0);
}
ASSERT_EQ(0x12, g_atfork_parent_calls);
ASSERT_EQ(12, g_atfork_parent_calls);
// Prepare calls are made in the reverse order.
ASSERT_EQ(0x21, g_atfork_prepare_calls);
ASSERT_EQ(21, g_atfork_prepare_calls);
int status;
ASSERT_EQ(pid, waitpid(pid, &status, 0));
}
static void AtForkPrepare3() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 3; }
static void AtForkPrepare4() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 4; }
static void AtForkParent3() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 3; }
static void AtForkParent4() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 4; }
static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
TEST(pthread, pthread_atfork_with_dlclose) {
ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
void* handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "proxy_pthread_atfork"));
ASSERT_TRUE(fn != nullptr) << dlerror();
// the library registers 2 additional atfork handlers in a constructor
ASSERT_EQ(0, fn(AtForkPrepare2, AtForkParent2, AtForkChild2));
ASSERT_EQ(0, fn(AtForkPrepare3, AtForkParent3, AtForkChild3));
ASSERT_EQ(0, pthread_atfork(AtForkPrepare4, AtForkParent4, AtForkChild4));
int pid = fork();
ASSERT_NE(-1, pid) << strerror(errno);
if (pid == 0) {
ASSERT_EQ(1234, g_atfork_child_calls);
_exit(0);
}
ASSERT_EQ(1234, g_atfork_parent_calls);
ASSERT_EQ(4321, g_atfork_prepare_calls);
EXPECT_EQ(0, dlclose(handle));
g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
int status;
ASSERT_EQ(pid, waitpid(pid, &status, 0));
pid = fork();
ASSERT_NE(-1, pid) << strerror(errno);
if (pid == 0) {
ASSERT_EQ(14, g_atfork_child_calls);
_exit(0);
}
ASSERT_EQ(14, g_atfork_parent_calls);
ASSERT_EQ(41, g_atfork_prepare_calls);
ASSERT_EQ(pid, waitpid(pid, &status, 0));
}
TEST(pthread, pthread_attr_getscope) {

View File

@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <atomic>
#include "ScopedSignalHandler.h"
@@ -197,7 +198,7 @@ TEST(time, timer_create) {
ASSERT_EQ(0, timer_delete(timer_id));
}
static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) {
++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
ASSERT_EQ(SIGUSR1, signal_number);
@@ -212,6 +213,7 @@ TEST(time, timer_create_SIGEV_SIGNAL) {
timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler);
ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
@@ -228,25 +230,26 @@ TEST(time, timer_create_SIGEV_SIGNAL) {
}
struct Counter {
volatile int value;
private:
std::atomic<int> value;
timer_t timer_id;
sigevent_t se;
bool timer_valid;
Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) {
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = fn;
se.sigev_value.sival_ptr = this;
Create();
}
void Create() {
ASSERT_FALSE(timer_valid);
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
timer_valid = true;
}
public:
Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) {
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = fn;
se.sigev_value.sival_ptr = this;
Create();
}
void DeleteTimer() {
ASSERT_TRUE(timer_valid);
ASSERT_EQ(0, timer_delete(timer_id));
@@ -259,12 +262,16 @@ struct Counter {
}
}
int Value() const {
return value;
}
void SetTime(time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns);
}
bool ValueUpdated() {
volatile int current_value = value;
int current_value = value;
time_t start = time(NULL);
while (current_value == value && (time(NULL) - start) < 5) {
}
@@ -287,30 +294,29 @@ struct Counter {
TEST(time, timer_settime_0) {
Counter counter(Counter::CountAndDisarmNotifyFunction);
ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 1, 0);
usleep(500000);
// The count should just be 1 because we disarmed the timer the first time it fired.
ASSERT_EQ(1, counter.value);
ASSERT_EQ(1, counter.Value());
}
TEST(time, timer_settime_repeats) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 0, 10);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer();
// Add a sleep as other threads may be calling the callback function when the timer is deleted.
usleep(500000);
}
static int timer_create_NULL_signal_handler_invocation_count = 0;
static int timer_create_NULL_signal_handler_invocation_count;
static void timer_create_NULL_signal_handler(int signal_number) {
++timer_create_NULL_signal_handler_invocation_count;
ASSERT_EQ(SIGALRM, signal_number);
@@ -321,6 +327,7 @@ TEST(time, timer_create_NULL) {
timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
timer_create_NULL_signal_handler_invocation_count = 0;
ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler);
ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
@@ -367,22 +374,59 @@ TEST(time, timer_delete_multiple) {
TEST(time, timer_create_multiple) {
Counter counter1(Counter::CountNotifyFunction);
ASSERT_TRUE(counter1.timer_valid);
Counter counter2(Counter::CountNotifyFunction);
ASSERT_TRUE(counter2.timer_valid);
Counter counter3(Counter::CountNotifyFunction);
ASSERT_TRUE(counter3.timer_valid);
ASSERT_EQ(0, counter1.value);
ASSERT_EQ(0, counter2.value);
ASSERT_EQ(0, counter3.value);
ASSERT_EQ(0, counter1.Value());
ASSERT_EQ(0, counter2.Value());
ASSERT_EQ(0, counter3.Value());
counter2.SetTime(0, 1, 0, 0);
usleep(500000);
EXPECT_EQ(0, counter1.value);
EXPECT_EQ(1, counter2.value);
EXPECT_EQ(0, counter3.value);
EXPECT_EQ(0, counter1.Value());
EXPECT_EQ(1, counter2.Value());
EXPECT_EQ(0, counter3.Value());
}
// Test to verify that disarming a repeatable timer disables the callbacks.
TEST(time, timer_disarm_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.SetTime(0, 0, 0, 0);
// Add a sleep as the kernel may have pending events when the timer is disarmed.
usleep(500000);
int value = counter.Value();
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.Value());
}
// Test to verify that deleting a repeatable timer disables the callbacks.
TEST(time, timer_delete_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer();
// Add a sleep as other threads may be calling the callback function when the timer is deleted.
usleep(500000);
int value = counter.Value();
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.Value());
}
struct TimerDeleteData {
@@ -499,45 +543,3 @@ TEST(time, clock_nanosleep) {
timespec out;
ASSERT_EQ(EINVAL, clock_nanosleep(-1, 0, &in, &out));
}
// Test to verify that disarming a repeatable timer disables the
// callbacks.
TEST(time, timer_disarm_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.SetTime(0, 0, 1, 0);
volatile int value = counter.value;
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.value);
}
// Test to verify that deleting a repeatable timer disables the
// callbacks.
TEST(time, timer_delete_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer();
volatile int value = counter.value;
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.value);
}

1
tools/Android.bp Normal file
View File

@@ -0,0 +1 @@
subdirs = ["relocation_packer"]

View File

@@ -8,11 +8,11 @@ Dependencies
------------
* Python 2.7
* [Advanced Python Scheduler](https://apscheduler.readthedocs.org/en/latest/)
* [Flask](http://flask.pocoo.org/)
* [Google API Client Library](https://developers.google.com/api-client-library/python/start/installation)
* [jenkinsapi](https://pypi.python.org/pypi/jenkinsapi)
* [Requests](http://docs.python-requests.org/en/latest/)
* [termcolor](https://pypi.python.org/pypi/termcolor)
Setup
-----

View File

@@ -15,12 +15,16 @@
# limitations under the License.
#
import json
import logging
import os
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask, request
import requests
import termcolor
import gerrit
import tasks
from flask import Flask, request
app = Flask(__name__)
@@ -43,7 +47,7 @@ def handle_build_message():
ref = params['REF']
patch_set = ref.split('/')[-1]
print '{} #{} {}: {}'.format(name, number, status, full_url)
logging.debug('%s #%s %s: %s', name, number, status, full_url)
# bionic-lint is always broken, so we don't want to reject changes for
# those failures until we clean things up.
@@ -69,19 +73,19 @@ def handle_build_message():
patch_set))
headers = {'Content-Type': 'application/json;charset=UTF-8'}
print 'POST {}: {}'.format(url, request_data)
print requests.post(url, headers=headers, json=request_data)
logging.debug('POST %s: %s', url, request_data)
requests.post(url, headers=headers, json=request_data)
elif name == 'clean-bionic-presubmit':
request_data = {'message': 'out/ directory removed'}
url = gerrit_url('/a/changes/{}/revisions/{}/review'.format(change_id,
patch_set))
headers = {'Content-Type': 'application/json;charset=UTF-8'}
print 'POST {}: {}'.format(url, request_data)
print requests.post(url, headers=headers, json=request_data)
logging.debug('POST %s: %s', url, request_data)
requests.post(url, headers=headers, json=request_data)
elif name == 'bionic-lint':
print 'IGNORED'
logging.warning('Result for bionic-lint ignored')
else:
print '{}: {}'.format(termcolor.colored('red', 'UNKNOWN'), name)
logging.error('Unknown project: %s', name)
return ''
@@ -100,19 +104,31 @@ def drop_rejection():
bb_review = 0
if bb_review >= 0:
print 'No rejection to drop: {} {}'.format(change_id, patch_set)
logging.info('No rejection to drop: %s %s', change_id, patch_set)
return ''
print 'Dropping rejection: {} {}'.format(change_id, patch_set)
logging.info('Dropping rejection: %s %s', change_id, patch_set)
request_data = {'labels': {'Verified': 0}}
url = gerrit_url('/a/changes/{}/revisions/{}/review'.format(change_id,
patch_set))
headers = {'Content-Type': 'application/json;charset=UTF-8'}
print 'POST {}: {}'.format(url, request_data)
print requests.post(url, headers=headers, json=request_data)
logging.debug('POST %s: %s', url, request_data)
requests.post(url, headers=headers, json=request_data)
return ''
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()
fh = logging.FileHandler('bionicbb.log')
fh.setLevel(logging.INFO)
logger.addHandler(fh)
# Prevent the job from being rescheduled by the reloader.
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
scheduler = BackgroundScheduler()
scheduler.start()
scheduler.add_job(tasks.get_and_process_jobs, 'interval', minutes=5)
app.run(host='0.0.0.0', debug=True)

View File

@@ -29,6 +29,12 @@ def get_commit(change_id, revision):
call('/changes/{}/revisions/{}/commit'.format(change_id, revision)))
def get_files_for_revision(change_id, revision):
return json.loads(
call('/changes/{}/revisions/{}/files'.format(
change_id, revision))).keys()
def call(endpoint, method='GET'):
if method != 'GET':
raise NotImplementedError('Currently only HTTP GET is supported.')

71
tools/bionicbb/gmail.py Normal file
View File

@@ -0,0 +1,71 @@
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import base64
import httplib2
import config
def get_body(msg):
if 'attachmentId' in msg['payload']['body']:
raise NotImplementedError('Handling of messages contained in '
'attachments not yet implemented.')
b64_body = msg['payload']['body']['data']
return base64.urlsafe_b64decode(b64_body.encode('ASCII'))
def build_service():
from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.modify'
STORAGE = Storage('oauth.storage')
# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(config.client_secret_file,
scope=OAUTH_SCOPE)
http = httplib2.Http()
# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
credentials = run(flow, STORAGE, http=http)
http = credentials.authorize(http)
return build('gmail', 'v1', http=http)
def get_gerrit_label(labels):
for label in labels:
if label['name'] == 'gerrit':
return label['id']
return None
def get_all_messages(service, label):
msgs = []
response = service.users().messages().list(
userId='me', labelIds=label).execute()
if 'messages' in response:
msgs.extend(response['messages'])
while 'nextPageToken' in response:
page_token = response['nextPageToken']
response = service.users().messages().list(
userId='me', pageToken=page_token).execute()
msgs.extend(response['messages'])
return msgs

View File

@@ -1,365 +0,0 @@
#!/usr/bin/env python2
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import base64
import httplib
import httplib2
import jenkinsapi
import json
import re
import requests
import termcolor
import socket
import sys
import time
import apiclient.errors
import config
import gerrit
class GmailError(RuntimeError):
def __init__(self, message):
super(GmailError, self).__init__(message)
def get_gerrit_label(labels):
for label in labels:
if label['name'] == 'gerrit':
return label['id']
return None
def get_headers(msg):
headers = {}
for hdr in msg['payload']['headers']:
headers[hdr['name']] = hdr['value']
return headers
def should_skip_message(info):
if info['MessageType'] in ('newchange', 'newpatchset', 'comment'):
commit = gerrit.get_commit(info['Change-Id'], info['PatchSet'])
committer = commit['committer']['email']
return not committer.endswith('@google.com')
else:
raise ValueError('should_skip_message() is only valid for new '
'changes, patch sets, and commits.')
def build_service():
from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.modify'
STORAGE = Storage('oauth.storage')
# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(config.client_secret_file,
scope=OAUTH_SCOPE)
http = httplib2.Http()
# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
credentials = run(flow, STORAGE, http=http)
http = credentials.authorize(http)
return build('gmail', 'v1', http=http)
def get_all_messages(service, label):
msgs = []
response = service.users().messages().list(
userId='me', labelIds=label).execute()
if 'messages' in response:
msgs.extend(response['messages'])
while 'nextPageToken' in response:
page_token = response['nextPageToken']
response = service.users().messages().list(
userId='me', pageToken=page_token).execute()
msgs.extend(response['messages'])
return msgs
def get_body(msg):
if 'attachmentId' in msg['payload']['body']:
raise NotImplementedError('Handling of messages contained in '
'attachments not yet implemented.')
b64_body = msg['payload']['body']['data']
return base64.urlsafe_b64decode(b64_body.encode('ASCII'))
def get_gerrit_info(body):
info = {}
gerrit_pattern = r'^Gerrit-(\S+): (.+)$'
for match in re.finditer(gerrit_pattern, body, flags=re.MULTILINE):
info[match.group(1)] = match.group(2).strip()
return info
def clean_project(gerrit_info, dry_run):
username = config.jenkins_credentials['username']
password = config.jenkins_credentials['password']
jenkins_url = config.jenkins_url
jenkins = jenkinsapi.api.Jenkins(jenkins_url, username, password)
build = 'clean-bionic-presubmit'
if build in jenkins:
if not dry_run:
job = jenkins[build].invoke()
url = job.get_build().baseurl
else:
url = 'DRY_RUN_URL'
print '{}({}): {} {}'.format(
termcolor.colored('CLEAN', 'green'),
gerrit_info['MessageType'],
build,
url)
else:
print '{}({}): {}'.format(
termcolor.colored('CLEAN', 'red'),
gerrit_info['MessageType'],
termcolor.colored(build, 'red'))
return True
def build_project(gerrit_info, dry_run, lunch_target=None):
project_to_jenkins_map = {
'platform/bionic': 'bionic-presubmit',
'platform/build': 'bionic-presubmit',
'platform/external/jemalloc': 'bionic-presubmit',
'platform/external/libcxx': 'bionic-presubmit',
'platform/external/libcxxabi': 'bionic-presubmit',
'platform/external/compiler-rt': 'bionic-presubmit',
}
username = config.jenkins_credentials['username']
password = config.jenkins_credentials['password']
jenkins_url = config.jenkins_url
jenkins = jenkinsapi.api.Jenkins(jenkins_url, username, password)
project = gerrit_info['Project']
change_id = gerrit_info['Change-Id']
if project in project_to_jenkins_map:
build = project_to_jenkins_map[project]
else:
build = 'bionic-presubmit'
if build in jenkins:
project_path = '/'.join(project.split('/')[1:])
if not project_path:
raise RuntimeError('bogus project: {}'.format(project))
if project_path.startswith('platform/'):
print '{}({}): {} => {}'.format(
termcolor.colored('ERROR', 'red'),
'project',
project,
project_path)
return False
try:
ref = gerrit.ref_for_change(change_id)
except gerrit.GerritError as ex:
print '{}({}): {} {}'.format(
termcolor.colored('GERRIT-ERROR', 'red'),
ex.code,
change_id,
ex.url)
return False
params = {
'REF': ref,
'CHANGE_ID': change_id,
'PROJECT': project_path
}
if lunch_target is not None:
params['LUNCH_TARGET'] = lunch_target
if not dry_run:
_ = jenkins[build].invoke(build_params=params)
# https://issues.jenkins-ci.org/browse/JENKINS-27256
# url = job.get_build().baseurl
url = 'URL UNAVAILABLE'
else:
url = 'DRY_RUN_URL'
print '{}({}): {} => {} {} {}'.format(
termcolor.colored('BUILD', 'green'),
gerrit_info['MessageType'],
project,
build,
url,
change_id)
else:
print '{}({}): {} => {} {}'.format(
termcolor.colored('BUILD', 'red'),
gerrit_info['MessageType'],
project,
termcolor.colored(build, 'red'),
change_id)
return True
def handle_change(gerrit_info, _, dry_run):
if should_skip_message(gerrit_info):
return True
return build_project(gerrit_info, dry_run)
handle_newchange = handle_change
handle_newpatchset = handle_change
def drop_rejection(gerrit_info, dry_run):
request_data = {
'changeid': gerrit_info['Change-Id'],
'patchset': gerrit_info['PatchSet']
}
url = '{}/{}'.format(config.build_listener_url, 'drop-rejection')
headers = {'Content-Type': 'application/json;charset=UTF-8'}
if not dry_run:
try:
requests.post(url, headers=headers, data=json.dumps(request_data))
except requests.exceptions.ConnectionError as ex:
print '{}(drop-rejection): {}'.format(
termcolor.colored('ERROR', 'red'), ex)
return False
print '{}({}): {}'.format(
termcolor.colored('CHECK', 'green'),
gerrit_info['MessageType'],
gerrit_info['Change-Id'])
return True
def handle_comment(gerrit_info, body, dry_run):
if 'Verified+1' in body:
drop_rejection(gerrit_info, dry_run)
# TODO(danalbert): Needs to be based on the account that made the comment.
if should_skip_message(gerrit_info):
return True
command_map = {
'clean': lambda: clean_project(gerrit_info, dry_run),
'retry': lambda: build_project(gerrit_info, dry_run),
'arm': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_arm-eng'),
'aarch64': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_arm64-eng'),
'mips': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_mips-eng'),
'mips64': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_mips64-eng'),
'x86': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_x86-eng'),
'x86_64': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_x86_64-eng'),
}
def handle_unknown_command():
pass # TODO(danalbert): should complain to the commenter.
commands = [match.group(1).strip() for match in
re.finditer(r'^bionicbb:\s*(.+)$', body, flags=re.MULTILINE)]
for command in commands:
if command in command_map:
command_map[command]()
else:
handle_unknown_command()
return True
def skip_handler(gerrit_info, _, __):
print '{}({}): {}'.format(
termcolor.colored('SKIP', 'yellow'),
gerrit_info['MessageType'],
gerrit_info['Change-Id'])
return True
handle_abandon = skip_handler
handle_merged = skip_handler
handle_restore = skip_handler
handle_revert = skip_handler
def process_message(msg, dry_run):
try:
body = get_body(msg)
gerrit_info = get_gerrit_info(body)
if not gerrit_info:
print termcolor.colored('No info found: {}'.format(msg['id']),
'red')
msg_type = gerrit_info['MessageType']
handler = 'handle_{}'.format(gerrit_info['MessageType'])
if handler in globals():
return globals()[handler](gerrit_info, body, dry_run)
else:
print termcolor.colored(
'MessageType {} unhandled.'.format(msg_type), 'red')
print
return False
except NotImplementedError as ex:
print ex
return False
except gerrit.GerritError as ex:
if ex.code == 404:
print '{}(404): {}!'.format(
termcolor.colored('ERROR', 'red'), ex)
return True
else:
return False
def main(argc, argv):
dry_run = False
if argc == 2 and argv[1] == '--dry-run':
dry_run = True
elif argc > 2:
sys.exit('usage: python {} [--dry-run]'.format(argv[0]))
gmail_service = build_service()
msg_service = gmail_service.users().messages()
while True:
try:
labels = gmail_service.users().labels().list(userId='me').execute()
if not labels['labels']:
raise GmailError('Could not retrieve Gmail labels')
label_id = get_gerrit_label(labels['labels'])
if not label_id:
raise GmailError('Could not find gerrit label')
for msg in get_all_messages(gmail_service, label_id):
msg = msg_service.get(userId='me', id=msg['id']).execute()
if process_message(msg, dry_run) and not dry_run:
msg_service.trash(userId='me', id=msg['id']).execute()
time.sleep(60 * 5)
except GmailError as ex:
print '{}: {}!'.format(termcolor.colored('ERROR', 'red'), ex)
time.sleep(60 * 5)
except apiclient.errors.HttpError as ex:
print '{}: {}!'.format(termcolor.colored('ERROR', 'red'), ex)
time.sleep(60 * 5)
except httplib.BadStatusLine:
pass
except httplib2.ServerNotFoundError:
pass
except socket.error:
pass
if __name__ == '__main__':
main(len(sys.argv), sys.argv)

203
tools/bionicbb/presubmit.py Normal file
View File

@@ -0,0 +1,203 @@
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import absolute_import
import json
import logging
import os.path
import re
import requests
import jenkinsapi
import gerrit
import config
def is_untrusted_committer(change_id, patch_set):
# TODO(danalbert): Needs to be based on the account that made the comment.
commit = gerrit.get_commit(change_id, patch_set)
committer = commit['committer']['email']
return not committer.endswith('@google.com')
def contains_cleanspec(change_id, patch_set):
files = gerrit.get_files_for_revision(change_id, patch_set)
return 'CleanSpec.mk' in [os.path.basename(f) for f in files]
def contains_bionicbb(change_id, patch_set):
files = gerrit.get_files_for_revision(change_id, patch_set)
return any('tools/bionicbb' in f for f in files)
def should_skip_build(info):
if info['MessageType'] not in ('newchange', 'newpatchset', 'comment'):
raise ValueError('should_skip_build() is only valid for new '
'changes, patch sets, and commits.')
change_id = info['Change-Id']
patch_set = info['PatchSet']
checks = [
is_untrusted_committer,
contains_cleanspec,
contains_bionicbb,
]
for check in checks:
if check(change_id, patch_set):
return True
return False
def clean_project(dry_run):
username = config.jenkins_credentials['username']
password = config.jenkins_credentials['password']
jenkins_url = config.jenkins_url
jenkins = jenkinsapi.api.Jenkins(jenkins_url, username, password)
build = 'clean-bionic-presubmit'
if build in jenkins:
if not dry_run:
job = jenkins[build].invoke()
url = job.get_build().baseurl
else:
url = 'DRY_RUN_URL'
logging.info('Cleaning: %s %s', build, url)
else:
logging.error('Failed to clean: could not find project %s', build)
return True
def build_project(gerrit_info, dry_run, lunch_target=None):
project_to_jenkins_map = {
'platform/bionic': 'bionic-presubmit',
'platform/build': 'bionic-presubmit',
'platform/external/jemalloc': 'bionic-presubmit',
'platform/external/libcxx': 'bionic-presubmit',
'platform/external/libcxxabi': 'bionic-presubmit',
'platform/external/compiler-rt': 'bionic-presubmit',
}
username = config.jenkins_credentials['username']
password = config.jenkins_credentials['password']
jenkins_url = config.jenkins_url
jenkins = jenkinsapi.api.Jenkins(jenkins_url, username, password)
project = gerrit_info['Project']
change_id = gerrit_info['Change-Id']
if project in project_to_jenkins_map:
build = project_to_jenkins_map[project]
else:
build = 'bionic-presubmit'
if build in jenkins:
project_path = '/'.join(project.split('/')[1:])
if not project_path:
raise RuntimeError('bogus project: {}'.format(project))
if project_path.startswith('platform/'):
raise RuntimeError('Bad project mapping: {} => {}'.format(
project, project_path))
ref = gerrit.ref_for_change(change_id)
params = {
'REF': ref,
'CHANGE_ID': change_id,
'PROJECT': project_path
}
if lunch_target is not None:
params['LUNCH_TARGET'] = lunch_target
if not dry_run:
_ = jenkins[build].invoke(build_params=params)
# https://issues.jenkins-ci.org/browse/JENKINS-27256
# url = job.get_build().baseurl
url = 'URL UNAVAILABLE'
else:
url = 'DRY_RUN_URL'
logging.info('Building: %s => %s %s %s', project, build, url,
change_id)
else:
logging.error('Unknown build: %s => %s %s', project, build, change_id)
return True
def handle_change(gerrit_info, _, dry_run):
if should_skip_build(gerrit_info):
return True
return build_project(gerrit_info, dry_run)
def drop_rejection(gerrit_info, dry_run):
request_data = {
'changeid': gerrit_info['Change-Id'],
'patchset': gerrit_info['PatchSet']
}
url = '{}/{}'.format(config.build_listener_url, 'drop-rejection')
headers = {'Content-Type': 'application/json;charset=UTF-8'}
if not dry_run:
try:
requests.post(url, headers=headers, data=json.dumps(request_data))
except requests.exceptions.ConnectionError as ex:
logging.error('Failed to drop rejection: %s', ex)
return False
logging.info('Dropped rejection: %s', gerrit_info['Change-Id'])
return True
def handle_comment(gerrit_info, body, dry_run):
if 'Verified+1' in body:
drop_rejection(gerrit_info, dry_run)
if should_skip_build(gerrit_info):
return True
command_map = {
'clean': lambda: clean_project(dry_run),
'retry': lambda: build_project(gerrit_info, dry_run),
'arm': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_arm-eng'),
'aarch64': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_arm64-eng'),
'mips': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_mips-eng'),
'mips64': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_mips64-eng'),
'x86': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_x86-eng'),
'x86_64': lambda: build_project(gerrit_info, dry_run,
lunch_target='aosp_x86_64-eng'),
}
def handle_unknown_command():
pass # TODO(danalbert): should complain to the commenter.
commands = [match.group(1).strip() for match in
re.finditer(r'^bionicbb:\s*(.+)$', body, flags=re.MULTILINE)]
for command in commands:
if command in command_map:
command_map[command]()
else:
handle_unknown_command()
return True
def skip_handler(gerrit_info, _, __):
logging.info('Skipping %s: %s', gerrit_info['MessageType'],
gerrit_info['Change-Id'])
return True

108
tools/bionicbb/tasks.py Normal file
View File

@@ -0,0 +1,108 @@
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import httplib
import httplib2
import logging
import re
import socket
import apiclient.errors
import gerrit
import gmail
import presubmit
def get_gerrit_info(body):
info = {}
gerrit_pattern = r'^Gerrit-(\S+): (.+)$'
for match in re.finditer(gerrit_pattern, body, flags=re.MULTILINE):
info[match.group(1)] = match.group(2).strip()
return info
def process_message(msg, dry_run):
try:
body = gmail.get_body(msg)
gerrit_info = get_gerrit_info(body)
if not gerrit_info:
logging.fatal('No Gerrit info found: %s', msg.subject)
msg_type = gerrit_info['MessageType']
handlers = {
'comment': presubmit.handle_comment,
'newchange': presubmit.handle_change,
'newpatchset': presubmit.handle_change,
'abandon': presubmit.skip_handler,
'merge-failed': presubmit.skip_handler,
'merged': presubmit.skip_handler,
'restore': presubmit.skip_handler,
'revert': presubmit.skip_handler,
}
message_type = gerrit_info['MessageType']
if message_type in handlers:
return handlers[message_type](gerrit_info, body, dry_run)
else:
logging.warning('MessageType %s unhandled.', msg_type)
return False
except NotImplementedError as ex:
logging.error("%s", ex)
return False
except gerrit.GerritError as ex:
change_id = gerrit_info['Change-Id']
logging.error('Gerrit error (%d): %s %s', ex.code, change_id, ex.url)
return ex.code == 404
def get_and_process_jobs():
dry_run = False
gmail_service = gmail.build_service()
msg_service = gmail_service.users().messages()
# We run in a loop because some of the exceptions thrown here mean we just
# need to retry. For errors where we should back off (typically any gmail
# API exceptions), process_changes catches the error and returns normally.
while True:
try:
process_changes(gmail_service, msg_service, dry_run)
return
except httplib.BadStatusLine:
pass
except httplib2.ServerNotFoundError:
pass
except socket.error:
pass
def process_changes(gmail_service, msg_service, dry_run):
try:
labels = gmail_service.users().labels().list(userId='me').execute()
if not labels['labels']:
logging.error('Could not retrieve Gmail labels')
return
label_id = gmail.get_gerrit_label(labels['labels'])
if not label_id:
logging.error('Could not find gerrit label')
return
for msg in gmail.get_all_messages(gmail_service, label_id):
msg = msg_service.get(userId='me', id=msg['id']).execute()
if process_message(msg, dry_run) and not dry_run:
msg_service.trash(userId='me', id=msg['id']).execute()
except apiclient.errors.HttpError as ex:
logging.error('API Client HTTP error: %s', ex)

View File

@@ -1,64 +0,0 @@
import gmail_listener
import mock
import unittest
class TestShouldSkipMessage(unittest.TestCase):
def test_accepts_googlers(self):
for message_type in ('newchange', 'newpatchset', 'comment'):
with mock.patch('gerrit.get_commit') as mock_commit:
mock_commit.return_value = {
'committer': {'email': 'googler@google.com'}
}
self.assertFalse(gmail_listener.should_skip_message({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
def test_rejects_non_googlers(self):
for message_type in ('newchange', 'newpatchset', 'comment'):
with mock.patch('gerrit.get_commit') as mock_commit:
mock_commit.return_value = {
'committer': {'email': 'fakegoogler@google.com.fake.com'}
}
self.assertTrue(gmail_listener.should_skip_message({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
with mock.patch('gerrit.get_commit') as mock_commit:
mock_commit.return_value = {
'committer': {'email': 'johndoe@example.com'}
}
self.assertTrue(gmail_listener.should_skip_message({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
def test_calls_gerrit_get_commit(self): # pylint: disable=no-self-use
for message_type in ('newchange', 'newpatchset', 'comment'):
with mock.patch('gerrit.get_commit') as mock_commit:
gmail_listener.should_skip_message({
'MessageType': message_type,
'Change-Id': 'foo',
'PatchSet': 'bar',
})
mock_commit.assert_called_once_with('foo', 'bar')
with mock.patch('gerrit.get_commit') as mock_commit:
gmail_listener.should_skip_message({
'MessageType': message_type,
'Change-Id': 'baz',
'PatchSet': 'qux',
})
mock_commit.assert_called_once_with('baz', 'qux')
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,94 @@
import mock
import unittest
import presubmit
class TestShouldSkipBuild(unittest.TestCase):
@mock.patch('presubmit.contains_bionicbb')
@mock.patch('presubmit.contains_cleanspec')
@mock.patch('gerrit.get_commit')
def test_accepts_googlers(self, mock_commit, *other_checks):
mock_commit.return_value = {
'committer': {'email': 'googler@google.com'}
}
for other_check in other_checks:
other_check.return_value = False
for message_type in ('newchange', 'newpatchset', 'comment'):
self.assertFalse(presubmit.should_skip_build({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
@mock.patch('presubmit.contains_bionicbb')
@mock.patch('presubmit.contains_cleanspec')
@mock.patch('gerrit.get_commit')
def test_rejects_googlish_domains(self, mock_commit, *other_checks):
mock_commit.return_value = {
'committer': {'email': 'fakegoogler@google.com.fake.com'}
}
for other_check in other_checks:
other_check.return_value = False
for message_type in ('newchange', 'newpatchset', 'comment'):
self.assertTrue(presubmit.should_skip_build({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
@mock.patch('presubmit.contains_bionicbb')
@mock.patch('presubmit.contains_cleanspec')
@mock.patch('gerrit.get_commit')
def test_rejects_non_googlers(self, mock_commit, *other_checks):
mock_commit.return_value = {
'committer': {'email': 'johndoe@example.com'}
}
for other_check in other_checks:
other_check.return_value = False
for message_type in ('newchange', 'newpatchset', 'comment'):
self.assertTrue(presubmit.should_skip_build({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
@mock.patch('presubmit.contains_bionicbb')
@mock.patch('presubmit.is_untrusted_committer')
@mock.patch('gerrit.get_files_for_revision')
def test_skips_cleanspecs(self, mock_files, *other_checks):
mock_files.return_value = ['foo/CleanSpec.mk']
for other_check in other_checks:
other_check.return_value = False
for message_type in ('newchange', 'newpatchset', 'comment'):
self.assertTrue(presubmit.should_skip_build({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
@mock.patch('presubmit.contains_cleanspec')
@mock.patch('presubmit.is_untrusted_committer')
@mock.patch('gerrit.get_files_for_revision')
def test_skips_bionicbb(self, mock_files, *other_checks):
mock_files.return_value = ['tools/bionicbb/common.sh']
for other_check in other_checks:
other_check.return_value = False
for message_type in ('newchange', 'newpatchset', 'comment'):
self.assertTrue(presubmit.should_skip_build({
'MessageType': message_type,
'Change-Id': '',
'PatchSet': '',
}))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,119 @@
//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
common_cppflags = [
"-Wall",
"-Wextra",
"-Wunused",
"-Werror",
"-Wold-style-cast",
]
cc_library_host_static {
srcs: [
"src/debug.cc",
"src/delta_encoder.cc",
"src/elf_file.cc",
"src/packer.cc",
"src/sleb128.cc",
],
static_libs: ["libelf"],
include_dirs: ["external/elfutils/src/libelf"],
name: "lib_relocation_packer",
cppflags: common_cppflags,
target: {
darwin: {
disabled: true
},
},
}
cc_binary_host {
srcs: ["src/main.cc"],
static_libs: [
"lib_relocation_packer",
"libelf",
],
stl: "libc++_static",
include_dirs: [
"external/elfutils/src/libelf",
"libnativehelper/include",
],
name: "relocation_packer",
cppflags: common_cppflags,
target: {
darwin: {
disabled: true
},
},
}
cc_test_host {
srcs: [
"src/debug_unittest.cc",
"src/delta_encoder_unittest.cc",
"src/elf_file_unittest.cc",
"src/sleb128_unittest.cc",
"src/packer_unittest.cc",
],
static_libs: [
"lib_relocation_packer",
"libelf",
],
include_dirs: ["external/elfutils/src/libelf"],
cppflags: common_cppflags,
name: "relocation_packer_unit_tests",
target: {
darwin: {
disabled: true
},
},
}
// $(1) library name
// ANDROIDMK TRANSLATION ERROR: unsupported directive
// define copy-test-library
// include $(CLEAR_VARS)
// LOCAL_IS_HOST_MODULE := true
// LOCAL_MODULE := $(1)
// LOCAL_MODULE_CLASS := SHARED_LIBRARIES
// LOCAL_MODULE_PATH := $(HOST_OUT_EXECUTABLES)
// LOCAL_STRIP_MODULE := false
// LOCAL_SRC_FILES := test_data/$(1)
// include $(BUILD_PREBUILT)
//
// ANDROIDMK TRANSLATION ERROR: unsupported line
// $(eval $(call copy-test-library,elf_file_unittest_relocs_arm32.so))
// ANDROIDMK TRANSLATION ERROR: unsupported line
// $(eval $(call copy-test-library,elf_file_unittest_relocs_arm32_packed.so))
// ANDROIDMK TRANSLATION ERROR: unsupported line
// $(eval $(call copy-test-library,elf_file_unittest_relocs_arm64.so))
// ANDROIDMK TRANSLATION ERROR: unsupported line
// $(eval $(call copy-test-library,elf_file_unittest_relocs_arm64_packed.so))

View File

@@ -26,7 +26,6 @@ LOCAL_SRC_FILES := \
src/debug.cc \
src/delta_encoder.cc \
src/elf_file.cc \
src/leb128.cc \
src/packer.cc \
src/sleb128.cc \
@@ -46,6 +45,9 @@ LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := src/main.cc
LOCAL_STATIC_LIBRARIES := lib_relocation_packer libelf
# Statically linking libc++ to make it work from prebuilts
LOCAL_CXX_STL := libc++_static
LOCAL_C_INCLUDES := external/elfutils/src/libelf libnativehelper/include
LOCAL_MODULE := relocation_packer
@@ -64,7 +66,6 @@ LOCAL_SRC_FILES := \
src/debug_unittest.cc \
src/delta_encoder_unittest.cc \
src/elf_file_unittest.cc \
src/leb128_unittest.cc \
src/sleb128_unittest.cc \
src/packer_unittest.cc \

Some files were not shown because too many files have changed in this diff Show More