Skip to content

Instantly share code, notes, and snippets.

@Hritik14
Last active July 5, 2020 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hritik14/0d5da988634421e2d4a866d65be48c0f to your computer and use it in GitHub Desktop.
Save Hritik14/0d5da988634421e2d4a866d65be48c0f to your computer and use it in GitHub Desktop.

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).

Tl;Dr

scanf fucks up when you provide char where int was supposed to be present.
Ref:
https://stackoverflow.com/a/20655460/2251364

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment