Hi there. Welcome to my channel.
Here we will solve Rach's dilemma.
Ready ?
You may jump to Tl;dr
Consider this program:
#include<stdio.h>
int main(){
int i;
scanf("%d", &i);
printf("%d", i);
return 0;
}
Compile and run with stdin: a
what does it print ?
Some garbage.
Why ?
----JARGON ----
Let's see the disassembly of the code (you may skip this jargon, it'll still make sense).
(you may skip to JARGON END
)
Compile and fire up gdb
(gdb) break main
Breakpoint 1 at 0x115d
Now run the program with 'r' and find the address of scanf call.
(gdb) r
Starting program: /home/hritik/Raw_Programs/a.out
Breakpoint 1, 0x000055555555515d in main ()
=> 0x000055555555515d <main+4>: 48 83 ec 10 sub rsp,0x10
(gdb) disassemble main
Dump of assembler code for function main:
0x0000555555555159 <+0>: push rbp
0x000055555555515a <+1>: mov rbp,rsp
=> 0x000055555555515d <+4>: sub rsp,0x10
0x0000555555555161 <+8>: mov rax,QWORD PTR fs:0x28
0x000055555555516a <+17>: mov QWORD PTR [rbp-0x8],rax
0x000055555555516e <+21>: xor eax,eax
0x0000555555555170 <+23>: lea rax,[rbp-0xc]
0x0000555555555174 <+27>: mov rsi,rax
0x0000555555555177 <+30>: lea rdi,[rip+0xe86] # 0x555555556004
0x000055555555517e <+37>: mov eax,0x0
0x0000555555555183 <+42>: call 0x555555555050 <__isoc99_scanf@plt>
0x0000555555555188 <+47>: mov eax,DWORD PTR [rbp-0xc]
0x000055555555518b <+50>: mov esi,eax
0x000055555555518d <+52>: lea rdi,[rip+0xe70] # 0x555555556004
0x0000555555555194 <+59>: mov eax,0x0
0x0000555555555199 <+64>: call 0x555555555040 <printf@plt>
0x000055555555519e <+69>: mov eax,0x0
0x00005555555551a3 <+74>: mov rdx,QWORD PTR [rbp-0x8]
0x00005555555551a7 <+78>: xor rdx,QWORD PTR fs:0x28
0x00005555555551b0 <+87>: je 0x5555555551b7 <main+94>
0x00005555555551b2 <+89>: call 0x555555555030 <__stack_chk_fail@plt>
0x00005555555551b7 <+94>: leave
0x00005555555551b8 <+95>: ret
End of assembler dump.
Set another breakpoint at scanf call.
(gdb) break *0x0000555555555183
Breakpoint 2 at 0x555555555183
and continue
(gdb) continue
Continuing.
Breakpoint 2, 0x0000555555555183 in main ()
=> 0x0000555555555183 <main+42>: e8 c8 fe ff ff call 0x555555555050 <__isoc99_scanf@plt>
(gdb)
Now, there's the time when scanf would be called. The parameters to scanf are stored in rdi, rsi etc
. (https://www.cs.uaf.edu/2015/fall/cs301/lecture/10_07_printf.html)
Let's verify
(gdb) x/s $rdi
0x555555556004: "%d"
Indeed. Our format string is there.
Now, $rsi contains the address of our variable in which we'd like to store our input.
Let's print that out.
(gdb) p/x $rsi
$1 = 0x7fffffffe5c4
Remember this address.
Proceed further and enter a number, say 99.
(gdb) ni
99
0x0000555555555188 in main ()
=> 0x0000555555555188 <main+47>: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc]
(gdb)
Now, if everything went fine, our number 99 should be at address $1
Let's see what's there.
(gdb) x/d $1
0x7fffffffe5c4: 99
Cool. It's there.
Now, repeat the above two steps with input as as character, say A
:
Starting program: /home/hritik/Raw_Programs/a.out
Breakpoint 4, 0x0000555555555183 in main ()
=> 0x0000555555555183 <main+42>: e8 c8 fe ff ff call 0x555555555050 <__isoc99_scanf@plt>
(gdb) p/x $rsi
$6 = 0x7fffffffe5c4
(gdb) ni
A
0x0000555555555188 in main ()
=> 0x0000555555555188 <main+47>: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc]
(gdb) x/d $6
0x7fffffffe5c4: -1
Wtf ? -1 ? Why ? Where's our character ?
Let's look around a few bytes.
(gdb) x/4d $6
0x7fffffffe5c4: -1 127 0 0
Still nothing that resembles the character.
So, scanf is the culprit!
Let's duckduckgo about what happens if we supply a character where an int is supposed to be present in scanf format string.
Soon, we'd stumble upon this answer:
https://stackoverflow.com/a/20655460/2251364
There you go. You were never reading anything valuable.
Also,
man 3 exit
shows in the beginning
The exit() function causes normal process termination and the least significant byte of
status (i.e., status & 0xFF) is returned to the parent (see wait(2)).
So, max size of status code is 1 byte. This'd explain the mostly zero exit codes in the parent question (not included here).
scanf fucks up when you provide char where int was supposed to be present.
Ref:
https://stackoverflow.com/a/20655460/2251364