Re: std.path.shell throws exception with garbage string

2011-03-09 Thread Jonathan M Davis
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@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


Re: std.path.shell throws exception with garbage string

2011-03-09 Thread Andrej Mitrovic
Found myself a solution. And probably the cause of the issue. shell()
doesn't expect a null-terminated string, but just a string with the
shell command without any newlines or nulls.

So I can do this (importing std.algorithm for until):
auto command = to!string(chBuffer[].until('\n'));
auto result = shell(command);

Not too shabby.

Still that error message wasn't of much help. shell() internally
creates a temp file with a random file name, temporarily redirects
stdout to that file to catch the contents of a system() invocation,
and then reads that file with readtext(). Somehow, something errors
out if there's a newline or null in the string, and it all explodes
with a weird error message.


std.path.shell throws exception with garbage string

2011-03-09 Thread Andrej Mitrovic
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@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?