Why is $? always 0 after system() is called? - c

I'm testing this tiny program under Linux:
// foo.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
int n = system(argv[1]);
printf("%d\n", n);
return n;
}
No matter what is fed into the command-line, an echo $? always prints 0, e.g.:
$ ./foo anything
sh: anything: not found
32512
$ echo $?
0
My question is: Why doesn't $? take the same value as n? I've also tested the program under Win32, and echo %errorlevel% gives the same value as n. Thanks!

If you print n in octal or hex, you'll discover that the low byte of it is always 0.
If you return WEXITSTATUS(n);, your program will exit with the status you are expecting.
Read man system and man wait carefully, and you'll understand.

Only lower 8 bits of the return value are recognized as the exit status, because the exit status is calculated by WEXITSTATUS macro, see SUSv4

Related

if we return non-zero value in main function, why doesn't it show any type of error

#include <stdio.h>
int main()
{
printf("hello world");
return 55;
}
I was reading an article that. The return value of main() function shows how the program exited. The normal exit of program is represented by zero return value. If the code has errors, fault etc., it will be terminated by non-zero value.
Since I am returning an non-zero value to main function. I assume that it must show errors(because I am not returning 0 to main function), but when i compliled and executed it.It didn't show any errors and it executed normally.Can you please explain it why? In advance thank you
Your assumption is wrong, the surrounding environment (the shell in Linux, command prompt in Windows, your IDE, or whatever you use to start the program) does not by default check the status so nothing happens.
If in Linux, you can do
$ ./myprog
$ echo $?
and you should see 55.
Update: In Windows, I just learned that you can use errorlevel:
$ .\myprog
$ echo %errorlevel%

Bash reopen tty on simple program

#include <stdio.h>
#include <stdlib.h>
int main()
{
char buf[512];
fgets(buf, 512, stdin);
system("/bin/sh");
}
Compile with cc main.c
I would like a one-line command that makes this program run ls without it waiting for user input.
# This does not work - it prints nothing
(echo ; echo ls) | ./a.out
# This does work if you type ls manually
(echo ; cat) | ./a.out
I'm wondering:
Why doesn't the first example work?
What command would make the program run ls, without changing the source?
My question is shell and OS-agnostic but I would like it to work at least on bash 4.
Edit:
While testing out the answers, I found out that this works.
(python -c "print ''" ; echo ls) | ./a.out
Using strace:
$ (python -c "print ''" ; echo ls) | strace ./a.out
...
read(0, "\n", 4096)
...
This also works:
(echo ; sleep 0.1; echo ls) | ./a.out
It seems like the buffering is ignored. Is this due to the race condition?
strace shows what's going on:
$ ( echo; echo ls; ) | strace ./foo
[...]
read(0, "\nls\n", 4096) = 4
[...]
clone(child_stack=NULL, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7ffdefc88b9c) = 9680
In other words, your program reads a whole 4096 byte buffer that includes both lines before it runs your shell. It's fine interactively, because by the time the read happens, there's only one line in the pipe buffer, so over-reading is not possible.
You instead need to stop reading after the first \n, and the only way to do that is to read byte by byte until you hit it. I don't know libc well enough to know if this kind of functionality is supported, but here it is with read directly:
#include <unistd.h>
#include <stdlib.h>
int main()
{
char buf[1];
while((read(0, buf, 1)) == 1 && buf[0] != '\n');
system("/bin/sh");
}

Read an integer from stdin (in C)

I want to write a C program that takes as input an integer, and outputs its square. Here is what I have tried.
However,
./a.out < 3 outputs 32768, and
./a.out < 4 also outputs 32768.
Where am I wrong? Thanks.
#include <stdio.h>
int main(){
int myInt;
scanf("%d", &myInt);
printf("%d\n",myInt*myInt);
}
It looks like what you're trying to do is
echo 4 | ./a.out
the syntax for < is
program < input_file
whereas | is
command_with_output | program
./a.out < 4
This tries to read the file named 4 and use it's content as input to a.out You can do it whichever way, but understand the < operator isn't for inputting the character you type quite literally.
One way to do this would be:
echo "4" > 4
./a.out < 4
I just run your program and its works great.
If you want the program receive an integer input you should use argc , argv as folowed and not use scanf.
*The code for argc argv: *
#include <stdio.h>
#include <stdlib.h>
int main(int argc , char** argv)
{
int myInt;
myInt = atoi(argv[1]);
printf("%d\n",myInt*myInt);
}
atoi - convert char* to integer.
If you want to run the program and then insert an integer, you did it right!
you can read about atoi
To run this program you should comile and run from terminal:
gcc a.c -o a
./a 3
and you will receive:
9
On the right hand side of "<", there should be a file containing the input.
try this thing:
$ echo "3" > foo
$ ./a.out < foo
Read this for more information (Specially section 5.1.2.2):
http://www.tldp.org/LDP/intro-linux/html/chap_05.html

No error message when using system() to execute program with buffer overflow vulnerability

Consider the following program (vul.c) with buffer overflow vulnerability.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[10];
strcpy(buf, argv[1]);
printf("%s\n", buf);
return 0;
}
Above program compiled using gcc -o vul vul.c and executed on arch linux - linux 4.4.16-1-lts x86-64 gave following output when executed in terminal with ./vul $(perl -e 'print "A"x100') command:
AAAAAAAAAAA...A
Segmentation fault (core dumped)
Then checking the program status using echo $? command gave 139 output.
Following program (exp.c) (for crashing the above program)
#include <stdlib.h>
int main(void)
{
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
return 0;
}
compiled using gcc -o exp exp.c when executed with ./exp command on same system gave following output:
AAAAAAAAAAAA...A
139
I have two questions:
Why no error message was generated by 2nd program? and,
I need to compile the program with -fstack-protector flag to enable the *** stack smashing detected *** error messages in arch linux but not in Ubuntu. In Ubuntu, it might be that this flag is include by default in gcc or is there any other reason?
As I pointed out in my comment,system returns an int with the programs's return value, which is normally it's error code (0 if successful).
If you want to print the error as a nice looking message, you can probably use strerror.
According to #rht's comment (see my next edit) and the answers to the question referenced in that comment, the returned value will be 0 on success and on error it will be error | 0x80. To get the original error code, use 128 - err_code.
try this:
#include <stdlib.h>
#include <errno.h>
int main(void)
{
int tmp = system("./vul $(perl -e 'print \"A\"x100)");
if(tmp < 0)
error("Couldn't run system command");
else if(tmp >0)
printf(stderr, "System command returned error: %s", strerror(128 - tmp));
else
; // nothing
return 0;
}
The fact that vul.c does (or does not) print an error message should be irrelevant for your exp.c program, since it depends on vul.c's compile flags values and any default compiler flags - things exp.c can't control.
EDIT(2) - in answer to the comment.
It could be that the error message returned isn't an errno value, but a signal trap value.
These are sometimes hard to differentiate and I have no good advice about how you can tell which one it is without using memcmp against the answer.
In this case you know vul.c will never return it's errno value, which leaves you only with signal trap errors, so you can use strsignal to print the error message.
As pointed out in #rht's comment, which references this question:
Passing tmp to strsignal generates the same error message: "unknown signal 139". The reason is that there is no signal with this signal number. /usr/include/bits/s‌​ignum.h contains all the signals with their signal numbers. Passing tmp-128 to strsignal works.
i.e.
#include <stdlib.h>
#include <string>
int main(void)
{
int tmp = system("./vul $(perl -e 'print \"A\"x100)");
if(tmp < 0)
error("Couldn't run system command");
else if(tmp >0)
printf(stderr, "System command returned error: %s", strsignal(tmp - 128));
else
; // nothing
return 0;
}
EDIT
The question was edited because it's code was mis-copied. I altered the answer to reflect that change.
From my comment to #Myst 's answer for "passing tmp-128 to strsignal()" function, after experimenting a little I found that it does not work in situations where the program exited normally but returned status other than 0.
Following are the contents of my /usr/include/bits/waitstatus.h:
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
/* If WIFSIGNALED(STATUS), the terminating signal. */
#define __WTERMSIG(status) ((status) & 0x7f)
/* Nonzero if STATUS indicates normal termination. */
#define __WIFEXITED(status) (__WTERMSIG(status) == 0)
/* Nonzero if STATUS indicates termination by a signal. */
#define __WIFSIGNALED(status) \
(((signed char) (((status) & 0x7f) + 1) >> 1) > 0)
Above code show that, exit status of a program is a 16bit number, the high order 8 bits of which are the status that the program returned and some/all of the remaining bits are set if the program exited because of a signal, 7 bits of which denote the signal that caused the program to exit. That's why subtracting 128 from the exit status returned by system() will not work in the situation as described above.
System()'s source code
Since system() function too uses fork() to create a new process and waits for the termination of the process, the same method of checking a child process's status in parent process can also be applied here. Following program demonstrates this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status = system("prg_name");
if (WIFEXITED(status))
printf("Exited Normally, status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("Killed by Signal %d which was %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
return 0;
}
Answering my own 2nd question.
gcc -Q -v vul.c command displayed the options passed to the gcc. The options in Ubuntu included -fstack-protector-strong flag but not in arch-linux. So in Ubuntu, the flag is passed by default to gcc.
There exists two problems in your vul.c and exp.c.
In vul.c,
char buf[10];
10 is not sufficient in this case, since the argv[1], i.e., $(perl -e 'print "A"x100', is larger than the buffer to be allocated. Enlarge the buf size should fix the segmentation fault.
In exp.c, you're missing one single quote, and should be modified as followed:
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));

Unix C - Portable WEXITSTATUS

I'm trying to get the exit code of a subprocess. On Linux and FreeBSD I can go like so:
[0] [ishpeck#kiyoshi /tmp]$ uname
FreeBSD
[0] [ishpeck#kiyoshi /tmp]$ cat tinker.c
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
FILE *proc = popen("ls", "r");
printf("Exit code: %d\n", WEXITSTATUS(pclose(proc)));
return 0;
}
[0] [ishpeck#kiyoshi /tmp]$ gcc tinker.c -o tinker
[0] [ishpeck#kiyoshi /tmp]$ ./tinker
Exit code: 0
[0] [ishpeck#kiyoshi /tmp]$ grep WEXITSTATUS /usr/include/sys/wait.h
#define WEXITSTATUS(x) (_W_INT(x) >> 8)
However, on OpenBSD, I get complaints from the compiler...
[0] [ishpeck#ishberk-00 /tmp]$ uname
OpenBSD
[0] [ishpeck#ishberk-00 /tmp]$ cat tinker.c
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
FILE *proc = popen("ls", "r");
printf("Exit code: %d\n", WEXITSTATUS(pclose(proc)));
return 0;
}
[0] [ishpeck#ishberk-00 /tmp]$ gcc tinker.c -o tinker
tinker.c: In function 'main':
tinker.c:7: error: lvalue required as unary '&' operand
[1] [ishpeck#ishberk-00 /tmp]$ grep WEXITSTATUS /usr/include/sys/wait.h
#define WEXITSTATUS(x) (int)(((unsigned)_W_INT(x) >> 8) & 0xff)
I don't really care how it's done, I just need the exit code.
This leads me to believe that I would also have this problem on Mac:
http://web.archiveorange.com/archive/v/8XiUWJBLMIKYSCRJnZK5#F4GgyRGRAgSCEG1
Is there a more portable way to use the WEXITSTATUS macro? Or is there a more portable alternative?
OpenBSD's implementation of WEXITSTATUS uses the address-of operator (unary &) on its argument, effectively requiring that its argument have storage. You are calling it with the return value of a function, which doesn't have storage, so the compiler complains.
It is unclear whether OpenBSD's WEXITSTATUS is POSIX-compliant, but the problem can be easily worked around by assigning the return value of pclose() to a variable:
int status = pclose(proc);
printf("Exit code: %d\n", WEXITSTATUS(status));
As a detail that could go unnoticed for some people arriving here, BSD object code needs the library:
#include <sys/wait.h>
I was too compiling to Linux and BSD, and WEXITSTATUS worked OK without the need for that library (I don't know why) when compiling to Linux (using gcc), but failed when compiling to BSD (using clang).
If your application died or was otherwise killed, the return status is bogus. You need to check the status to see if the exit value is even valid. See the man page for waitpid.
if(WIFEXITED(status))
{
use WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
use WTERMSIG(status);
} else {
oh oh
}

Resources