3

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.

WhiteMist
  • 885
  • 4
  • 13
  • What happens if you don't use `autodie` ? See also [How to get Capture::Tiny to print stderr and stdout upon failure?](https://stackoverflow.com/q/66016077/2173773) – Håkon Hægland Feb 03 '21 at 21:00
  • If you mean does it solve the problem, then no it doesn't. But it you mean what is is useful for, it is used to exit the program with an error message if there is an error with a filehandle – WhiteMist Feb 03 '21 at 21:08
  • I am sorry, but even if this modue works, I probably won't use it because it would slow down the script a bit because the module have to be loaded. And it is annoying. I want to keep my script moderately fast – WhiteMist Feb 03 '21 at 21:10
  • I just saw that my question is kind of a duplicate, and that the solution of prog-fh was there also https://stackoverflow.com/questions/18332846/in-perl-how-do-we-detect-a-segmentation-fault-in-an-external-command – WhiteMist Feb 03 '21 at 21:45
  • "_...I probably won't use it because it would slow down the script a bit..._" -- that's misguided. While any library slows things down a bit I don't see how you're going to notice those <100-200ms of start up (or some such), while you're missing on all the support that good libraries provide. – zdim Feb 03 '21 at 22:10

1 Answers1

5

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;
}
prog-fh
  • 13,492
  • 1
  • 15
  • 30
  • Thank you I had no idea that the Segmentation Fault error was send by the shell. I copy pasted like you the code from the documentation of the system function and it solved my problem I guess. I will just remember that 11 stands for segmentation fault. I juste removed the else part of the code because it is just noise – WhiteMist Feb 03 '21 at 21:37
  • @WhiteMist Also note that there are good libraries in Perl for running and managing external programs, that can quite "_replace `system ...`_" as the post nicely says. From simpler to more capable, for example, [IPC::System::Simple](https://metacpan.org/pod/IPC::System::Simple), [Capture::Tiny](https://metacpan.org/pod/Capture::Tiny), [IPC::Run3](https://metacpan.org/pod/IPC::Run3), [IPC::Run](https://metacpan.org/pod/IPC::Run) – zdim Feb 03 '21 at 22:05
  • Yes, sorry I still have to learn how stackoverflow works. This is a good idea the thing you propose by replacing system by fork, exec, waitpid and strsignal. I already have perl scripts that do fork exec, I have to had the last 2. I can not do it right know because I do not know yet how to do programs with system calls. This is one of the reasons I want to learn C in the first place.. – WhiteMist Feb 03 '21 at 22:06