Cannot get stderr of the execution of a compiled C program with the system command in perl

Viewed 120

I have written a nice little perl script that is very useful to me. It allows me to compile and execute C instructions as if it were instructions of an interpreted language. It is the C programming IDE of sorts that I'm using to learn the C language.

Here's how I use it :

crepl -Istdio 'char * str="text"; printf("%s\n", str);'
OUTPUT
text

crepl -Istdio,string 'char * str="text"; int i; for(i=0; i < strlen(str);i++){printf("%c", str[i]);} printf("\n");'
OUTPUT
text

crepl -Istdio 'char * str="text"; int i=0; while(str[i] != '\''\0'\''){printf("%c", str[i]); i++;} printf("\n");'
OUTPUT
text

and here's the script :

#!/usr/bin/perl

# this script requires this line in /etc/fstab :
#tmpfs   /tmp/ram/   tmpfs    defaults,noatime,nosuid,nodev,mode=1777,size=32M 0 0

use strict;
use warnings;
use autodie;

my @include;
$,="\n";
$\="\n";

if (not @ARGV) { exit }
elsif ($ARGV[0] =~ m/^-I/) {
    $ARGV[0] =~ s/^-I//;
    @include = split /,/, $ARGV[0];
    shift;
}

#my $source_code   = "/tmp/ram/c_program.c";    # requires adding a line in /etc/fstab
#my $compiled_code = "/tmp/ram/c_program.o";    # requires adding a line in /etc/fstab
my $source_code   = "./.c_program.c";
my $compiled_code = "./.c_program.o";

open my $FH, ">", $source_code;
foreach (@include){
    print $FH "#include <$_.h>";
}
print $FH "int main(int argc, char *argv[]) {";
print $FH $ARGV[0];
print $FH "return 0;";
print $FH "}";
close $FH;

system "gcc", $source_code, "-o", $compiled_code;
system $compiled_code;

The problem I have is that I don't get the error message that happens at run time. (While I do get error messages of compilation.)

If I do something like this:

crepl -Istdio 'char * str="text"; char * copy; int i=0; while(str[i] != '\''\0'\''){copy[i]=str[i]; i++;} printf("%s\n", copy);'

I get no output. But I should really obtain this:

Segmentation fault (core dumped)

because I forgot malloc. The right way to copy a string is this way:

crepl -Istdio,string,stdlib 'char * str="text"; char * copy=malloc(strlen(str)); int i=0; while(str[i] != '\''\0'\''){copy[i]=str[i]; i++;} printf("%s\n", copy);'

This is annoying. I will have trouble learning C if I don't get messages like Segmentation Fault.

I have tried replacing

system $compiled_code;

by

system "$compiled_code 2>&1";

or

print `$compiled_code 2>&1`;

but neither works.

Do you know how I could modify my script to get these error messages ?

Thanks.

1 Answers

The Segmentation fault (core dumped) message you sometimes see in the terminal is not produced by the process you launch but by the shell that launched this process.

When it launches a process, the shell waits for it with a system call similar to man 3 waitpid. Such a system-call tells if the process exited successfully (with return or _exit()) or was killed by a signal. In this last case, the shell displays a message specific to the signal that caused the early termination (man 3 strsignal).

In your specific case, this is not the shell that launches the process you wrote in C, but the perl interpreter. Your process being killed does not make perl be killed too, so your shell does not display such a message.

I cannot write perl but I'm certain that you can replace system $compiled_code; by something that does the equivalent of fork()/exec()/waitpid()/strsignal().

Using the end of this page, I think you can try this at the end of your script.

system $compiled_code;
my $status = $?;
if ($status == -1) {
    print "failed to execute: $!\n";
}
elsif ($status & 127) {
    printf "child died with signal %d, %s coredump\n",
        ($status & 127), ($status & 128) ? 'with' : 'without';
}
else {
    printf "child exited with value %d\n", $status >> 8;
}
Related