Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] NDK r28 beta1: issues with existing polyfills #2081

Closed
dg0yt opened this issue Oct 4, 2024 · 36 comments
Closed

[BUG] NDK r28 beta1: issues with existing polyfills #2081

dg0yt opened this issue Oct 4, 2024 · 36 comments
Assignees
Labels

Comments

@dg0yt
Copy link

dg0yt commented Oct 4, 2024

Description

This is in response to the r28 beta1 release notes.

If your project contains polyfills for any of those APIs, this change may
break your build due to the conflicting declarations. The simplest fix is to
rename your polyfill to not collide with libc. For example, rename
conflicting_api to conflicting_api_fallback and call that instead. Use
#define conflicting_api() conflicting_api_fallback() if you want to avoid
rewriting callsites.

Please open a bug if you run into issues with existing polyfills. We may be
able to add the polyfill directly to the NDK.

A test build in vcpkg CI (which uses android 21) shows a lot of breakage related to __INTRODUCED_IN() with polyfills from gnulib. There is no full picture yet because the build error cascade starts early. The first hit is mempcpy in GNU libiconv. I added a patch to rename the polyfill, but the next failures is already gettext-libintl.

In the non-gnulib group, openssl is affected, removing many ports from the build. For poppler, I assume that GNU libiconv used to be the polyfill, but I didn't verify that. "libiconv as a polyfill" might be a broader pattern.

I grepped the arm64 logs for __INTRODUCED_IN. Transformed and compressed:

gettext-libintl 'feof_unlocked' is unavailable: introduced in Android 23
gettext-libintl 'fgets_unlocked' is unavailable: introduced in Android 28
gettext-libintl 'mblen' is unavailable: introduced in Android 26
gettext-libintl 'mempcpy' is unavailable: introduced in Android 23
gettext-libintl 'nl_langinfo' is unavailable: introduced in Android 26
gsasl 'error_at_line' is unavailable: introduced in Android 23
gsasl 'error' is unavailable: introduced in Android 23
gsasl 'error_message_count' is unavailable: introduced in Android 23
gsasl 'error_print_progname' is unavailable: introduced in Android 23
gsasl 'fflush_unlocked' is unavailable: introduced in Android 28
gsasl 'fputs_unlocked' is unavailable: introduced in Android 28
gsasl '__freading' is unavailable: introduced in Android 28
gsasl '__fsetlocking' is unavailable: introduced in Android 23
gsasl 'getrandom' is unavailable: introduced in Android 28
gsasl 'iconv_close' is unavailable: introduced in Android 28
gsasl 'iconv' is unavailable: introduced in Android 28
gsasl 'iconv_open' is unavailable: introduced in Android 28
gsasl 'mblen' is unavailable: introduced in Android 26
gsasl 'nl_langinfo' is unavailable: introduced in Android 26
libconfuse 'fmemopen' is unavailable: introduced in Android 23
libidn2 'error_at_line' is unavailable: introduced in Android 23
libidn2 'error' is unavailable: introduced in Android 23
libidn2 'error_message_count' is unavailable: introduced in Android 23
libidn2 'error_print_progname' is unavailable: introduced in Android 23
libidn2 'nl_langinfo' is unavailable: introduced in Android 26
libidn2 'strchrnul' is unavailable: introduced in Android 24
liblsl 'pthread_getname_np' is unavailable: introduced in Android 26
libuv 'freeifaddrs' is unavailable: introduced in Android 24
libuv 'getifaddrs' is unavailable: introduced in Android 24
libuv 'preadv' is unavailable: introduced in Android 24
libuv 'pthread_barrier_destroy' is unavailable: introduced in Android 24
libuv 'pthread_barrier_init' is unavailable: introduced in Android 24
libuv 'pthread_barrier_wait' is unavailable: introduced in Android 24
libuv 'pwritev' is unavailable: introduced in Android 24
openssl 'getentropy' is unavailable: introduced in Android 28
poppler 'iconv_close' is unavailable: introduced in Android 28
poppler 'iconv' is unavailable: introduced in Android 28
poppler 'iconv_open' is unavailable: introduced in Android 28

Patching gnutext-libintl would probably add many more.
(All those packages build with NDK r26. NDK r27 is still blocked by its bugs.)

Affected versions

r28

Canary version

beta1

Host OS

Linux

Host OS version

vcpkg CI image

Affected ABIs

arm64-v8a

Build system

Other (specify below)

Other build system

No response

minSdkVersion

21

Device API level

No response

@dg0yt dg0yt added the bug label Oct 4, 2024
@dg0yt
Copy link
Author

dg0yt commented Oct 4, 2024

In gettext libintl, the mempcpy related errors also include:

[..]gettext-runtime/intl/dcigettext.c:1723:1: error: static declaration of 'mempcpy' follows non-static declaration

@DanAlbert
Copy link
Member

Ooh, if vcpkg's CI has issues that gives us a great place to go look at the scope of the problem. Thanks! I should remember to try that whenever I'm making ambitious changes in the future.

We'll have a look and see what can be done. My gut says that we'll re-hide the stuff that's causing problems for r28 and work on upstreaming fixes. If it were a shorter list of projects I'd say we should just fix those projects and ship r28 as-is, but if it's hit a non-trivial number of projects just in vcpkg, that's a lot of patches to upstream, and a lot of package updates that developers would need to take to get those fixes.

A complete rollback is an option, but it's sort of the last resort. For the reasons mentioned in the changelog, this is a step in the right direction that we want to take, so I'd like to see us make progress wherever we can do so safely. I'm okay with gradual progress though, so if we need to re-hide the stuff that's broadly polyfilled already we can do that to avoid breaks while we fix the various open source projects to be compatible with the change.

@DanAlbert
Copy link
Member

A test build in vcpkg CI (which uses android 21) shows a lot of breakage related to __INTRODUCED_IN() with polyfills from gnulib.

How did you do this? I was expecting to find a GitHub workflow for this, or instructions on how to build all the ports in their docs, but I'm not finding either.

@DanAlbert
Copy link
Member

I eventually figured this out: ANDROID_NDK_HOME=/path/to/ndk vcpkg ci --triplet=arm64-android, which seems to do what I need.

@DanAlbert
Copy link
Member

This is very slow though so if there's a smarter way to do this please lmk.

@enh-google
Copy link
Collaborator

i agree with danalbert's plan to quickly fix all this by just adding #if version checks...

...but for the longer-term solution, here's a quick brain dump in case i go under a bus:

gettext-libintl 'feof_unlocked' is unavailable: introduced in Android 23
gettext-libintl 'fgets_unlocked' is unavailable: introduced in Android 28
gsasl 'fflush_unlocked' is unavailable: introduced in Android 28
gsasl 'fputs_unlocked' is unavailable: introduced in Android 28
gsasl '__freading' is unavailable: introduced in Android 28
gsasl '__fsetlocking' is unavailable: introduced in Android 23

i don't really see any way to polyfill any of the unlocked stuff unless we re-expose the FILE implementation details. which maybe we should, but (a) that's a big decision and (b) we should definitely see what the wasm plan looks like in that area first. (since they might be the first actual beneficiaries of the increased opacity.)

libconfuse 'fmemopen' is unavailable: introduced in Android 23

large but doable, modulo similar FILE-internals leakage.

gettext-libintl 'mempcpy' is unavailable: introduced in Android 23

trivial one-liner. we should probably have done this as a polyfill in the first place and stopped there given that memcpy() can even be optimized to direct loads/stores, but mempcpy() is definitely going to cost you two function calls. where it should really just cost you an add.

gettext-libintl 'mblen' is unavailable: introduced in Android 26

so believe it or not, mblen() is a trivial wrapper for mbrlen() which is freely available. so surprisingly, this should be a trivial polyfill too.

gettext-libintl 'nl_langinfo' is unavailable: introduced in Android 26

this might seem like an obvious "no", but it's one where i wonder whether this is actually a great candidate for "let's just polyfill all the time". why? because Android has hard-coded answers to all the questions. and because every call i've ever seen asks a hard-coded question. so i'd expect that clang would be able to turn nl_langinfo("AM_STR") into "AM" or whatever. (of course, this probably isn't as exciting as it sounds, because in practice nothing is using this for anything that actually matters.)

gsasl 'error_at_line' is unavailable: introduced in Android 23
gsasl 'error' is unavailable: introduced in Android 23
gsasl 'error_message_count' is unavailable: introduced in Android 23
gsasl 'error_print_progname' is unavailable: introduced in Android 23

the reliance on globals here makes this a "no".

gsasl 'iconv_close' is unavailable: introduced in Android 28
gsasl 'iconv' is unavailable: introduced in Android 28
gsasl 'iconv_open' is unavailable: introduced in Android 28

even our limited set of supported encodings is probably too big for this to make sense.

libidn2 'strchrnul' is unavailable: introduced in Android 24

as long as we don't care about not having the optimized arm64 implementation (which is kind of a moot point if your alternative is "nothing", as here), there's a trivial implementation of this.

liblsl 'pthread_getname_np' is unavailable: introduced in Android 26

certainly doable, though it's a weak symbol so that native bridge can override it, so doing so would likely cause a bit of trouble there.

libuv 'freeifaddrs' is unavailable: introduced in Android 24
libuv 'getifaddrs' is unavailable: introduced in Android 24

nightmare.

libuv 'pthread_barrier_destroy' is unavailable: introduced in Android 24
libuv 'pthread_barrier_init' is unavailable: introduced in Android 24
libuv 'pthread_barrier_wait' is unavailable: introduced in Android 24

this doesn't seem to touch any internal pthread state, and it's all relatively self-contained and based on <stdatomic.h>, so i think this is something we could do ... it would leak the currently-private internal implementation of pthread_barrier_t, though i suspect we could always cheat there by giving the polyfill struct and functions slightly different names?

libuv 'preadv' is unavailable: introduced in Android 24
libuv 'pwritev' is unavailable: introduced in Android 24

conceptually easy, but really annoying as long as we're still supporting ILP32/32-bit off_t. which, realistically, is something we'll be doing for longer than we're still supporting API 24. certainly doable though. just gross.

gsasl 'getrandom' is unavailable: introduced in Android 28
openssl 'getentropy' is unavailable: introduced in Android 28

getentropy() relies on getrandom() under the covers, and although that's been around since 3.17, it was only added to bionic at the end of 2017, so only 2018+ devices will have a seccomp policy that will let you use these. TL;DR: not likely.

@dg0yt
Copy link
Author

dg0yt commented Oct 22, 2024

A test build in vcpkg CI (which uses android 21) shows a lot of breakage related to __INTRODUCED_IN() with polyfills from gnulib.

How did you do this? I was expecting to find a GitHub workflow for this, or instructions on how to build all the ports in their docs, but I'm not finding either.

It a draft PR, microsoft/vcpkg#41293. It is in the timeline here. The failure logs are available as "assets" from Azure Pipelines.

I eventually figured this out: ANDROID_NDK_HOME=/path/to/ndk vcpkg ci --triplet=arm64-android, which seems to do what I need.

Basically yes, but vcpkg CI also skips known failures with --ci-baseline=scripts/ci.baseline.txt.

This is very slow though so if there's a smarter way to do this please lmk.

Of course ... vcpkg builds debug+release, and you start with empty caches for assets and artifacts.

You can look at individual ports with vcpkg install <port> --triplet=arm64-android.

Maybe you can limit the build to the release config with --cmake-args=-DVCPKG_BUILD_TYPE=release.

@DanAlbert
Copy link
Member

I definitely looked for PRs... I must have accidentally done that in the wrong tab with a different repo. Thanks.

This is very slow though so if there's a smarter way to do this please lmk.

Of course

Ah, okay. If this is just a thing that's slow, alright.

@dg0yt
Copy link
Author

dg0yt commented Oct 22, 2024

Note that when the Microsoft team added Android, they didn't fix all the existing ports. scripts/ci.baseline.txt really must be applied. Otherwise you will meet ports which will make you cry.

@DanAlbert
Copy link
Member

Oh, I'd misunderstood you before and thought that was applied automatically. That explains why I've found mostly stuff that didn't work with r27 either.

hubot pushed a commit to aosp-mirror/platform_bionic that referenced this issue Oct 22, 2024
Bug: android/ndk#2081
Test: vcpkg install --triplet arm64-android gettext-libintl
Change-Id: Id2eff76b929543f18d64accd5b6afb64bc63e117
@DanAlbert
Copy link
Member

gettext-libintl 'feof_unlocked' is unavailable: introduced in Android 23
gettext-libintl 'fgets_unlocked' is unavailable: introduced in Android 28
gettext-libintl 'mblen' is unavailable: introduced in Android 26
gettext-libintl 'mempcpy' is unavailable: introduced in Android 23
gettext-libintl 'nl_langinfo' is unavailable: introduced in Android 26

I see (and have fixed) the mempcpy one, but the others don't repro for me (using vcpkg install --triplet=arm64-android gettext-libintl).

@DanAlbert
Copy link
Member

DanAlbert commented Oct 22, 2024

gsasl 'error_at_line' is unavailable: introduced in Android 23
gsasl 'error' is unavailable: introduced in Android 23
gsasl 'error_message_count' is unavailable: introduced in Android 23
gsasl 'error_print_progname' is unavailable: introduced in Android 23

the reliance on globals here makes this a "no".

No, this is more broken than you'd think. The gl/ subdirectory of the gsasl source tarball is a copy of the glibc sysroot (the files all say This file is part of the GNU C Library.), and it's using that and bionic. I tried with an older NDK I had installed (r25b) and it surprisingly does build. I'm guessing it builds just because the bionic headers and glibc headers are compatible enough then, but this is fundamentally a broken (mixing and matching C libraries has been a source of bugs for Android apps in the past; it's the reason that the NDK's libc++ wasn't reliable for the first few years of its existence) port and honestly a bit alarming. It's not just glibc headers in there, there are implementations, and quite a lot of them!

I'm honestly not sure if I'm doing anyone any favors by "fixing" the NDK to make this port compatible again. I'm not convinced that the previous port which built would actually work.

@enh-google
Copy link
Collaborator

nothing says "Simple Authentication and Security Layer" like "we copied and merged multiple libcs" :-)

@dg0yt
Copy link
Author

dg0yt commented Oct 23, 2024

The gl/ subdirectory of the gsasl source tarball is a copy of the glibc sysroot (the files all say This file is part of the GNU C Library.),

nothing says "Simple Authentication and Security Layer" like "we copied and merged multiple libcs" :-)

I think this interpretation needs some adjustment, even if I didn't check gsasl in particular.
gl probably is not a naive copy of glibc but actually Gnulib, a software collection meant to help with portability issues. And it is the package mentioned in my initial post.

Gnulib is not a standalone lib, but vendored into the configuration and build of software packages. It is organized into "modules", some meant to add, rectify or enhance implementations of ISO C or POSIX functtions.
https://www.gnu.org/software/gnulib/manual/gnulib.html#Support-for-ISO-C-or-POSIX-functions_002e
Polyfill. Subject to check results during configure, gnulib modules will be added to a build. They may provide implementation under the same name, or replacements with a different identifier but mapped using macros.

I don't consider myself an expert for autotools or gnulib. I honestly also don't know what is the best way to deal with this, and I don't ask for a particular solution. Gnulib providing an implementation under the same name may be hard to align with the Android ecosystem's variation over API level and actual runtime.

The vcpkg problem is that the modules are littered into all those packages based on autotools. They all need to be patched individually until Gnulib improvements are integrated by each single package.

@DanAlbert
Copy link
Member

gl probably is not a naive copy of glibc but actually Gnulib, a software collection meant to help with portability issues. And it is the package mentioned in my initial post.

Gnulib is not a standalone lib, but vendored into the configuration and build of software packages. It is organized into "modules", some meant to add, rectify or enhance implementations of ISO C or POSIX functtions.
https://www.gnu.org/software/gnulib/manual/gnulib.html#Support-for-ISO-C-or-POSIX-functions_002e
Polyfill. Subject to check results during configure, gnulib modules will be added to a build. They may provide implementation under the same name, or replacements with a different identifier but mapped using macros.

Ah, that comment in the headers is pretty misleading if so.

Odd. https://www.gnu.org/software/gnulib/manual/gnulib.html#Support-for-ISO-C-or-POSIX-functions_002e says that gnulib's polyfills are supposed to be prefixed to avoid exactly this kind of name conflict.

The vcpkg problem is that the modules are littered into all those packages based on autotools. They all need to be patched individually until Gnulib improvements are integrated by each single package.

Yep, we do understand that. That's why we're partially reverting bionic's header changes for now. I am going to look through the existing ports while I do that though, because some of them may be problems with the ports. 7zip wasn't in your list, but it's the first one I looked at and it's just wrong, so soon 7zip should build for android: microsoft/vcpkg#41721. For the rest where it's not a port problem, I'll revert the bionic header change that's causing the problem. Like I said that's already been done for mempcpy.

@DanAlbert
Copy link
Member

Odd. https://www.gnu.org/software/gnulib/manual/gnulib.html#Support-for-ISO-C-or-POSIX-functions_002e says that gnulib's polyfills are supposed to be prefixed to avoid exactly this kind of name conflict.

Ah, because I'd come to this bug prepared to find issues with polyfills, but that's not what this is. This looks to be an autoconf detection issue. It's trying to use error_message_count because it's declared, even though it's declared unavailable. I don't know why it's considering that as available.

@DanAlbert
Copy link
Member

I happened to be watching the log re-populate when rebuilding libuv after hiding the pthread_barrier_* stuff, and it doesn't actually protect against calls if it's not available:

/usr/local/google/home/danalbert/src/vcpkg/buildtrees/libuv/src/v1.49.2-5cffa54d5b.clean/src/thread-common.c:154:18: warning: implicit declaration of function 'pthread_barrier_init' [-Wimplicit-function-declaration]
  154 |   return UV__ERR(pthread_barrier_init(barrier, NULL, count));
      |                  ^
/usr/local/google/home/danalbert/src/vcpkg/buildtrees/libuv/src/v1.49.2-5cffa54d5b.clean/src/thread-common.c:161:8: warning: implicit declaration of function 'pthread_barrier_wait' [-Wimplicit-function-declaration]
  161 |   rc = pthread_barrier_wait(barrier);
      |        ^
/usr/local/google/home/danalbert/src/vcpkg/buildtrees/libuv/src/v1.49.2-5cffa54d5b.clean/src/thread-common.c:171:7: warning: implicit declaration of function 'pthread_barrier_destroy' [-Wimplicit-function-declaration]
  171 |   if (pthread_barrier_destroy(barrier))
      |       ^
3 warnings generated.

It links though, so I guess those calls are probably culled by dead code elimination?

@DanAlbert
Copy link
Member

Once this stack of commits is merged, the list you gave above all builds, aside from poppler, which is broken for other reasons. I think upstream forgot an #include for something in the stdlib? Thanks for your help with this.

It's going to be a bit before I can actually pull this update into the NDK. The OS repo is not in a state where I can pull a new sysroot, so I have to wait for that before I can update the NDK. We won't ship r28 without that, it's just going to be a while before we can get even a canary build to recheck vcpkg :(

@DanAlbert DanAlbert moved this from Unconfirmed to Triaged in NDK r28 Oct 23, 2024
@DanAlbert DanAlbert moved this from Triaged to Needs prebuilt update in NDK r28 Oct 23, 2024
@enh-google
Copy link
Collaborator

I happened to be watching the log re-populate when rebuilding libuv after hiding the pthread_barrier_* stuff, and it doesn't actually protect against calls if it's not available:

/usr/local/google/home/danalbert/src/vcpkg/buildtrees/libuv/src/v1.49.2-5cffa54d5b.clean/src/thread-common.c:154:18: warning: implicit declaration of function 'pthread_barrier_init' [-Wimplicit-function-declaration]
  154 |   return UV__ERR(pthread_barrier_init(barrier, NULL, count));
      |                  ^
/usr/local/google/home/danalbert/src/vcpkg/buildtrees/libuv/src/v1.49.2-5cffa54d5b.clean/src/thread-common.c:161:8: warning: implicit declaration of function 'pthread_barrier_wait' [-Wimplicit-function-declaration]
  161 |   rc = pthread_barrier_wait(barrier);
      |        ^
/usr/local/google/home/danalbert/src/vcpkg/buildtrees/libuv/src/v1.49.2-5cffa54d5b.clean/src/thread-common.c:171:7: warning: implicit declaration of function 'pthread_barrier_destroy' [-Wimplicit-function-declaration]
  171 |   if (pthread_barrier_destroy(barrier))
      |       ^
3 warnings generated.

It links though, so I guess those calls are probably culled by dead code elimination?

ah, funnily enough i saw your code change before i saw this, and my review comment there might be the answer --- i think they're actually checking for the corresponding constant #define instead. my guess is that if you undo the change you did make, and #if around the #define instead, you'll get the result you're looking for.

(this was phrased more as a question on the code review because i wasn't sure whether i just didn't understand the cmake bumf...)

@DanAlbert
Copy link
Member

i think they're actually checking for the corresponding constant #define instead.

I'd have to hide the #define and the function decls. If I only hide the #define then it'll use its polyfill path and then fail for "redefined with different attributes" error or however it called it:

#if defined(_AIX) || \
    defined(__OpenBSD__) || \
    !defined(PTHREAD_BARRIER_SERIAL_THREAD)
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {

If I hide only the function decls, anyone that needs to call these via dlsym can still use PTHREAD_BARRIER_SERIAL_THREAD.

hubot pushed a commit to aosp-mirror/platform_bionic that referenced this issue Oct 24, 2024
Bug: android/ndk#2081
Test: vcpkg install --triple=arm64-android gsasl
Change-Id: If47f2676c312cd5e6a699b2fa0a2ce86a6f8724b
@DanAlbert
Copy link
Member

I'm considering another approach to this.

What we're trying to accomplish by unguarding all these bionic APIs is to make is possible for stuff in libc to be runtime guarded with __builtin_available() and called without having to meddle with dlsym(), as described on https://developer.android.com/ndk/guides/using-newer-apis. Unguarding these APIs fixes the first caveat listed here: that feature doesn't currently work for libc because of these guards.

Exposing these decls when not using that mode (and not using it is the default behavior for the reasons explained on that page) is less important, and I'm not really sure how useful that would be. The main thing you get with this there is better error messages and marginally easier dlsym() (because you can decltype() the API when casting the dlsym() result). Anyone that's actually writing code for Android should be using weak API references (I'm sure there are exceptions, but generally that's true), so the use cases where you're not doing that are where you're not (intentionally) writing code for Android. In those cases you're probably the maintainer of a cross platform library that isn't considering how your library will behave across different Android versions (perhaps because you don't even know your code will run on Android), and for that case the best thing the NDK can do for you is probably to pretend that the answer to "is foo() available?" really is something that can be reliably answered at build time, even if that means means answering "no" when the truth is "maybe, ask again at runtime".

The third thing we'd like to accomplish by unhinding this stuff adding more polyfills directly to bionic. It's silly for everyone to have to make their own polyfill for something that's trivially inlined into the libc headers.

https://android-review.googlesource.com/c/platform/bionic/+/3319120 (very much a draft) I think accomplishes both goals: it exposes these APIs to the people that probably do want accurate answers, while maintaining source compatibility as the default behavior. It doesn't really solve the third thing, but it would allow us to expose the polyfills in that mode and not in the default mode so we can make some progress.

@enh-google
Copy link
Collaborator

If I hide only the function decls, anyone that needs to call these via dlsym can still use PTHREAD_BARRIER_SERIAL_THREAD.

(i'm pretty sure the last time we had to do something like that, it was for this same library!)

It doesn't really solve the third thing, but it would allow us to expose the polyfills in that mode and not in the default mode so we can make some progress.

yeah, and i'm definitely sad about that, but at the same time, this seems like the "not a regression from an ndk perspective" way to remove versioner (which is a nice tech debt removal for us). probably best not to combine too many unrelated concerns here. "sgtm".

hubot pushed a commit to aosp-mirror/platform_bionic that referenced this issue Oct 28, 2024
Putting this behavior behind a macro so we can easily change it across
bionic if needed.

Bug: android/ndk#2081
Test: None
Change-Id: Ia08b54a61b5b06f6fa4646f036ef1e788d7c3ece
hubot pushed a commit to aosp-mirror/platform_bionic that referenced this issue Oct 30, 2024
This was generated mechanically by reverting my recent re-hide commits
(except for mempcpy, but versioner cleaned that up for me anyway),
reverting the commits which removed versioner, then:

```
m out/soong/ndk_headers.timestamp
cp -r out/soong/ndk/sysroot/usr/include/* bionic/libc/include
git -C bionic clean -df
```

Effectively, this has restored the `versioner` processed headers, but
I'm checking the results of that in so we don't have to keep
`versioner` around.

For the NDK, this restores r27 behavior by default. Anyone that's
opted into weak APIs will get the new behavior. I think this is our
best option. Anyone writing code with Android in mind should be using
weak APIs, but any code being lightly ported (and thus using the
default configuration) should not be, and it's those ports where we're
having trouble with collisions.

Bug: android/ndk#2081
Test: None
Change-Id: I370079d27566b0c1543fb5890c958c8d09b05006
@DanAlbert
Copy link
Member

This should be fixed as of https://ci.android.com/builds/branches/aosp-master-ndk/grid?head=12591196&tail=12591196&legacy=1. @dg0yt, mind verifying that? I'll try one of the packages above in a bit but it'd be nice to know if your vcpkg PR would be unblocked :)

@DanAlbert
Copy link
Member

Confirmed that gsasl builds fine with that. It was all one automated fix so the rest should be good too. lmk if they aren't.

@DanAlbert DanAlbert moved this from Needs prebuilt update to Needs cherry-pick in NDK r28 Nov 1, 2024
@DanAlbert DanAlbert self-assigned this Nov 1, 2024
dg0yt added a commit to dg0yt/vcpkg that referenced this issue Nov 2, 2024
@dg0yt
Copy link
Author

dg0yt commented Nov 2, 2024

This should be fixed as of https://ci.android.com/builds/branches/aosp-master-ndk/grid?head=12591196&tail=12591196&legacy=1. @dg0yt, mind verifying that?

There is no easily accessible URL to download the actual artifact into vcpkg CI.

@DanAlbert
Copy link
Member

DanAlbert commented Nov 4, 2024

https://androidbuildinternal.googleapis.com/android/internal/build/v3/builds/12591196/linux/attempts/latest/artifacts/android-ndk-12591196-linux-x86_64.zip/url should work. It works on my non-corp logged in browser, so I think the "internal" in the URL is just a historical oddity.

@dg0yt
Copy link
Author

dg0yt commented Nov 8, 2024

Okay, the CI finished much more successfully now. The "polyfills" topic is mostly resolved.

Looking at the remaining failures, some patterns involve SDK headers. Initially I thought it is mostly about being strict with old C standards, but there are also issues with C++11 and C++17. For example:

FAILED: gio/giomm/libgiomm-2.68.a.p/contenttype.cc.o 
/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=x86_64-none-linux-android21 -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -frtti -fexceptions -fPIC -fno-limit-debug-info --sysroot=/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot -Igio/giomm/libgiomm-2.68.a.p -Igio -I../src/glibmm-2-8b3b1eb988.clean/gio -I../src/glibmm-2-8b3b1eb988.clean/untracked/gio -Iglib -I../src/glibmm-2-8b3b1eb988.clean/glib -I../src/glibmm-2-8b3b1eb988.clean/untracked/glib -I/mnt/vcpkg-ci/installed/x64-android/debug/lib/pkgconfig/../../../include -I/mnt/vcpkg-ci/installed/x64-android/debug/lib/pkgconfig/../../../include/glib-2.0 -I/mnt/vcpkg-ci/installed/x64-android/debug/lib/pkgconfig/../../lib/glib-2.0/include -I/mnt/vcpkg-ci/installed/x64-android/debug/lib/pkgconfig/../../../include/gio-unix-2.0 -I/mnt/vcpkg-ci/installed/x64-android/include -fdiagnostics-color=always -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++17 -g --target=x86_64-none-linux-android21 -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -frtti -fexceptions -fPIC -fno-limit-debug-info --sysroot=/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -pthread -DGIOMM_BUILD=1 -MD -MQ gio/giomm/libgiomm-2.68.a.p/contenttype.cc.o -MF gio/giomm/libgiomm-2.68.a.p/contenttype.cc.o.d -o gio/giomm/libgiomm-2.68.a.p/contenttype.cc.o -c ../src/glibmm-2-8b3b1eb988.clean/gio/giomm/contenttype.cc
In file included from ../src/glibmm-2-8b3b1eb988.clean/gio/giomm/contenttype.cc:17:
In file included from ../src/glibmm-2-8b3b1eb988.clean/gio/giomm/contenttype.h:19:
In file included from ../src/glibmm-2-8b3b1eb988.clean/glib/glibmm/ustring.h:29:
In file included from /vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/sstream:320:
In file included from /vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/istream:169:
In file included from /vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/bitset:147:
/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/string:746:43: error: implicit instantiation of undefined template 'std::char_traits<unsigned char>'
  746 |   static_assert((is_same<_CharT, typename traits_type::char_type>::value),
      |                                           ^
../src/glibmm-2-8b3b1eb988.clean/gio/giomm/contenttype.cc:93:57: note: in instantiation of template class 'std::basic_string<unsigned char>' requested here
   93 |   gchar* cresult = g_content_type_guess(c_filename, data.c_str(), data.size(), &c_result_uncertain);
      |                                                         ^
/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/__fwd/string.h:23:29: note: template is declared here
   23 | struct _LIBCPP_TEMPLATE_VIS char_traits;
      |                             ^
1 error generated.

This is just a short collection of notes.

argtable2: EOVERFLOW in enum
argtable3: C89 vs. /usr/include/ctype.h:error: unknown type name 'inline'
cpp-netlib: C++11 vs. usr/include/c++/v1/string:746:43: error: implicit instantiation of undefined template 'std::char_traits<unsigned int>'
cpprestsdk: C++11 vs. usr/include/c++/v1/string:746:43: error: implicit instantiation of undefined template 'std::char_traits<unsigned int>'
cspice: ANSI C vs. /usr/include/ctype.h:error: unknown type name 'inline'
efsw: GNU++11 vs. usr/include/c++/v1/string:746:43: error: implicit instantiation of undefined template 'std::char_traits<unsigned int>'
glibmm C++17 vs. usr/include/c++/v1/string:746:43: error: implicit instantiation of undefined template 'std::char_traits<unsigned int>'
...
libpq (PostgreSQL): pthread_barrier_t (API 21) polyfill conflict
...
tinyspline: C89 vs. /usr/include/ctype.h:error: unknown type name 'inline'
...

Logs can be downloaded from the assets page, https://dev.azure.com/vcpkg/public/_build/results?buildId=109033&view=artifacts&type=publishedArtifacts (Hover line, than use the menu on the right side).

@dg0yt
Copy link
Author

dg0yt commented Nov 8, 2024

vcpkg (API level 21) with "r29-canary" from #2081 (comment):

Success Fail Cascade
arm-neon-android 1592 21 26
arm64-android 1639 22 27
x64-android 1666 22 27

Notes for all failing ports, grouped:

unknown type name 'inline'

/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/ctype.h:98:8: error: unknown type name 'inline'
   98 | static inline int __bionic_ctype_in_range(unsigned __lo, int __ch, unsigned __hi) {
      |        ^
1 error generated.

argtable3: C89
cspice: ANSI C
launch-darkly-server: C89
libuv: GNU90
sdl2-mixer-ext: C89
tinyspline: C89

undefined template 'std::char_traits<unsigned int>'

In file included from /vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/ios:222:
In file included from /vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/__locale:24:
/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/string:746:43: error: implicit instantiation of undefined template 'std::char_traits<unsigned char>'
  746 |   static_assert((is_same<_CharT, typename traits_type::char_type>::value),
      |                                           ^
/mnt/vcpkg-ci/b/telnetpp/src/v3.1.0-ee3a04cde3.clean/include/telnetpp/core.hpp:48:21: note: in instantiation of template class 'std::basic_string<unsigned char>' requested here
   48 | inline byte_storage operator""_tb(char const *text, size_t length)
      |                     ^
/vcpkg/android-ndk-r29-canary/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/__fwd/string.h:23:29: note: template is declared here
   23 | struct _LIBCPP_TEMPLATE_VIS char_traits;
      |                             ^

cpp-netlib: C++11
cpprestsdk: C++11
efsw: GNU++11
glibmm: C++17
mapnik: C++14
mygui: GNU++17
nu-boo-zxing-cpp: C++17
paho-mqttpp3: C++11
poco: GNU++17
poppler: C++17
telnetpp: undefined C++ standard

Redefinition of pthread_barrier_t

hidapi
libpq

Other

argtable2: EOVERFLOW in enum
libconfuse: redefinition of 'reallocarray'

[openvino: unrelated vcpkg regression]

@enh-google
Copy link
Collaborator

https://android-review.googlesource.com/c/platform/bionic/+/3343442 fixes the stray inline.

i think undefined template 'std::char_traits<unsigned int>' is WAI, at least in the sense of "the C++ standard does not guarantee an instantiation for that type"? C++ has a distinct char32_t type [as opposed to just a typedef] since C++11.

as for pthread_barrier_t --- that's not a regression, right? we've always had an unconditional definition of that type for anything that pulls in <pthread.h>...

likewise the use of EOVERFLOW in an enum --- i don't think there's ever been a version of bionic where that wouldn't expand to 75 and thus a syntax error. that's also true for musl and glibc and iOS/macOS, so i think this code is just broken everywhere? or perhaps it just relies on <errno.h> not being transitively included at that point, which isn't something we can change without breaking lots of code, even if we wanted to.

@DanAlbert
Copy link
Member

Yeah, the libc++ thing is the same as I explained here: #2094 (comment).

@dg0yt
Copy link
Author

dg0yt commented Nov 8, 2024

FTR all listed port build successfully with r27 in vcpkg. (I don't claim they run correctly.)

hubot pushed a commit to aosp-mirror/platform_bionic that referenced this issue Nov 8, 2024
Bug: android/ndk#2081
Change-Id: I8d63fb003510837c28dad0da9b0c6703a3487f7b
@dg0yt
Copy link
Author

dg0yt commented Nov 8, 2024

In r27, the definition of pthread_barrier_t is behind #if __ANDROID_API__ >= 24. In the new NDK, it is no longer gated.
Renaming the polyfill in libpq was an easy patch. And moving vcpkg CI to 24 is on my list. (I'm only a contributor...)

@DanAlbert
Copy link
Member

The inline thing is fixed (the CL is up, it hasn't propagated through the the NDK yet).

The libc++ thing is out of our hands. That's a 3p library that we don't have control over, and the change was correct to match the C++ spec afaict. The most we can do there would be to file an LLVM bug but I'm not at all optimistic that it would be "fixed", since it's not actually wrong.

In r27, the definition of pthread_barrier_t is behind #if ANDROID_API >= 24. In the new NDK, it is no longer gated.

That's an easy fix, but it's also kind of a weird one? If the problem in hidapi is also an easy patch, we always prefer to keep types visible even if the APIs are not, otherwise you can't reasonably use the API's via dlsym() after runtime guards. OTOH anyone that wants to do that is probably using weak API references anyway, so we can rehide it if needed.

libconfuse: redefinition of 'reallocarray'

Ah, I think I need to fix this one separately from the others since it was a different problem than most of them since it was an explicit polyfill rather than just a decl. I'll do that in a moment.

And moving vcpkg CI to 24 is on my list. (I'm only a contributor...)

In case it hasn't already been said, we do appreciate the work you do here :) This report in particular is some of the biggest help we've ever gotten in terms of pre-release feedback for making sure we don't ship a release that's hard for people to adopt. I'm pretty interested in making things easier for vcpkg, so keep the reports coming (and apologies in advance that for LLVM bugs we typically can't do anything until upstream fixes them, we're really just a distributor for that).

@dg0yt
Copy link
Author

dg0yt commented Nov 8, 2024

The EOVERFLOW thing is local to a .c file. Should be an easy fix, too. (#undef.) I assume it is from changes in header inclusion structure.

@dg0yt
Copy link
Author

dg0yt commented Nov 8, 2024

Well, basically it looks good to me now.

@DanAlbert
Copy link
Member

https://r.android.com/3341580 rehides reallocarray.

Well, basically it looks good to me now.

Excellent, the enum one sounded a bit messy to fix. Thanks!

hubot pushed a commit to aosp-mirror/platform_bionic that referenced this issue Nov 11, 2024
This conflicts with an existing polyfill in libconfuse.

Bug: android/ndk#2081
Test: None
Change-Id: I4d0a1530ac0cd0e4e75f52106ca3f284e630c847
@DanAlbert DanAlbert moved this from Needs cherry-pick to Merged in NDK r28 Nov 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Merged
Development

No branches or pull requests

3 participants