www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - segfaults

reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
Hello.

I'm trying to invoke a command inside d, and it returns a success code 
when the command in question segfaults.

any ideas?

// the caller
import std.process;

int main(){
     auto r = system("./test");
     return(r);
}


//test.d
import std.stdio;

void main()
{
     Object o;
     writeln(o.toString());
}
May 03 2010
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Mon, 03 May 2010 15:54:28 -0500, Ellery Newcomer wrote:

 Hello.
 
 I'm trying to invoke a command inside d, and it returns a success code
 when the command in question segfaults.
 
 any ideas?
 
 // the caller
 import std.process;
 
 int main(){
      auto r = system("./test");
      return(r);
 }
 
 
 //test.d
 import std.stdio;
 
 void main()
 {
      Object o;
      writeln(o.toString());
 }

It's a null dereference. What you're doing is essentially Object o = null; writeln(o.toString()); -Lars
May 03 2010
next sibling parent reply Bernard Helyer <b.helyer gmail.com> writes:
On 04/05/10 08:57, Lars T. Kyllingstad wrote:
 On Mon, 03 May 2010 15:54:28 -0500, Ellery Newcomer wrote:

 Hello.

 I'm trying to invoke a command inside d, and it returns a success code
 when the command in question segfaults.

 any ideas?

 // the caller
 import std.process;

 int main(){
       auto r = system("./test");
       return(r);
 }


 //test.d
 import std.stdio;

 void main()
 {
       Object o;
       writeln(o.toString());
 }

It's a null dereference. What you're doing is essentially Object o = null; writeln(o.toString()); -Lars

I believe his problem is that the return code of the caller indicates success.
May 03 2010
next sibling parent Bernard Helyer <b.helyer gmail.com> writes:
On 04/05/10 09:49, Steven Schveighoffer wrote:
 On Mon, 03 May 2010 17:25:30 -0400, Bernard Helyer <b.helyer gmail.com>
 wrote:
 I believe his problem is that the return code of the caller indicates
 success.

Could it be perhaps that it can't possibly get at that status? Remember, system runs /bin/sh -c, so all you can get as status is the return code of /bin/sh (which didn't segfault). -Steve

sh -c returns failure if the specified executable segfaults.
May 03 2010
prev sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 05/03/2010 04:49 PM, Steven Schveighoffer wrote:
 Could it be perhaps that it can't possibly get at that status? Remember,
 system runs /bin/sh -c, so all you can get as status is the return code
 of /bin/sh (which didn't segfault).

 -Steve

All I know is the analogous code in python returns the expected 139
May 03 2010
parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 05/03/2010 06:08 PM, Graham Fawcett wrote:
 What OS are you running on? In D2, this the definition of system():

      int system(string command)
      {
        if (!command) return std.c.process.system (null);
        const commandz = toStringz (command);
        invariant status = std.c.process.system (commandz);
        if (status == -1) return status;
        version (Posix)
          return (status&  0x0000ff00)>>>  8;
       else
         return status;
      }


 And "(139&  0x0000ff00)>>>  8" evaluates to 0.  I am not sure why it's
 not simply returning the raw status-code, though, and only on Posix
 systems -- it must be a Posix-ism I'm not familiar with.

 Graham

I'm on fedora, and yeah, I guess it's a posixism. investigation yields lower 16 bits is coredump flag and signal code upper 16 bits is status code I tell ya, working with D, ya learn something new every day [while implementing crap that the provided libraries should handle on their own...]
May 03 2010
parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 05/04/2010 01:58 AM, Lars T. Kyllingstad wrote:

 In your case the segfault would cause SIGSEGV (signal 11) to be sent to
 the process, and the the above test would print "Process terminated by
 signal 11".

 See "man wait" for more info.

That's where I got my info (or rather /usr/include/bits/waitstatus.h)
 std.process is currently undergoing a complete redesign, so the current
 situation should improve in the near future. :)

 -Lars

That's good to hear. And since you're an expert in this stuff, does this my code look alright? import std.typecons; static import std.c.process; import std.functional; import std.stdio; import std.string; alias Tuple!(ubyte, "status",ubyte, "term", ubyte, "sig",bool,"signaled",bool, "stopped", bool,"continued",bool, "coredumped") PID; PID toPID(int p){ PID pid; pid.status = cast(byte)((p & 0xff00) >> 8); pid.term = cast(byte)(p & 0xff); pid.sig = cast(byte)(p & 0x7f); pid.signaled = pid.sig != 0 && pid.sig != 0x7f; pid.coredumped = cast(bool)(p & 0x80); pid.stopped = pid.term == 0x7f; pid.continued = p == 0xffff; return pid; } int fromPID(PID pid){ if(pid.signaled) return pid.term; return pid.status; } alias compose!(toPID, std.c.process.system, toStringz) system_p; alias compose!(fromPID, system_p) system;
May 04 2010
next sibling parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 05/04/2010 09:51 AM, Graham Fawcett wrote:
 Thanks for posting this. Just curious -- why did you choose to model PID
 as a tuple instead of a struct? I'm not clear on what the tradeoffs are.

 Best,
 Graham

according to core.sys.posix.sys.wait, this is only valid for linux, grrr. I don't think there is a difference, as a tuple is a glorified struct. You just have to remember to use t.field instead of t.tupleof when iterating the elements in a foreach. Mostly, I just love one liners.
May 04 2010
prev sibling parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 05/04/2010 11:32 AM, Lars T. Kyllingstad wrote:
 Shouldn't 'term' and 'signaled' switch names?  It looks to me like 'term'
 will be nonzero if the process receives any signal, while 'signaled' will
 be only be true if it is a terminating signal, and not if it is a stop
 signal.

signaled corresponds to WIFSIGNALED, whatever that is, and takes its name. term has no justification for its name; I just want something that is the same as what bash returns on segfault. I don't know what it does on BSD, though.
 Otherwise it looks right, at least on Linux.  But why not use the
 core.sys.posix.sys.wait.Wxxx() functions?  Then it will automatically
 work on BSD and MacOS as well.

Easy, I didn't know about that module when I wrote this. alias Tuple!(int, "status",int, "signal", int, "termsig",bool, "signaled",bool, "stopped", bool,"continued") PID; PID toPID(int p){ PID pid; pid.status = WEXITSTATUS(p); pid.signal = (p & 0xff); pid.termsig = WTERMSIG(p); pid.signaled = WIFSIGNALED(p); pid.stopped = WIFSTOPPED(p); pid.continued = cast(bool) WIFCONTINUED(p); //why the eff is this defined as an int? return pid; } Is the coredump flag a linux-only thing?
May 04 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 May 2010 17:25:30 -0400, Bernard Helyer <b.helyer gmail.com>  
wrote:

 On 04/05/10 08:57, Lars T. Kyllingstad wrote:
 On Mon, 03 May 2010 15:54:28 -0500, Ellery Newcomer wrote:

 Hello.

 I'm trying to invoke a command inside d, and it returns a success code
 when the command in question segfaults.

 any ideas?

 // the caller
 import std.process;

 int main(){
       auto r = system("./test");
       return(r);
 }


 //test.d
 import std.stdio;

 void main()
 {
       Object o;
       writeln(o.toString());
 }

It's a null dereference. What you're doing is essentially Object o = null; writeln(o.toString()); -Lars

I believe his problem is that the return code of the caller indicates success.

Could it be perhaps that it can't possibly get at that status? Remember, system runs /bin/sh -c, so all you can get as status is the return code of /bin/sh (which didn't segfault). -Steve
May 03 2010
prev sibling next sibling parent Graham Fawcett <fawcett uwindsor.ca> writes:
On Mon, 03 May 2010 17:34:51 -0500, Ellery Newcomer wrote:

 On 05/03/2010 04:49 PM, Steven Schveighoffer wrote:
 Could it be perhaps that it can't possibly get at that status?
 Remember, system runs /bin/sh -c, so all you can get as status is the
 return code of /bin/sh (which didn't segfault).

 -Steve

All I know is the analogous code in python returns the expected 139

What OS are you running on? In D2, this the definition of system(): int system(string command) { if (!command) return std.c.process.system (null); const commandz = toStringz (command); invariant status = std.c.process.system (commandz); if (status == -1) return status; version (Posix) return (status & 0x0000ff00) >>> 8; else return status; } And "(139 & 0x0000ff00) >>> 8" evaluates to 0. I am not sure why it's not simply returning the raw status-code, though, and only on Posix systems -- it must be a Posix-ism I'm not familiar with. Graham
May 03 2010
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 04 May 2010 09:25:30 +1200, Bernard Helyer wrote:

 On 04/05/10 08:57, Lars T. Kyllingstad wrote:
 On Mon, 03 May 2010 15:54:28 -0500, Ellery Newcomer wrote:

 Hello.

 I'm trying to invoke a command inside d, and it returns a success code
 when the command in question segfaults.

 any ideas?

 [...]

It's a null dereference. [...]

I believe his problem is that the return code of the caller indicates success.

Note to self: Read posts *thoroughly* before answering. Man, I was feeling so pleased with myself for having spotted the error so quickly. ;) -Lars
May 03 2010
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Mon, 03 May 2010 20:32:03 -0500, Ellery Newcomer wrote:

 On 05/03/2010 06:08 PM, Graham Fawcett wrote:
 [...]

 And "(139&  0x0000ff00)>>>  8" evaluates to 0.  I am not sure why it's
 not simply returning the raw status-code, though, and only on Posix
 systems -- it must be a Posix-ism I'm not familiar with.

 Graham

I'm on fedora, and yeah, I guess it's a posixism. investigation yields lower 16 bits is coredump flag and signal code upper 16 bits is status code

That hardcoded bit shift in std.process is really ugly, and hides what is going on. Here's the correct way to analyse POSIX status codes: import core.sys.posix.sys.wait; ... if (WIFEXITED(status)) writeln("Process exited with code ", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) writeln("Process terminated by signal ", WTERMSIG(status)); In your case the segfault would cause SIGSEGV (signal 11) to be sent to the process, and the the above test would print "Process terminated by signal 11". See "man wait" for more info.
 I tell ya, working with D, ya learn something new every day [while
 implementing crap that the provided libraries should handle on their
 own...]

std.process is currently undergoing a complete redesign, so the current situation should improve in the near future. :) -Lars
May 03 2010
prev sibling next sibling parent Graham Fawcett <fawcett uwindsor.ca> writes:
On Tue, 04 May 2010 08:55:36 -0500, Ellery Newcomer wrote:

 On 05/04/2010 01:58 AM, Lars T. Kyllingstad wrote:
 
 
 In your case the segfault would cause SIGSEGV (signal 11) to be sent to
 the process, and the the above test would print "Process terminated by
 signal 11".

 See "man wait" for more info.

That's where I got my info (or rather /usr/include/bits/waitstatus.h)
 std.process is currently undergoing a complete redesign, so the current
 situation should improve in the near future. :)

 -Lars

That's good to hear. And since you're an expert in this stuff, does this my code look alright? import std.typecons; static import std.c.process; import std.functional; import std.stdio; import std.string; alias Tuple!(ubyte, "status",ubyte, "term", ubyte, "sig",bool,"signaled",bool, "stopped", bool,"continued",bool, "coredumped") PID; PID toPID(int p){ PID pid; pid.status = cast(byte)((p & 0xff00) >> 8); pid.term = cast(byte)(p & 0xff); pid.sig = cast(byte)(p & 0x7f); pid.signaled = pid.sig != 0 && pid.sig != 0x7f; pid.coredumped = cast(bool)(p & 0x80); pid.stopped = pid.term == 0x7f; pid.continued = p == 0xffff; return pid; } int fromPID(PID pid){ if(pid.signaled) return pid.term; return pid.status; } alias compose!(toPID, std.c.process.system, toStringz) system_p; alias compose!(fromPID, system_p) system;

Thanks for posting this. Just curious -- why did you choose to model PID as a tuple instead of a struct? I'm not clear on what the tradeoffs are. Best, Graham
May 04 2010
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 04 May 2010 08:55:36 -0500, Ellery Newcomer wrote:
 On 05/04/2010 01:58 AM, Lars T. Kyllingstad wrote:
 std.process is currently undergoing a complete redesign, so the current
 situation should improve in the near future. :)

 -Lars

That's good to hear. And since you're an expert in this stuff, does this my code look alright? import std.typecons; static import std.c.process; import std.functional; import std.stdio; import std.string; alias Tuple!(ubyte, "status",ubyte, "term", ubyte, "sig",bool,"signaled",bool, "stopped", bool,"continued",bool, "coredumped") PID; PID toPID(int p){ PID pid; pid.status = cast(byte)((p & 0xff00) >> 8); pid.term = cast(byte)(p & 0xff); pid.sig = cast(byte)(p & 0x7f); pid.signaled = pid.sig != 0 && pid.sig != 0x7f; pid.coredumped = cast(bool)(p & 0x80); pid.stopped = pid.term == 0x7f; pid.continued = p == 0xffff; return pid; }

Shouldn't 'term' and 'signaled' switch names? It looks to me like 'term' will be nonzero if the process receives any signal, while 'signaled' will be only be true if it is a terminating signal, and not if it is a stop signal. Otherwise it looks right, at least on Linux. But why not use the core.sys.posix.sys.wait.Wxxx() functions? Then it will automatically work on BSD and MacOS as well.
 int fromPID(PID pid){
      if(pid.signaled) return pid.term;
      return pid.status;
 }
 
 alias compose!(toPID, std.c.process.system, toStringz) system_p; alias
 compose!(fromPID, system_p) system;

I didn't know about compose, that's nifty. :) -Lars
May 04 2010
prev sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 04 May 2010 15:22:52 -0500, Ellery Newcomer wrote:

 On 05/04/2010 11:32 AM, Lars T. Kyllingstad wrote:
 Shouldn't 'term' and 'signaled' switch names?  It looks to me like
 'term' will be nonzero if the process receives any signal, while
 'signaled' will be only be true if it is a terminating signal, and not
 if it is a stop signal.

name. term has no justification for its name; I just want something that is the same as what bash returns on segfault. I don't know what it does on BSD, though.
 Otherwise it looks right, at least on Linux.  But why not use the
 core.sys.posix.sys.wait.Wxxx() functions?  Then it will automatically
 work on BSD and MacOS as well.

Easy, I didn't know about that module when I wrote this. alias Tuple!(int, "status",int, "signal", int, "termsig",bool, "signaled",bool, "stopped", bool,"continued") PID; PID toPID(int p){ PID pid; pid.status = WEXITSTATUS(p); pid.signal = (p & 0xff); pid.termsig = WTERMSIG(p); pid.signaled = WIFSIGNALED(p); pid.stopped = WIFSTOPPED(p); pid.continued = cast(bool) WIFCONTINUED(p); //why the eff is this defined as an int?

Don't know. Since all the other WIF* tests return bool, that looks like a bug.
      return pid;
 }
 
 Is the coredump flag a linux-only thing?

No, it exists in BSD and MacOS as well, but it's not a part of the POSIX specification. I assume that's why Sean didn't include it in the druntime headers. According to the man page it's not available on AIX and SunOS, and probably others. -Lars
May 05 2010