Discussion:
CreateProcess() randomly changes current directory (old? fixed?)
(too old to reply)
Charlie Gibbs
2022-11-29 23:29:14 UTC
Permalink
When calling CreateProcess() with lpCurrentDirectory set to NULL, the
child process is supposed to inherit the parent's current directory -
but I've learned the hard way that occasionally it doesn't. I've
had several instances where the child's current directory is set to
something random. The child program then fails because it can't find
files it's expecting to see in the current directory. Before it shuts
down it opens a log file in the current directory (wherever that now
may be), and writes an error message to it; log files have shown up
all over the disk.

This doesn't happen very often - but if you have 1000 customers running
your programs daily, it doesn't take long before anguished phone calls
start coming in.

So far the only completely reliable solution I've found is to include
code in my initialization routines to set the current directory to a
known value; I call GetModuleFileName() to determine where the program
loaded from, and set the current directory there. This works, but has
the disadvantage that my programs cannot run in a directory that is
different from the one in which their .EXE files live.

This might be an old bug that has long since been fixed - we had
a lot of trouble with it back in 2001 and 2002, and my belt-and-
suspenders solution has been in place ever since. It might be
safe to remove my fixes now, but we were burned so badly that
I'm reluctant to take the risk.

Has anyone else encountered this problem?

<rant>
Windows seems to take a cavalier attitude toward the concept of
"current directory". The GetOpenFileName() and GetSaveFileName()
APIs will change the current directory if the user goes into a
different directory while searching for files. The OPENFILENAME
structure passed to these APIs contains the flag OFN_NOCHANGEDIR,
whose purpose is to restore the current directory in such cases,
although I prefer to first call getcwd() and save the current
directory, then use chdir() to restore it afterwards.
Since I wrote this code myself, I trust it to be bombproof -
and should it turn out not to be, I can change it until it is.
</rant>
--
/~\ Charlie Gibbs | Life is perverse.
\ / <***@kltpzyxm.invalid> | It can be beautiful -
X I'm really at ac.dekanfrus | but it won't.
/ \ if you read it the right way. | -- Lily Tomlin
JJ
2022-11-30 00:29:22 UTC
Permalink
Post by Charlie Gibbs
When calling CreateProcess() with lpCurrentDirectory set to NULL, the
child process is supposed to inherit the parent's current directory -
but I've learned the hard way that occasionally it doesn't. I've
had several instances where the child's current directory is set to
something random. The child program then fails because it can't find
files it's expecting to see in the current directory. Before it shuts
down it opens a log file in the current directory (wherever that now
may be), and writes an error message to it; log files have shown up
all over the disk.
This doesn't happen very often - but if you have 1000 customers running
your programs daily, it doesn't take long before anguished phone calls
start coming in.
So far the only completely reliable solution I've found is to include
code in my initialization routines to set the current directory to a
known value; I call GetModuleFileName() to determine where the program
loaded from, and set the current directory there. This works, but has
the disadvantage that my programs cannot run in a directory that is
different from the one in which their .EXE files live.
This might be an old bug that has long since been fixed - we had
a lot of trouble with it back in 2001 and 2002, and my belt-and-
suspenders solution has been in place ever since. It might be
safe to remove my fixes now, but we were burned so badly that
I'm reluctant to take the risk.
Has anyone else encountered this problem?
<rant>
Windows seems to take a cavalier attitude toward the concept of
"current directory". The GetOpenFileName() and GetSaveFileName()
APIs will change the current directory if the user goes into a
different directory while searching for files. The OPENFILENAME
structure passed to these APIs contains the flag OFN_NOCHANGEDIR,
whose purpose is to restore the current directory in such cases,
although I prefer to first call getcwd() and save the current
directory, then use chdir() to restore it afterwards.
Since I wrote this code myself, I trust it to be bombproof -
and should it turn out not to be, I can change it until it is.
</rant>
`CreateProcess()` never change the working directory. If it's changed,
something must have changed it before `CreateProcess()` is called.

Like the Open/Save dialog that you've mentioned, which may change the
working directory depending on user input. User code is not the only one
which may change the working directory.

Different thread shouldn't change the working directory - even temporarily,
because it will create a chance for other threads to use the wrong working
directory. At least not without thread synchronization. Be it user code, or
API. Directly or indirectly.

My suggestion is to debug the launcher process and place breakpoints on
NTDLL functions which change the working directory.
Charlie Gibbs
2022-11-30 01:10:33 UTC
Permalink
Post by JJ
Post by Charlie Gibbs
When calling CreateProcess() with lpCurrentDirectory set to NULL, the
child process is supposed to inherit the parent's current directory -
but I've learned the hard way that occasionally it doesn't. I've
had several instances where the child's current directory is set to
something random.
<snip>
Post by JJ
`CreateProcess()` never change the working directory. If it's changed,
something must have changed it before `CreateProcess()` is called.
Like the Open/Save dialog that you've mentioned, which may change the
working directory depending on user input. User code is not the only one
which may change the working directory.
What makes it hard to diagnose is that it's very infrequent (i.e. highly
intermittent), and the directory I get changed to is completely random.
Post by JJ
Different thread shouldn't change the working directory - even temporarily,
because it will create a chance for other threads to use the wrong working
directory. At least not without thread synchronization. Be it user code, or
API. Directly or indirectly.
The programs in question are single-threaded.
Post by JJ
My suggestion is to debug the launcher process and place breakpoints on
NTDLL functions which change the working directory.
I've been thinking about doing this. The trick is to find a consistent
location in which I can log the results - an absolute path is probably
needed - and how to notify the support people should it happen at one
of our many customer sites. We do have e-mail capability - if I can
detect that something has gone awry I could probably jam the current
directory back to where we belong, then trigger our e-mail program.

And then again, since any further occurrences over the past 20 years
would have been masked by my workaround, there's no telling whether
it's ever happened since. Between prorgram maintenance and various
other upgrades, it might no longer be an issue. But I'll have to
tread softly.
--
/~\ Charlie Gibbs | If your nose runs
\ / <***@kltpzyxm.invalid> | and your feet smell,
X I'm really at ac.dekanfrus | you're built
/ \ if you read it the right way. | umop-apisdn.
Loading...