Skip to content

[android] fix the android build #999

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

Merged
merged 1 commit into from
Oct 29, 2024
Merged

Conversation

hyp
Copy link
Contributor

@hyp hyp commented Oct 23, 2024

Platform.swift regressed after 71eefee

@hyp hyp requested review from compnerd and jmschonfeld October 23, 2024 20:07
@hyp
Copy link
Contributor Author

hyp commented Oct 23, 2024

@swift-ci please test

@hyp
Copy link
Contributor Author

hyp commented Oct 23, 2024

build failures without the fix:

:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:168:35: error: cannot find 'group' in scope
166 |     
167 |     static func gid(forName name: String) -> uid_t? {
168 |         withUserGroupBuffer(name, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrnam_r) {
    |                                   `- error: cannot find 'group' in scope
169 |             $0.gr_gid
170 |         }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:168:98: error: cannot find 'getgrnam_r' in scope
166 |     
167 |     static func gid(forName name: String) -> uid_t? {
168 |         withUserGroupBuffer(name, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrnam_r) {
    |                                                                                                  `- error: cannot find 'getgrnam_r' in scope
169 |             $0.gr_gid
170 |         }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:168:98: error: converting non-escaping value to '(String, UnsafeMutablePointer<Output>, UnsafeMutablePointer<CChar>, Int, UnsafeMutablePointer<UnsafeMutablePointer<Output>?>) -> Int32' (aka '(String, UnsafeMutablePointer<Output>, UnsafeMutablePointer<Int8>, Int, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Output>>>) -> Int32') may allow it to escape
166 |     
167 |     static func gid(forName name: String) -> uid_t? {
168 |         withUserGroupBuffer(name, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrnam_r) {
    |                                                                                                  `- error: converting non-escaping value to '(String, UnsafeMutablePointer<Output>, UnsafeMutablePointer<CChar>, Int, UnsafeMutablePointer<UnsafeMutablePointer<Output>?>) -> Int32' (aka '(String, UnsafeMutablePointer<Output>, UnsafeMutablePointer<Int8>, Int, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Output>>>) -> Int32') may allow it to escape
169 |             $0.gr_gid
170 |         }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:175:32: error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
173 |     static func name(forUID uid: uid_t) -> String? {
174 |         withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) {
175 |             String(cString: $0.pw_name)
    |                                |- error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
    |                                |- note: coalesce using '??' to provide a default when the optional value contains 'nil'
    |                                `- note: force-unwrap using '!' to abort execution if the optional value contains 'nil'
176 |         }
177 |     }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:181:32: error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
179 |     static func fullName(forUID uid: uid_t) -> String? {
180 |         withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) {
181 |             String(cString: $0.pw_gecos)
    |                                |- error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
    |                                |- note: coalesce using '??' to provide a default when the optional value contains 'nil'
    |                                `- note: force-unwrap using '!' to abort execution if the optional value contains 'nil'
182 |         }
183 |     }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:186:34: error: cannot find 'group' in scope
184 |     
185 |     static func name(forGID gid: gid_t) -> String? {
186 |         withUserGroupBuffer(gid, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrgid_r) {
    |                                  `- error: cannot find 'group' in scope
187 |             String(cString: $0.gr_name)
188 |         }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:186:97: error: cannot find 'getgrgid_r' in scope
184 |     
185 |     static func name(forGID gid: gid_t) -> String? {
186 |         withUserGroupBuffer(gid, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrgid_r) {
    |                                                                                                 `- error: cannot find 'getgrgid_r' in scope
187 |             String(cString: $0.gr_name)
188 |         }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:186:97: error: converting non-escaping value to '(gid_t, UnsafeMutablePointer<Output>, UnsafeMutablePointer<CChar>, Int, UnsafeMutablePointer<UnsafeMutablePointer<Output>?>) -> Int32' (aka '(UInt32, UnsafeMutablePointer<Output>, UnsafeMutablePointer<Int8>, Int, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Output>>>) -> Int32') may allow it to escape
184 |     
185 |     static func name(forGID gid: gid_t) -> String? {
186 |         withUserGroupBuffer(gid, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrgid_r) {
    |                                                                                                 `- error: converting non-escaping value to '(gid_t, UnsafeMutablePointer<Output>, UnsafeMutablePointer<CChar>, Int, UnsafeMutablePointer<UnsafeMutablePointer<Output>?>) -> Int32' (aka '(UInt32, UnsafeMutablePointer<Output>, UnsafeMutablePointer<Int8>, Int, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Output>>>) -> Int32') may allow it to escape
187 |             String(cString: $0.gr_name)
188 |         }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:193:32: error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
191 |     static func homeDirectory(forUserName userName: String) -> String? {
192 |         withUserGroupBuffer(userName, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwnam_r) {
193 |             String(cString: $0.pw_dir)
    |                                |- error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
    |                                |- note: coalesce using '??' to provide a default when the optional value contains 'nil'
    |                                `- note: force-unwrap using '!' to abort execution if the optional value contains 'nil'
194 |         }
195 |     }

D:/r/_work/swift-build/swift-build/SourceCache/swift-foundation/Sources/FoundationEssentials/Platform.swift:199:32: error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')
197 |     static func homeDirectory(forUID uid: uid_t) -> String? {
198 |         withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) {
199 |             String(cString: $0.pw_dir)
    |                                |- error: value of optional type 'UnsafeMutablePointer<CChar>?' (aka 'Optional<UnsafeMutablePointer<Int8>>') must be unwrapped to a value of type 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>')

    |                                |- note: coalesce using '??' to provide a default when the optional value contains 'nil'

    |                                `- note: force-unwrap using '!' to abort execution if the optional value contains 'nil'

200 |         }

201 |     }

[571/577] Building CXX object _deps/swiftfoundationicu-build/icuSources/CMakeFiles/_FoundationICU.dir/common/icu_packaged_data.cpp.o
ninja: build stopped: subcommand failed.

@hyp
Copy link
Contributor Author

hyp commented Oct 23, 2024

we need to import full Android module to import sub-module grp to access group APIs, and also the const char * properties of users/groups are nullable on Android.

@@ -172,31 +171,46 @@ extension Platform {

static func name(forUID uid: uid_t) -> String? {
withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) {
String(cString: $0.pw_name)
// Android's pw_name `char *`` is nullable, so always coerce to a nullable pointer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm: is this property nullable on Android because it has different semantics than the Darwin/Glibc definition (i.e. it is valid to be null whereas it's not valid on Darwin/Linux)? Or is this a potential issue with the Android module/swift overlay that we could address there to make it non-optional like Darwin/Linux?

If the difference is intentional then this seems like the best way to account for it, just want to make sure we shouldn't try to make this change to the Android module before we add complexity to this code that we don't have much unit testing for

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! I looked over the sources for Android's libc and it looks like the situation is mixed:

  • pw_name doesn't seem to be nullable , so I think it should be _Nonnull instead.
  • pw_gecos is typically null, so it's correct for it to be _Nullable.
  • gr_name doesn't seem to be nullable, so I think it should be _Nonnull instead.
  • pw_dir doesn't seem to be nullable, so I think it should be _Nonnul linstead.

I'll update the patch to only account for nullability in pw_gecos in that case, and will try to re-annotate the other fields using API notes instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also pw_gecos isn't available on 32 bit android, as it's a macro in headers, so I'll handle that case too.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the trouble with fields like this is "when are making your claim?". even if one particular function guarantees the field won't be null, other code can pass you an instance of this struct with a null field. there's no prohibition against user code creating/mutating instances of any libc type (nor could there be, in C).

tbh, i don't think there's any particularly satisfactory answer to this question. afaik no other libc has tried adding annotations, so we can't even compare notes to be "at least consistently wrong"...

i'm listening, but this feels "WAI" to me, given that insufficient expressivity of the existing annotations.

(and if you think this is bad, check out the places where we've shrugged and said __BIONIC_COMPLICATED_NULLNESS where the answer is "it depends on the values of other arguments" :-( )

@hyp hyp force-pushed the eng/fix-android-platform branch from d504ec7 to dfc3d9d Compare October 24, 2024 20:13
@hyp
Copy link
Contributor Author

hyp commented Oct 24, 2024

@jmschonfeld unfortunately, it looks like Clang's API Notes do not support changing the nullability of a field in a C struct :( , and I would be unable to use API notes to fix the nullability for fields I mentioned above. I'm going to file an issue on the NDK so that they can fix it in source, but in the mean time, do you think it would be ok to land this instead, with fixed up comments that mention that we're waiting on the NDK fix?

}
}

static func fullName(forUID uid: uid_t) -> String? {
withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) {
String(cString: $0.pw_gecos)
#if os(Android) && (arch(i386) || arch(arm))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small comment: should we use _pointerBitWidth(_32) here just so we don't have to maintain a list of 32bit architectures if this ever changes?

@jmschonfeld
Copy link
Contributor

@jmschonfeld unfortunately, it looks like Clang's API Notes do not support changing the nullability of a field in a C struct :( , and I would be unable to use API notes to fix the nullability for fields I mentioned above. I'm going to file an issue on the NDK so that they can fix it in source, but in the mean time, do you think it would be ok to land this instead, with fixed up comments that mention that we're waiting on the NDK fix?

Unfortunate but yeah this is probably the best resolution to keep Android building in the meantime. Left one small comment but otherwise this is looking good to me based on that.

Platform.swift regressed after 71eefee
@hyp hyp force-pushed the eng/fix-android-platform branch from dfc3d9d to dacaf23 Compare October 29, 2024 18:37
@hyp
Copy link
Contributor Author

hyp commented Oct 29, 2024

@jmschonfeld Updated the PR as requested, and linked to the NDK issue.

@hyp
Copy link
Contributor Author

hyp commented Oct 29, 2024

@swift-ci please test

Copy link
Contributor

@jmschonfeld jmschonfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks!

@hyp hyp merged commit ab00100 into swiftlang:main Oct 29, 2024
3 checks passed
cthielen pushed a commit to cthielen/swift-foundation that referenced this pull request Nov 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants