std.path.shell throws exception with garbage string

Jonathan M Davis jmdavisProg at gmx.com
Wed Mar 9 16:20:05 PST 2011


On Wednesday, March 09, 2011 15:55:07 Andrej Mitrovic wrote:
> import std.process;
> 
> void main()
> {
>     char[] chBuffer = new char[](256);
>     chBuffer[] = '\0';
>     chBuffer[0..3] = "dir".dup;
> 
>     auto result = shell(chBuffer.idup);
> }
> 
> It does two things:
> 1. It prints out the result of the shell invocation to stdout. This
> shouldn't happen.
> 
> 2. It throws this:
> std.file.FileException at std\file.d(295):
> 5a5785b9a9ef300e292f021170a6bb2e34b80c86bb8decbb6b9b8d3b5e852cd
> 
> This sample works:
> import std.process;
> 
> void main()
> {
>     string chBuffer = "dir";
>     auto result = shell(chBuffer);
> }
> 
> Here the shell invocation isn't printed to the screen, but stored in result
>  like it should be.
> 
> The problem is I'm working with the win32 API and I can't use lovely D
> strings. I've tried using to!string and .idup on the call to 'shell', I've
> tried appending null's to the char[] but nothing seems to help. What am I
> doing wrong?

How about not feeding any strings with stray '\0' characters in it. shell takes 
a D string, which is _not_ null terminated. Looking at the implementation for 
cmd on Windows, it ultimately calls std.c.process.system which _does_ take a 
null terminated string, but the string that is fed to system has stuff _after_ 
the string that you give it. That means that feeding it a string with '\0' in it 
like that is going to give a bad string to system, so it fails. In order to get 
the output of the command that you run, shell attempts to redirect the output to 
file, but your nulls screw it up and it doesn't get redirected and the file never 
gets created. The filename is a randomly generated number - hence the bizarre 
exception message.

If you put '\0' in the middle of a string, D will just treat it as data, whereas  
functions will cut off at that point and assume that the string ended there. If 
you're passing a string to a C function, make sure it's null-terminated. If 
you're passing a string to a D function, do _not_ null-terminate it. You're 
passing a null-terminated string to a D function. That's just asking for 
trouble.

What you need to do is only pass the string up to - but not including - the null 
terminator to shell. If you have a char*, then to!string should do the right 
thing. But if you have a char[], then you either need to slice it right before 
the null terminator or use its ptr property and use to!string on _that_.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list