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

[SR-12843] NSString.expandingTildeInPath not working correctly if HOME variable is set #3255

Open
fabianfett opened this issue May 20, 2020 · 1 comment

Comments

@fabianfett
Copy link
Member

Previous ID SR-12843
Radar None
Original Reporter @fabianfett
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Foundation
Labels Bug
Assignee None
Priority Medium

md5: d00baaf0707960035a9b504222e29460

Issue Description:

If the default `$HOME` path is changed by an environment variable, `NSString.expandingTildeInPath` does not reflect this change.

As a user I would expect that `NSString.expandingTildeInPath` returns the same as `echo $HOME` or `echo ~` on the command line or a direct call against libc.

This problem surfaces when using GitHub actions where the default HOME path is changed to: `/github/home`

See: https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners

Code to reproduce:

#if os(Linux)
import Glibc
#else
import Darwin
#endif
import Foundation
 
func expandTildeInFilePath(_ filePath: String) -> String {
    filePath.withCString { (ptr) -> String in
        var wexp = wordexp_t()
        guard 0 == wordexp(ptr, &wexp, 0), let we_wordv = wexp.we_wordv else {
            return filePath
        }
        defer {
            wordfree(&wexp)
        }
        
        guard let resolved = we_wordv[0], let pth = String(cString: resolved, encoding: .utf8) else {
             return filePath
        }
        
        return pth
    }
}
 
let expandableFilePath = "~/test"
 
let expandedNewPath = expandTildeInFilePath(expandableFilePath)
let expandedNSString = NSString(string: expandableFilePath).expandingTildeInPath
 
print("results")
print("  Glibc/Darwin: \(expandedNewPath)")
print("  Foundation  : \(expandedNSString)")

Logs:

[ fat@fatBook-WLAN ] ~/Developer/nio/test
$> docker run -it --rm -v $(pwd):/src --workdir /src swift:5.2 /bin/bash                                  
root@4d76cca8d7e0:/src# swift build
root@4d76cca8d7e0:/src# .build/debug/test
results
  Glibc/Darwin: /root/test
  Foundation  : /root/test

[ fat@fatBook-WLAN ] ~/Developer/nio/test
$> docker run -it --rm -e HOME="/github/home" -v $(pwd):/src --workdir /src swift:5.2 /bin/bash
root@4d9507e716e5:/src# echo ~
/github/home
root@4d9507e716e5:/src# echo $HOME
/github/home
root@4d9507e716e5:/src# .build/debug/test
results
  Glibc/Darwin: /github/home/test
  Foundation  : /root/test

Verified with:

  • swift:5.2

  • swiftlang/swift:nightly-master-xenial

@spevans
Copy link
Collaborator

spevans commented Jun 3, 2020

Although NSString.expandingTildeInPath does make use of $HOME it checks the user's home directory using getpwnam(3) first so the $HOME is not considered

(see _CFCopyHomeDirURLForUser in

static CFURLRef _CFCopyHomeDirURLForUser(const char *username, bool fallBackToHome) {
)

However a re-reading of https://developer.apple.com/documentation/foundation/1413045-nshomedirectory, the documentation for NSHomeDirectory, says that it returns "In macOS, it is the application’s sandbox directory or the current user’s home directory (if the application is not in a sandbox)"

The sandboxing sets the CFFIXED_USER_HOME environment variable which overrides the use of getpwnam so it can be used as follows:

$ docker run -it --rm -e HOME="/github/home" -v $(pwd):/src --workdir /src swift:5.2 /bin/bash
root@65419c9f1a73:/src# cat home.swift
import Foundation

print("NSHomeDirectory()", NSHomeDirectory())
let homedir = ("~/somedir" as NSString).expandingTildeInPath
print(homedir)

print("NSHomeDirectoryForUser(\"unknown\")", NSHomeDirectoryForUser("unknown") as Any)
let homedir2 = ("~unknown/somedir" as NSString).expandingTildeInPath
print(homedir2)
root@65419c9f1a73:/src# swiftc -o home home.swift
root@65419c9f1a73:/src# ./home
NSHomeDirectory() /root
/root/somedir
NSHomeDirectoryForUser("unknown") nil
~unknown/somedir
root@65419c9f1a73:/src# CFFIXED_USER_HOME=${HOME} ./home 
NSHomeDirectory() /github/home
/github/home/somedir
NSHomeDirectoryForUser("unknown") Optional("/github/home")
/github/home/somedir
root@65419c9f1a73:/src# 

So the best workaround to use $HOME would be to use

export CFFIXED_USER_HOME=${HOME}

The code that uses $HOME cant really be changed in CoreFoundation as it would probably break other programs depending on the behaviour.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants