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

ExpressionParser: inherit the environment for the REPL #9334

Open
wants to merge 1 commit into
base: stable/20230725
Choose a base branch
from

Conversation

compnerd
Copy link
Member

@compnerd compnerd commented Sep 25, 2024

This is particularly important on Windows where Path needs to be propagated to the inferior to allow LoadLibraryW(L"swiftCore.dll") to succeed. The library is looked up via the Path environment variable and the default target environment is empty. As a result, the library is not found and the inferior exits terminating the REPL instance.

Fixes: swiftlang/swift#76702
Fixes: swiftlang/swift#70005

This is particularly important on Windows where `Path` needs to be
propagated to the inferior to allow `LoadLibraryW(L"swiftCore.dll")` to
succeed. The library is looked up via the `Path` environment variable
and the default target environment is empty. As a result, the library is
not found and the inferior exits terminating the REPL instance.
@compnerd
Copy link
Member Author

@compnerd
Copy link
Member Author

@swift-ci please test

@kastiglione
Copy link

My one concern is: what issues will this have by inheriting the full environment? Either on windows or any other platform? Should this be smarter, possibly by inheriting only certain env variables (perhaps by platform)?

@compnerd
Copy link
Member Author

@kastiglione you are mirroring my concern and why I'm somewhat hesitant with making this change. On the other hand, I do agree with @al45tair that it is odd for the REPL to not have the full environment.

@kastiglione
Copy link

that's a fair point

@compnerd
Copy link
Member Author

@swift-ci please test macOS platform

1 similar comment
@compnerd
Copy link
Member Author

@swift-ci please test macOS platform

@compnerd
Copy link
Member Author

Can't seem to reproduce the test failure locally :/

@compnerd
Copy link
Member Author

@swift-ci please test macOS platform

@AnthonyLatsis
Copy link

@adrian-prantl Since this issue and llvm#70005 are being fixed in the LLVM repo, could you please transfer them?

@adrian-prantl
Copy link

@adrian-prantl Since this issue and llvm#70005 are being fixed in the LLVM repo, could you please transfer them?

Sorry I'm confused what you mean: transfer what to where?

@adrian-prantl
Copy link

@compnerd It sounds like that should be testable in a Shell repl test by running env FOO=1 lldb ... and calling getenv from withing the REPL and FileChecking the result.

I also agree with @kastiglione : What do you think about allow-listing the environment settings you need?

@compnerd
Copy link
Member Author

compnerd commented Oct 3, 2024

@adrian-prantl would we also whitelist the random testing environment variable? I think that we should be allowing all the environment variables really - why would the REPL which is launched from the shell not have its environment variables? I may be doing something like GIVE_ME_MY_ENVIRONMENT_VARIABLE=YES swift repl and then expecting to be able to use it.

@jimingham
Copy link

I would expect:

lldb -O "settings set target.env-vars FOO=bar" --repl

would make a REPL in which there is an environment variable FOO that has the value BAR. I don't think this will be true if you just use the inherited environment. So I think it is formally wrong to just swap out the target one for the inherited one.

If we need to provide certain environment variables to the REPL for it to work, I think you need to add them to the target environment.

@adrian-prantl
Copy link

Who is setting these environment variables in the first place? I'm also wondering if the swift driver (invoked as swift repl) should be launching lldb using the flag @jimingham mentioned instead.

@al45tair
Copy link

al45tair commented Oct 4, 2024

Who is setting these environment variables in the first place?

Anyone, but generally the user, the operating system, installers that modify the default environment variables. Perhaps it would help to contrast with Python:

$ python
Python 3.9.6 (default, Aug  9 2024, 14:24:13) 
[Clang 16.0.0 (clang-1600.0.26.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ["HOME"]
'/Users/alastair'

but

$ swift repl
Welcome to Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2).
Type :help for assistance.
  1> import Foundation
  2> ProcessInfo.processInfo.environment["HOME"]
$R0: String? = nil

I don't think the notion that the target has a separate environment that isn't inherited is very useful for the repl. If users want to set extra environment variables for the repl, they'll do so like this:

$ MY_VARIABLE=foobar swift repl

and not by passing extra arguments to lldb.

@al45tair
Copy link

al45tair commented Oct 4, 2024

This isn't just a Windows problem, I might add. It's weird on Darwin, never mind Windows. It's just on Windows it also breaks things in a really obvious manner, because dynamic library loading relies on Path. On Linux and Darwin, you likely won't get link errors, but things like TERM, LANG and HOME are going to be a problem.

@al45tair
Copy link

al45tair commented Oct 4, 2024

I would expect:

lldb -O "settings set target.env-vars FOO=bar" --repl

would make a REPL in which there is an environment variable FOO that has the value BAR. I don't think this will be true if you just use the inherited environment. So I think it is formally wrong to just swap out the target one for the inherited one.

If we need to provide certain environment variables to the REPL for it to work, I think you need to add them to the target environment.

I think we want to provide all the environment variables to the REPL. The fact that REPL happens to be LLDB under the covers is an implementation detail, and I don't think swift-driver should be passing the environment through by adding commands to the LLDB command line. It may be that this PR is wrong and that --repl should cause LLDB to initialise the target environment from the inherited environment (which would make the -O "settings set target.env-vars FOO=bar" above work), but fundamentally the REPL should have access to the environment in which swift repl was executed.

@AnthonyLatsis
Copy link

Sorry I'm confused what you mean: transfer what to where?

Sorry, I meant to post that in swiftlang/swift#76702 (transfer these two issues to llvm-project). Wrong browser tab.

@jimingham
Copy link

jimingham commented Oct 7, 2024 via email

@al45tair
Copy link

al45tair commented Oct 7, 2024

I'm not sure why you assert this as a general rule. Why, for instance, should the equivalent of DYLD_LIBRARY_PATH necessarily be shared - i.e. why should lldb & the REPL victim program necessarily load the same shared libraries. lldb can also debug programs that don't have the same architecture, so you could, on macOS, launch an x86_64 victim program, and connect an arm64 lldb to it. It doesn't seem to me those two programs necessarily have the same environment either. It's fine to have a way to easily say "I want to run the REPL with the same environment that my lldb has", but I don't see this having the force of necessity. Jim

That only makes sense if you think of the REPL as LLDB, but users of Swift don't see it that way; what they see is swift repl doesn't behave the same way as python, php -a, node, gore etcetera.

People using swift repl are not trying to debug a program (let alone remotely). They just want somewhere they can type Swift code and have it evaluated. If that somewhere doesn't see the same environment variables as the shell they started the repl from, it seems odd and broken.

@al45tair
Copy link

al45tair commented Oct 7, 2024

To take the specific example of DYLD_LIBRARY_PATH, yes absolutely if I do

$ DYLD_LIBRARY_PATH=/foo/bar swift repl
Welcome to Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2).
Type :help for assistance.
  1> import Darwin
  2> let foo = dlopen("foobar.dylib", RTLD_NOW)

I'm expecting the dynamic loader to look for foobar.dylib in /foo/bar. And as a user of the Swift REPL, I'm not really aware that I'm running LLDB under the covers. I accept, though, that if the DYLD_LIBRARY_PATH setting upsets the REPL process somehow and makes it go wrong, well, that's my problem.

@jimingham
Copy link

jimingham commented Oct 7, 2024 via email

@al45tair
Copy link

al45tair commented Oct 8, 2024

There's no formal reason why you have to do "in order to run the REPL victim program with a set of environment variables, lldb has to run with the same set".

That's true, there's no fundamental reason we have to run LLDB with the same set. But… doing anything else necessitates filtering out environment variables that might break LLDB, and then somehow passing them to LLDB so that they are inherited by the target process. That isn't trivial.

Are we suggesting, for instance, that the driver should somehow know how to filter Path on Windows to remove things that might break LLDB? Because Windows requires Path to be set correctly in order to load DLLs, including potentially ones that LLDB itself depends upon; without it, we might not even get as far as running LLDB in the first place. But with it, who is to say that some item in Path won't break LLDB?

And it's not like the REPL gains much from doing this; you can still trivially break it with the same variables you're worrying about by setting them in such a way that the driver itself won't work, so we can't say to the user that setting "dangerous" environment variables is safe, because it isn't.

@adrian-prantl
Copy link

This was also what I was getting at with my earlier question:

  • should LLDB in REPL mode inherit the environment, or
  • should the Swift driver set the environment of the inferior when launching LLDB as swift repl?

@al45tair
Copy link

al45tair commented Oct 8, 2024

This was also what I was getting at with my earlier question:

  • should LLDB in REPL mode inherit the environment, or
  • should the Swift driver set the environment of the inferior when launching LLDB as swift repl?

The most important thing is that the environment in which swift repl is run is available to the inferior process.

In principle it doesn't matter so much if the hidden LLDB itself has a different environment. However, if you're arguing that the driver should provide LLDB with a different environment, for instance by filtering out DYLD_LIBRARY_PATH, it's unclear to me what that actually buys us in terms of robustness. By the time the driver is in a position to do something like that, it has already been affected by the environment variables in question, and on Windows, the equivalent environment variable is Path, which has to be set for anything to work properly, so not passing it would just break everything.

Additionally, I worry that doing anything other than just leaving the environment alone is more complicated than it sounds; for instance, we might end up having to escape things if we're going to generate LLDB commands to set environment variables.

@jimingham
Copy link

jimingham commented Oct 8, 2024 via email

@compnerd
Copy link
Member Author

compnerd commented Oct 8, 2024

Note that in addition to Path, I believe that UserProfile and TEMP should be set up properly. In order to get Foundation to work, there are a few other variables as well. I think that SDKROOT also needs to be setup properly in some cases, and PROCESSOR_ARCHITECTURE is often consulted. I think that ComSpec is another one which can be used for process management, and so this is important to keep in the filter set. I imagine that the more I think about it, the longer the list will get.

@al45tair
Copy link

al45tair commented Oct 8, 2024

If that's an accurate assessment, then the swift driver can explicitly tell lldb it should "inherit the whole environment" - which you can do by passing -O "settings set target.inherit-env 1" in the launch line for lldb.

OK, that may be the thing that we need here, in which case that needs a driver change, which is fair.

@jimingham
Copy link

jimingham commented Oct 8, 2024 via email

@al45tair
Copy link

al45tair commented Nov 8, 2024

If I understand @jimingham correctly, the LLDB team has a preference for fixing #9551 and then we can update the Swift Driver to pass -O "settings set target.inherit-environment 1".

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.

6 participants