os.Getwd inspects PWD?

1,267 views
Skip to first unread message

dra...@gmail.com

unread,
Jul 24, 2017, 8:44:13 PM7/24/17
to golang-dev, r...@golang.org, ia...@golang.org
Hi,

I noticed that os.Getwd() is not merely a pass-through to the system's getwd() (or rather getcwd()).  It attempts to inspect the PWD environment variable, generally set by the shell, and use that value if it is equivalent to the current directory.  The commit 6cee4d3e (reviewed here https://github.com/golang/go/issues/8400) that introduced this behavior (or possibly restored it after a previous change) seems to suggest that this is the way the standard C library function getwd() behaves on OS X.  Here's the commit message:

    os: in Getwd, $PWD override syscall.Getwd

    This makes os.Getwd mimic C getwd on OS X,
    and possibly other systems. The change on OS X
    was a regression from 1.2 to 1.3.

I have a few thoughts about this:

1. I'm not aware of any C library's getwd/getcwd that inspects PWD.  I don't have extensive experience developing on OS X, but it does not appear to behave that way on OS X Sierra 10.12.5 which I have installed on my system currently.
2. Performing this sort of high-level operation within a package named "os" is unexpected and potentially unwelcome when the user expects the traditional getwd/getcwd behavior that you would get in most (all?) other languages, e.g. C,C++,Java,Python,Perl,Ruby etc.
3. Inspecting PWD in os.Getwd _without_ updating PWD in os.Chdir is inconsistent and may lead to more confusion.  Personally, I find it very confusing to have os.Getwd() return vastly different results before and after changing into a sub-directory of the current directory.

While it can be useful to have a function that performs the high-level inspection of the PWD environment variable, the value is reduced when it is not updated as the current directory is changed.

While we could modify os.Chdir() to update PWD, it doesn't seem like the "os" package is the appropriate place to do that.  Perhaps the behavior of os.Getwd() should be modified so that it produces the behavior of the traditional C library's getwd/getcwd?  And new Getwd/Chdir functions could be introduced in an appropriate package, possibly "path"?, that inspect and update PWD as appropriate?

-Brandon

Ian Lance Taylor

unread,
Jul 25, 2017, 10:37:28 AM7/25/17
to dra...@gmail.com, golang-dev, Russ Cox
On Mon, Jul 24, 2017 at 12:53 PM, <dra...@gmail.com> wrote:
>
> I noticed that os.Getwd() is not merely a pass-through to the system's
> getwd() (or rather getcwd()). It attempts to inspect the PWD environment
> variable, generally set by the shell, and use that value if it is equivalent
> to the current directory. The commit 6cee4d3e (reviewed here
> https://github.com/golang/go/issues/8400) that introduced this behavior (or
> possibly restored it after a previous change) seems to suggest that this is
> the way the standard C library function getwd() behaves on OS X. Here's the
> commit message:
>
> os: in Getwd, $PWD override syscall.Getwd
>
> This makes os.Getwd mimic C getwd on OS X,
> and possibly other systems. The change on OS X
> was a regression from 1.2 to 1.3.

This was actually originally introduced by
https://github.com/golang/go/commit/23c81f74247f3d28d5de454e7629d8e01d20968c
when os.Getwd was added, before the first open source release of Go.


> I have a few thoughts about this:
>
> 1. I'm not aware of any C library's getwd/getcwd that inspects PWD. I don't
> have extensive experience developing on OS X, but it does not appear to
> behave that way on OS X Sierra 10.12.5 which I have installed on my system
> currently.
> 2. Performing this sort of high-level operation within a package named "os"
> is unexpected and potentially unwelcome when the user expects the
> traditional getwd/getcwd behavior that you would get in most (all?) other
> languages, e.g. C,C++,Java,Python,Perl,Ruby etc.

The C library more closely resembles the Go syscall library, and you
can get the behavior you want by calling syscall.Getwd. The os
library works at a level above the syscall library.


> 3. Inspecting PWD in os.Getwd _without_ updating PWD in os.Chdir is
> inconsistent and may lead to more confusion. Personally, I find it very
> confusing to have os.Getwd() return vastly different results before and
> after changing into a sub-directory of the current directory.
>
> While it can be useful to have a function that performs the high-level
> inspection of the PWD environment variable, the value is reduced when it is
> not updated as the current directory is changed.
>
> While we could modify os.Chdir() to update PWD, it doesn't seem like the
> "os" package is the appropriate place to do that. Perhaps the behavior of
> os.Getwd() should be modified so that it produces the behavior of the
> traditional C library's getwd/getcwd? And new Getwd/Chdir functions could
> be introduced in an appropriate package, possibly "path"?, that inspect and
> update PWD as appropriate?

The split you are asking for already exists. The syscall package
corresponds to what you want the os package to be, and the os package
corresponds to your suggested change to the path package.

So the question is: should we modify os.Chdir to modify PWD? It's an
imperfect solution if the program has races on os.Chdir, but I suppose
that such a program has problems anyhow. Your implicit argument about
subdirectories seems reasonable to me. So I would support changing
os.Chdir such that if PWD refers to the current directory, then
os.Chdir would update PWD to refer to the new directory. Want to open
an issue for that? https://golang.org/issue .

Ian

Rob Pike

unread,
Jul 25, 2017, 5:09:54 PM7/25/17
to Ian Lance Taylor, dra...@gmail.com, golang-dev, Russ Cox
It's been sad watching Unix degrade into a pile of hacks and special cases. There was once a better path.

I suppose the change proposed to os.Chdir is inevitable now. It is possible to make the system actually understand file names, though, even if Unix never will. See http://doc.cat-v.org/plan_9/4th_edition/papers/lexnames for an explanation.

-rob



Ian

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Brandon Casey

unread,
Jul 25, 2017, 5:41:03 PM7/25/17
to Ian Lance Taylor, golang-dev, Russ Cox
On Tue, Jul 25, 2017 at 7:37 AM, Ian Lance Taylor <ia...@golang.org> wrote:
> On Mon, Jul 24, 2017 at 12:53 PM, <dra...@gmail.com> wrote:
>>
>> I noticed that os.Getwd() is not merely a pass-through to the system's
>> getwd() (or rather getcwd()). It attempts to inspect the PWD environment
>> variable, generally set by the shell, and use that value if it is equivalent
>> to the current directory. The commit 6cee4d3e (reviewed here
>> https://github.com/golang/go/issues/8400) that introduced this behavior (or
>> possibly restored it after a previous change) seems to suggest that this is
>> the way the standard C library function getwd() behaves on OS X. Here's the
>> commit message:
>>
>> os: in Getwd, $PWD override syscall.Getwd
>>
>> This makes os.Getwd mimic C getwd on OS X,
>> and possibly other systems. The change on OS X
>> was a regression from 1.2 to 1.3.
>
> This was actually originally introduced by
> https://github.com/golang/go/commit/23c81f74247f3d28d5de454e7629d8e01d20968c
> when os.Getwd was added, before the first open source release of Go.

Heh, I notice inspecting PWD was used as a fallback and not the
primary method :-)

>> I have a few thoughts about this:
>>
>> 1. I'm not aware of any C library's getwd/getcwd that inspects PWD. I don't
>> have extensive experience developing on OS X, but it does not appear to
>> behave that way on OS X Sierra 10.12.5 which I have installed on my system
>> currently.
>> 2. Performing this sort of high-level operation within a package named "os"
>> is unexpected and potentially unwelcome when the user expects the
>> traditional getwd/getcwd behavior that you would get in most (all?) other
>> languages, e.g. C,C++,Java,Python,Perl,Ruby etc.
>
> The C library more closely resembles the Go syscall library, and you
> can get the behavior you want by calling syscall.Getwd. The os
> library works at a level above the syscall library.

Good point. It's always possible to get the system's getwd/getcwd via
the syscall package, but then that is system-dependent. Up to now,
I've viewed the os package as a normalized abstraction of a low-level
system api. Since no system that I'm aware of provides a getcwd/chdir
that inspects/updates PWD, I didn't expect that the os package would
do so.

>> 3. Inspecting PWD in os.Getwd _without_ updating PWD in os.Chdir is
>> inconsistent and may lead to more confusion. Personally, I find it very
>> confusing to have os.Getwd() return vastly different results before and
>> after changing into a sub-directory of the current directory.
>>
>> While it can be useful to have a function that performs the high-level
>> inspection of the PWD environment variable, the value is reduced when it is
>> not updated as the current directory is changed.
>>
>> While we could modify os.Chdir() to update PWD, it doesn't seem like the
>> "os" package is the appropriate place to do that. Perhaps the behavior of
>> os.Getwd() should be modified so that it produces the behavior of the
>> traditional C library's getwd/getcwd? And new Getwd/Chdir functions could
>> be introduced in an appropriate package, possibly "path"?, that inspect and
>> update PWD as appropriate?
>
> The split you are asking for already exists. The syscall package
> corresponds to what you want the os package to be, and the os package
> corresponds to your suggested change to the path package.

Fair enough.

> So the question is: should we modify os.Chdir to modify PWD? It's an
> imperfect solution if the program has races on os.Chdir, but I suppose
> that such a program has problems anyhow.

Yeah, if you're concurrently calling chdir from multiple threads,
you've got problems :-)

> Your implicit argument about
> subdirectories seems reasonable to me. So I would support changing
> os.Chdir such that if PWD refers to the current directory, then
> os.Chdir would update PWD to refer to the new directory. Want to open
> an issue for that? https://golang.org/issue .

Ok, sounds reasonable. I just need to shift my view of the os package
and then it makes sense to teach os.Chdir to update PWD.

Thanks Ian, I'll open an issue.

-Brandon

gtow...@gmail.com

unread,
Jul 25, 2017, 6:23:28 PM7/25/17
to golang-dev, ia...@golang.org, r...@golang.org


On Tuesday, July 25, 2017 at 2:41:03 PM UTC-7, Brandon Casey wrote:
On Tue, Jul 25, 2017 at 7:37 AM, Ian Lance Taylor <ia...@golang.org> wrote:
...

> Your implicit argument about
> subdirectories seems reasonable to me.  So I would support changing
> os.Chdir such that if PWD refers to the current directory, then
> os.Chdir would update PWD to refer to the new directory.  Want to open
> an issue for that?  https://golang.org/issue .

Ok, sounds reasonable.  I just need to shift my view of the os package
and then it makes sense to teach os.Chdir to update PWD.

It would be surprising to me if os.Chdir were to change $PWD.  I expect $PWD to contain the directory as set by the shell (or whoever) at the start of execution and I would not want os.Chdir to change it as a side effect.

-- Gregg
 

Brandon Casey

unread,
Jul 25, 2017, 6:34:21 PM7/25/17
to Rob Pike, Ian Lance Taylor, golang-dev, Russ Cox
On Tue, Jul 25, 2017 at 2:09 PM, Rob Pike <r...@golang.org> wrote:
> It's been sad watching Unix degrade into a pile of hacks and special cases.
> There was once a better path.

*sigh*

> I suppose the change proposed to os.Chdir is inevitable now. It is possible
> to make the system actually understand file names, though, even if Unix
> never will. See http://doc.cat-v.org/plan_9/4th_edition/papers/lexnames for
> an explanation.

Hmm, yes, using PWD at all seems to suggest that the entire suite of
functions in the os package should take PWD into account when they
interpret their path arguments, and update PWD as appropriate.

Is this something that we think the os package should do?

-Brandon
>> email to golang-dev+...@googlegroups.com.

Rob Pike

unread,
Jul 25, 2017, 8:11:28 PM7/25/17
to Brandon Casey, Ian Lance Taylor, golang-dev, Russ Cox
I completely disagree. I think os.Chdir has no business playing with the environment variables.

-rob

Rob Pike

unread,
Jul 25, 2017, 8:14:57 PM7/25/17
to Brandon Casey, Ian Lance Taylor, golang-dev, Russ Cox
If you admit that os.Chdir is just wrapping a system call, its purpose is clear. If instead you state that it must emulate higher-level tools that worry about directories, things get much fuzzier and, critically, introduce much more stringent, even impossible, standards for portability across operating systems.

I say leave it alone. Reading PWD is one thing (and certainly misleading in many cases, but we're stuck with it now), but setting it is just a blanket bad idea.

-rob

Bakul Shah

unread,
Jul 25, 2017, 9:18:36 PM7/25/17
to Rob Pike, Brandon Casey, Ian Lance Taylor, golang-dev, Russ Cox
On Wed, 26 Jul 2017 10:11:01 +1000 Rob Pike <r...@golang.org> wrote:
>
> I completely disagree. I think os.Chdir has no business playing with the
> environment variables.

I completely agree! $PWD may not even exist in process env.
$PWD was introduced for shell script use and most shells on
startup ignore its passed in value and recompute it. It
shouldn't even have been an env. variable.

BTW, I looked at issue #8400 mentioned earlier in this thread
and I don't see the behavior Russ saw. See below. Tested on
OS X Sierra.

Turns out getwd(3) and getcwd(3) return /private/tmp, not
/tmp. chdir("..") leaves you in "/private". And this is
consistent with what *BSD has always done with symlinks.

But /bin/pwd returns /tmp and "cd /tmp; cd .." leaves you in
/ and not in /private. Not sure why they put the "fix" in the
wrong place.

Symlinks are indeed scrwed up but the place to fix that is in
the unix kernel.

$ cd /tmp
# cat >foo.c<<'EOF'
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

char buf[1024];

int main() {
printf("%s\n", getenv("PWD"));
printf("%s\n", getcwd(buf, sizeof buf));
chdir("..");
printf("%s\n", getcwd(buf, sizeof buf));
}
EOF
$ cc foo.c
$ PWD=foo ./a.out
$ PWD=foo sh -c 'echo $PWD'

Brandon Casey

unread,
Jul 25, 2017, 11:17:11 PM7/25/17
to Rob Pike, Ian Lance Taylor, golang-dev, Russ Cox
On Tue, Jul 25, 2017 at 5:14 PM, Rob Pike <r...@golang.org> wrote:
> If you admit that os.Chdir is just wrapping a system call, its purpose is
> clear.

This was actually my original assertion. I thought it was strange
that os.Getwd() was reading PWD and assumed the os package was merely
supposed to be a wrapper around the system's getwd/getcwd.

> If instead you state that it must emulate higher-level tools that
> worry about directories, things get much fuzzier and, critically, introduce
> much more stringent, even impossible, standards for portability across
> operating systems.
>
> I say leave it alone. Reading PWD is one thing (and certainly misleading in
> many cases, but we're stuck with it now), but setting it is just a blanket
> bad idea.

Why are we stuck with it? If the os package _is_ supposed to be a
normalized abstraction of a low-level system api, then why should
os.Getwd ever inspect PWD?

-Brandon

Rob Pike

unread,
Jul 25, 2017, 11:24:02 PM7/25/17
to Brandon Casey, Ian Lance Taylor, golang-dev, Russ Cox
The behavior is established so we would need more than a philosophical justification to contradict the Go 1 compatibility guidelines by removing it.

-rob

Ralph Corderoy

unread,
Jul 26, 2017, 5:53:05 AM7/26/17
to golang-dev, Brandon Casey
Hi,

rob wrote:
> I say leave it alone. Reading PWD is one thing (and certainly
> misleading in many cases, but we're stuck with it now), but setting it
> is just a blanket bad idea.

http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
says

PWD
This variable shall represent an absolute pathname of the
current working directory. It shall not contain any components
that are dot or dot-dot. The value is set by the cd utility,
and by the sh utility during initialization.

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cd.html says
lots, including how cd(1)'s -L and -P affect the setting of PWD, and

PWD
This variable shall be set as specified in the DESCRIPTION. If
an application sets or unsets the value of PWD, the behavior of
cd is unspecified.

I'd say Go has no business modifying PWD when it changes a process's
CWD. If a coder wants to pass a PWD that's different to the inherited value
over execve(2) to children then it's already able to do so.

--
Cheers, Ralph.
https://plus.google.com/+RalphCorderoy

Brandon Casey

unread,
Jul 26, 2017, 12:57:13 PM7/26/17
to Rob Pike, Ian Lance Taylor, golang-dev, Russ Cox
Well, the current behavior was introduced in Go 1.4, so it seems like
it could be argued that by reverting it we would restore the behavior
that was promised by the Go 1 compatibility guidelines couldn't it?

I personally find it much more surprising that os.Getwd() may return
vastly different results before and after cd'ing into a subdirectory
of the original PWD, than I would by it returning the same value that
getwd/getcwd and nearly every other language does.

-Brandon

roger peppe

unread,
Jul 26, 2017, 1:43:53 PM7/26/17
to Brandon Casey, Rob Pike, Ian Lance Taylor, golang-dev, Russ Cox
ISTR that $PWD is only advisory. I suspect that Getwd should only
return $PWD if it stats it and finds that it's the same directory as
that returned by the underlying syscall.

Then it doesn't matter if Chdir sets $PWD or not, because you're guaranteed
that Getwd will always return something reasonably legitimate even if $PWD
is set to something entirely spurious.


--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.

Jan Mercl

unread,
Jul 26, 2017, 1:51:37 PM7/26/17
to roger peppe, golang-dev

On Wed, Jul 26, 2017 at 7:43 PM roger peppe <rogp...@gmail.com> wrote:

> ISTR that $PWD is only advisory. I suspect that Getwd should only
> return $PWD if it stats it and finds that it's the same directory as
> that returned by the underlying syscall.

My understanding of the above is

        if a == b {
                return b
        }

        return b

What's the point of the stat then?

--

-j

Ian Lance Taylor

unread,
Jul 26, 2017, 1:53:42 PM7/26/17
to roger peppe, Brandon Casey, Rob Pike, golang-dev, Russ Cox
On Wed, Jul 26, 2017 at 10:43 AM, roger peppe <rogp...@gmail.com> wrote:
>
> ISTR that $PWD is only advisory. I suspect that Getwd should only
> return $PWD if it stats it and finds that it's the same directory as
> that returned by the underlying syscall.

That is exactly how it works.

Ian

Ian Lance Taylor

unread,
Jul 26, 2017, 1:55:05 PM7/26/17
to Jan Mercl, roger peppe, golang-dev
It is possible for `$PWD` and `getcwd` to return different names for
the same directory when symlinks are involved. The current behavior
of `os.Getwd` is to prefer the `$PWD` value if it resolves to the same
directory as the `getcwd` value.

Ian

Brandon Casey

unread,
Jul 26, 2017, 1:57:35 PM7/26/17
to roger peppe, Rob Pike, Ian Lance Taylor, golang-dev, Russ Cox
On Wed, Jul 26, 2017 at 10:43 AM, roger peppe <rogp...@gmail.com> wrote:
> ISTR that $PWD is only advisory. I suspect that Getwd should only
> return $PWD if it stats it and finds that it's the same directory as
> that returned by the underlying syscall.

That's the behavior it currently has. Why should that be the desired behavior?

> Then it doesn't matter if Chdir sets $PWD or not, because you're guaranteed
> that Getwd will always return something reasonably legitimate even if $PWD
> is set to something entirely spurious.

What you do not get by having os.Getwd return a value that is
sometimes based on PWD and sometimes not, and by having every other
function in the os package completely ignore PWD when they perform
their operations, is consistency. So the principle of least surprise
is violated in my opinion.

You also get behavior that is different from the behavior that most
(all?) other languages have with respect to their getwd
implementation.

-Brandon
>> email to golang-dev+...@googlegroups.com.

Ian Lance Taylor

unread,
Jul 26, 2017, 1:58:01 PM7/26/17
to Brandon Casey, Rob Pike, golang-dev, Russ Cox
On Wed, Jul 26, 2017 at 9:57 AM, Brandon Casey <dra...@gmail.com> wrote:
> Well, the current behavior was introduced in Go 1.4, so it seems like
> it could be argued that by reverting it we would restore the behavior
> that was promised by the Go 1 compatibility guidelines couldn't it?

It's more complicated than that. See https://golang.org/issue/8400.
In any case, that style of argument only works for one releases, not
since Go 1.4.

Ian

Brandon Casey

unread,
Jul 26, 2017, 2:25:08 PM7/26/17
to Ian Lance Taylor, Rob Pike, golang-dev, Russ Cox
Yes, I've read that issue and I'm really not sure what I can trust in
it, since it also makes the claim:

The C library routine getwd returns "/tmp".

..which seems completely bogus to me. So at least some of the basis
for the change was flawed.

If this is the 1.2 release of Getwd:

$ git show go1.2:src/pkg/os/getwd.go
<snip>
func Getwd() (pwd string, err error) {
// If the operating system provides a Getwd call, use it.
if syscall.ImplementsGetwd {
s, e := syscall.Getwd()
if useSyscallwd(e) {
return s, NewSyscallError("getwd", e)
}
}
<snip>

..and this is the 1.1 release:

$ git show go1.1:src/pkg/os/getwd.go
<snip>
func Getwd() (pwd string, err error) {
// If the operating system provides a Getwd call, use it.
if syscall.ImplementsGetwd {
s, e := syscall.Getwd()
return s, NewSyscallError("getwd", e)
}
<snip>

..and this is the 1.0 release:

$ git show go1:src/pkg/os/getwd.go
<snip>
func Getwd() (pwd string, err error) {
// If the operating system provides a Getwd call, use it.
if syscall.ImplementsGetwd {
s, e := syscall.Getwd()
return s, NewSyscallError("getwd", e)
}
<snip>

..and likewise for go1.3:src/pkg/os/getwd.go, then it seems like the
default behavior for os.Getwd has been to use syscall.Getwd() since
the first Go 1 release, and not until Go1.4 did it change to prefer
PWD over the result of syscall.Getwd().

It looks like the catalyst for issue 8400 was commit 7963ba6 which
changed the behavior of os.Getwd on OS X, and in response, commit
6cee4d3 changed it on all others.

-Brandon

Bakul Shah

unread,
Jul 26, 2017, 4:12:16 PM7/26/17
to roger peppe, Brandon Casey, Rob Pike, Ian Lance Taylor, golang-dev, Russ Cox
On Wed, 26 Jul 2017 18:43:45 BST roger peppe <rogp...@gmail.com> wrote:
>
> ISTR that $PWD is only advisory. I suspect that Getwd should only
> return $PWD if it stats it and finds that it's the same directory as
> that returned by the underlying syscall.
>
> Then it doesn't matter if Chdir sets $PWD or not, because you're guaranteed
> that Getwd will always return something reasonably legitimate even if $PWD
> is set to something entirely spurious.

Consider:

package main

import ("fmt"; "os")

func main() {
os.Chdir("/private/tmp")
cwd, _ := os.Getwd()
fmt.Println(cwd)
}

On OS X, cwd will be /tmp if the program was started in /tmp
but /private/tmp if started elsewhere. *Even though* I gave
chdir a rooted path that has no symlinks in it, Getwd()
returns a result that contains a symlink!

Sure, the result can be explained but all you have done is
pushed the surprise around, not gotten rid of.

roger peppe

unread,
Jul 26, 2017, 7:50:04 PM7/26/17
to Bakul Shah, r, Brandon Casey, Russ Cox, golang-dev, Ian Lance Taylor
Can you provide an example where that would actually matter?

Brandon Casey

unread,
Jul 26, 2017, 8:37:24 PM7/26/17
to roger peppe, Bakul Shah, r, Russ Cox, golang-dev, Ian Lance Taylor
An example is moot anyway isn't it? (aside from being an educational exercise)

If it doesn't matter, then why should we go through the trouble of
doing anything other than simply returning the result of
syscall.Getwd().

If it does matter, then we should do the most obvious thing that is
least likely to cause surprise, which is also to simply return the
result of syscall.Getwd().

-Brandon

Matt Harden

unread,
Jul 27, 2017, 1:48:51 PM7/27/17
to Brandon Casey, roger peppe, Bakul Shah, r, Russ Cox, golang-dev, Ian Lance Taylor
Maybe we should all unset PWD at the start of our Go programs to avoid this dumb behavior.

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.

Bryan C. Mills

unread,
Jul 27, 2017, 2:12:29 PM7/27/17
to Brandon Casey, roger peppe, Bakul Shah, r, Russ Cox, golang-dev, Ian Lance Taylor
On Wed, Jul 26, 2017 at 8:37 PM, Brandon Casey <dra...@gmail.com> wrote:
An example is moot anyway isn't it?  (aside from being an educational exercise)

If it doesn't matter, then why should we go through the trouble of
doing anything other than simply returning the result of
syscall.Getwd().

Because history matters. We need a motivating example is to justify the *new* costs, not the previous ones. The "trouble" of changing the API includes not only changing the standard library, but also updating all of the code that had come to rely on its current behavior.

Regardless of whether the current behavior was a mistake, the costs of changing existing code to adapt to it have largely concluded: we cannot un-pay what we have already paid. The only new costs of the current behavior are the issues that users encounter going forward — in other words, exactly the examples Roger is asking you to provide.


Matt Harden

unread,
Jul 27, 2017, 8:59:30 PM7/27/17
to Bryan C. Mills, Brandon Casey, roger peppe, Bakul Shah, r, Russ Cox, golang-dev, Ian Lance Taylor
Inconsistency makes me sad, even when it isn't actively hurting me at the moment. Now whenever I use os.Getwd, I have to understand it will try to be smart and give me a different answer than I would intuitively expect. I think that any program that depends on this behavior is likely to be buggy as a result - what if it gets run in an environment that doesn't set PWD, or where it is not in sync with the current directory? So I also have to avoid depending on this behavior.

This conversation also led me to discover that POSIX actually requires /bin/pwd to behave this way (use PWD)! Happily GNU coreutils was enlightened enough to ignore that requirement: https://git.savannah.gnu.org/cgit/coreutils.git/tree/src/pwd.c?id=c8ee5f19e8c697c860a5d23cd44ed300c0c222a2#n330.

To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.

Hiroshi Ioka

unread,
Jul 28, 2017, 7:19:44 AM7/28/17
to golang-dev, bcm...@google.com, dra...@gmail.com, rogp...@gmail.com, ba...@bitblocks.com, r...@golang.org, r...@golang.org, ia...@golang.org
FWIW, http://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html says:
The pathname shall contain no components that are dot or dot-dot, or are symbolic links. 

And, the old Apple implementation doesn't follow it. I suppose that is the behavior mentioned in #8400.
See
  https://opensource.apple.com/source/Libc/Libc-166/gen.subproj/getcwd.c.auto.html
  https://opensource.apple.com/source/Libc/Libc-1158.50.2/gen/FreeBSD/getcwd.c.auto.html
for detail if you are interested in.

Hiroshi

Austin Clements

unread,
Jul 31, 2017, 10:45:39 AM7/31/17
to Matt Harden, Bryan C. Mills, Brandon Casey, roger peppe, Bakul Shah, r, Russ Cox, golang-dev, Ian Lance Taylor
On Thu, Jul 27, 2017 at 8:59 PM, Matt Harden <matt....@gmail.com> wrote:
Inconsistency makes me sad, even when it isn't actively hurting me at the moment. Now whenever I use os.Getwd, I have to understand it will try to be smart and give me a different answer than I would intuitively expect. I think that any program that depends on this behavior is likely to be buggy as a result - what if it gets run in an environment that doesn't set PWD, or where it is not in sync with the current directory? So I also have to avoid depending on this behavior.

If PWD isn't set or is not in sync with the current directory, os.Getwd will simply ignore it. It won't return a path that isn't a legitimate path to the current working directory.

This conversation also led me to discover that POSIX actually requires /bin/pwd to behave this way (use PWD)! Happily GNU coreutils was enlightened enough to ignore that requirement: https://git.savannah.gnu.org/cgit/coreutils.git/tree/src/pwd.c?id=c8ee5f19e8c697c860a5d23cd44ed300c0c222a2#n330.

Though, curiously, GNU libc provides get_current_dir_name, which (beyond being the easiest way to avoid buffer overruns) also has the PWD behavior.

roger peppe

unread,
Jul 31, 2017, 1:30:45 PM7/31/17
to Austin Clements, Matt Harden, Bryan C. Mills, Brandon Casey, Bakul Shah, r, Russ Cox, golang-dev, Ian Lance Taylor
On 31 July 2017 at 15:45, Austin Clements <aus...@google.com> wrote:
> On Thu, Jul 27, 2017 at 8:59 PM, Matt Harden <matt....@gmail.com> wrote:
>>
>> Inconsistency makes me sad, even when it isn't actively hurting me at the
>> moment. Now whenever I use os.Getwd, I have to understand it will try to be
>> smart and give me a different answer than I would intuitively expect. I
>> think that any program that depends on this behavior is likely to be buggy
>> as a result - what if it gets run in an environment that doesn't set PWD, or
>> where it is not in sync with the current directory? So I also have to avoid
>> depending on this behavior.
>
>
> If PWD isn't set or is not in sync with the current directory, os.Getwd will
> simply ignore it. It won't return a path that isn't a legitimate path to the
> current working directory.

Yeah, I'm still waiting for someone to come up with an example
where this logic might lead to an actual bug. I don't really
buy the "this prints something slightly surprising but still valid"
case.

If your code is that dependent on whether a path contains a symlink
or not, you should really be calling filepath.EvalSymlinks to make sure.

Russ Cox

unread,
Aug 1, 2017, 12:48:24 PM8/1/17
to roger peppe, Austin Clements, Matt Harden, Bryan C. Mills, Brandon Casey, Bakul Shah, r, golang-dev, Ian Lance Taylor
I'm sorry that os.Getwd doesn't do what you expect, but at this point I don't think we're going to make any changes to os.Getwd or os.Chdir without evidence of a dramatic benefit (absent in this thread) to outweigh the subtle behavioral changes that would be introduced by any change. They've been working well enough for many people for many years. Now that you know how they work by default, you can always adjust the defaults by calling syscall.Getwd; or clearing $PWD before calling os.Getwd; or setting $PWD after os.Chdir.

Russ

Brandon Casey

unread,
Aug 22, 2017, 2:22:33 AM8/22/17
to Russ Cox, roger peppe, Austin Clements, Matt Harden, Bryan C. Mills, Bakul Shah, r, golang-dev, Ian Lance Taylor
I don't understand why the burden of producing "evidence of dramatic
benefit" is somehow on those that are on the side of correct and
normal behavior.

When it's pointed out that a library call does not have correct and
normal behavior, I would expect the default mode of action to be to
correct the behavior unless there is strong evidence to indicate that
the change would cause significant harm or hardship. Especially for a
new-ish language like Go that will have significantly more code
written in it in the next few years than has been written to date, it
seems especially important to remove any remaining behaviors that
could cause confusion or surprise.

I seriously doubt there is any program out there that intentionally
relies on the current behavior of os.Getwd. I'm sure there are a few
that will break when they are run from a symlinked directory
specifically because of the _current_ behavior of os.Getwd. Glide is
one of them, and it's how I discovered this issue.

In this case, either behavior falls within the documented behavior of
os.Getwd which says:

"If the current directory can be reached via multiple paths (due to
symbolic links), Getwd may return any one of them."

So why not choose the behavior that is in-line with the behavior that
every other language has, and will be expected by every
mildly-seasoned developer?

-Brandon

Ian Lance Taylor

unread,
Aug 25, 2017, 1:55:17 AM8/25/17
to Brandon Casey, Russ Cox, roger peppe, Austin Clements, Matt Harden, Bryan C. Mills, Bakul Shah, r, golang-dev
On Mon, Aug 21, 2017 at 11:22 PM, Brandon Casey <dra...@gmail.com> wrote:
>
> I don't understand why the burden of producing "evidence of dramatic
> benefit" is somehow on those that are on the side of correct and
> normal behavior.

Because Go takes backward compatibility very seriously.

I very strongly encourage you to simply use syscall.Getwd and carry on.

Ian

Brandon Casey

unread,
Aug 25, 2017, 2:35:44 AM8/25/17
to Ian Lance Taylor, Russ Cox, roger peppe, Austin Clements, Matt Harden, Bryan C. Mills, Bakul Shah, r, golang-dev
On Thu, Aug 24, 2017 at 10:55 PM, Ian Lance Taylor <ia...@golang.org> wrote:
> On Mon, Aug 21, 2017 at 11:22 PM, Brandon Casey <dra...@gmail.com> wrote:
>>
>> I don't understand why the burden of producing "evidence of dramatic
>> benefit" is somehow on those that are on the side of correct and
>> normal behavior.
>
> Because Go takes backward compatibility very seriously.

That policy seems to be applied somewhat selectively. Backwards
compatibility didn't seem to be high on the list 3 years ago when this
behavior was introduced :-/

As I've tried to point out, changing this would not break backwards
compatibility since either behavior falls within the documented
behavior of os.Getwd. One behavior just happens to be consistent (and
sane IMHO) with the behavior of other languages, and the other is not.

-Brandon

Ian Lance Taylor

unread,
Aug 25, 2017, 5:54:17 PM8/25/17
to Brandon Casey, Russ Cox, roger peppe, Austin Clements, Matt Harden, Bryan C. Mills, Bakul Shah, r, golang-dev
On Thu, Aug 24, 2017 at 11:35 PM, Brandon Casey <dra...@gmail.com> wrote:
> On Thu, Aug 24, 2017 at 10:55 PM, Ian Lance Taylor <ia...@golang.org> wrote:
>> On Mon, Aug 21, 2017 at 11:22 PM, Brandon Casey <dra...@gmail.com> wrote:
>>>
>>> I don't understand why the burden of producing "evidence of dramatic
>>> benefit" is somehow on those that are on the side of correct and
>>> normal behavior.
>>
>> Because Go takes backward compatibility very seriously.
>
> That policy seems to be applied somewhat selectively. Backwards
> compatibility didn't seem to be high on the list 3 years ago when this
> behavior was introduced :-/

Perhaps that was a mistake.


> As I've tried to point out, changing this would not break backwards
> compatibility since either behavior falls within the documented
> behavior of os.Getwd. One behavior just happens to be consistent (and
> sane IMHO) with the behavior of other languages, and the other is not.

See Hyrum's Law: https://twitter.com/onoffleftright/status/885627206033997825 .

Ian
Reply all
Reply to author
Forward
0 new messages