Skip to content

Call chdir to change working directory in older versions of glibc #449

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

Closed
wants to merge 4 commits into from

Conversation

yim-lee
Copy link
Contributor

@yim-lee yim-lee commented Dec 1, 2023

Motivation:
SPM_posix_spawn_file_actions_addchdir_np_supported and SPM_posix_spawn_file_actions_addchdir_np simply return error for glibc versions < 2.29. This causes SwiftPM tools such as swift package-registry publish to be unusable on Amazon Linux 2, which has an older version of glibc installed.

Modifications:
For older versions of glibc, call chdir to change working directory as an alternative to posix_spawn_file_actions_addchdir_np. This way child process will inherit the working directory path.

@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 1, 2023

@swift-ci please test

@MaxDesiatov
Copy link
Contributor

@swift-ci test windows

@MaxDesiatov
Copy link
Contributor

Added more reviewers who either dealt with this problem before, or have to deal with old glibc now. 🙂

@@ -13,7 +14,8 @@ int SPM_posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *restric
# if __GLIBC_PREREQ(2, 29)
return posix_spawn_file_actions_addchdir_np(file_actions, path);
# else
return ENOSYS;
// Change working directory which child process will inherit
return chdir(path);
Copy link
Contributor

Choose a reason for hiding this comment

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

please don't do this. This is very racy and affects the whole process.

Copy link
Contributor

Choose a reason for hiding this comment

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

If you spawn two things at the same time this will fail horribly. return ENOSYS is correct here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a way to make it non racy? Or alternative solution?

Copy link
Contributor

Choose a reason for hiding this comment

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

With posix_spawn, the only way is posix_spawn_file_actions_addchdir_np.

You could use fork() + execve() and then you could chdir in the child process.

But if you don't want to rewrite to fork/exec and you don't have posix_spawn_file_actions_addchdir_np, then there's no way, no.

Copy link
Contributor

Choose a reason for hiding this comment

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

does Foundation process solve this problem, or is posix_spawn_file_actions_addchdir_np used there as well?

Copy link
Contributor

@MaxDesiatov MaxDesiatov Dec 1, 2023

Choose a reason for hiding this comment

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

Foundation uses that function as well, which is the cause of swiftlang/swift#59610, a fix for which had to be reverted.

Copy link
Contributor Author

@yim-lee yim-lee Dec 2, 2023

Choose a reason for hiding this comment

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

0216fd2 uses fork and execve. PTAL.

Motivation:
`SPM_posix_spawn_file_actions_addchdir_np_supported` and `SPM_posix_spawn_file_actions_addchdir_np` simply return error for glibc versions < 2.29. This causes SwiftPM tools such as `swift package-registry publish` to be unusable on Amazon Linux 2, which has an older version of glibc installed.

Modifications:
For older versions of glibc, call `chdir` to change working directory as an alternative to `posix_spawn_file_actions_addchdir_np`. This way child process will inherit the working directory path.
@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 2, 2023

@swift-ci please test

@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 2, 2023

@swift-ci please test Windows

@MaxDesiatov MaxDesiatov requested a review from weissi December 2, 2023 10:02
@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 2, 2023

@swift-ci please test

@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 2, 2023

@swift-ci please test Windows

@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 5, 2023

@swift-ci please test

2 similar comments
@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 5, 2023

@swift-ci please test

@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 5, 2023

@swift-ci please test

@neonichu
Copy link
Contributor

neonichu commented Dec 6, 2023

Can we make the switch to fork accessible in some way such that we can run the tests on Linux in both posix_spawn and fork modes?

Separately, I am a bit concerned that we're introducing yet another capability that Foundation doesn't have, it will make it even harder to ever switch away from maintaining our own process code.

@yim-lee yim-lee marked this pull request as draft December 7, 2023 19:51
@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 7, 2023

Can we make the switch to fork accessible in some way such that we can run the tests on Linux in both posix_spawn and fork modes?

Will look into this once we think the fork impl generally looks ok


if (redirect_out) {
// Open the write end of the pipe.
dup2(out_pipe[1], 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

who's reading that pipe? It appears like the parent waits for the child to complete and then reads those pipes.

That's a deadlock.

The child will fill up the pipe until it's full (assuming the child writes enough). And then the child will block until something reads from that pipe. So the child won't exit but the parent will wait for it to exit:

child waits for parent to read <-> parent waits for child to exit

dup2(1, 1);
dup2(2, 2);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

there are a bunch of things missing here:

} else if (*pid > 0) { // Parent process
// Wait for child process to finish
int status;
waitpid(*pid, &status, 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

this is suspicious: usually the parent needs to read from the stdout & stderr pipes it passed into the child. If not, the child will block if it writes more than the pipe has space for (usually somewhere between 8 and 128 kiB).

@yim-lee
Copy link
Contributor Author

yim-lee commented Dec 12, 2023

swiftlang/swift-package-manager#7187 is alternative approach that implements workaround just for unblocking swift package-registry publish tool.

@yim-lee
Copy link
Contributor Author

yim-lee commented Jan 5, 2024

Doing swiftlang/swift-package-manager#7187 instead. Closing this.

@yim-lee yim-lee closed this Jan 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants