We programmers are bound to make silly mistakes and tend to write absurd code :-). If these things are spotted during code reviews or internal testing, then you are spared. If the buggy stuffs land in customer's runway, then we are in trouble :-). Today's blog is to closely examine gcc behavior's to such absurd code. This example is not exhaustive. I will try to come up with few more examples in future to learn myself and share observations. As of now, here is sample code.
#include<stdio.h>
int test(unsigned int k)
{
if (k < 0)
printf("BUG IN COMPILER: THIS IS ABSURD BLOCK\n");
}
int main()
{
unsigned int k = 9;
test(k);
return 0;
}
As a programmer you know the absurdity of the code. So how does gcc behave. We can only say by looking into assembly output emitted by gcc. Here is the assembly dump of the program (with default optimization).
<snip>
test:
.LFB0:
.cfi_startproc
pushq %rbp /* Save return pointer */
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp /* New base pointer */
.cfi_def_cfa_register 6
movl %edi, -4(%rbp) /* Copy Argument */
popq %rbp /* Restore base pointer */
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size test, .-test
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $9, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %edi
call test /* Here is call to function */
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
<snip>
As you can see, the entire 'if' block is discarded by gcc :-D. Compilers are smart nowadays ;-). They know how to get rid of weeds and make ELF fertile :-). Even though we inject irrelevant code, compilers (atleast gcc) get rid of them in final binary. Let me see what more weird stuff can be experimented with. Hope you enjoyed this small and simple post. Critiques and comments are always welcome!
#include<stdio.h>
int test(unsigned int k)
{
if (k < 0)
printf("BUG IN COMPILER: THIS IS ABSURD BLOCK\n");
}
int main()
{
unsigned int k = 9;
test(k);
return 0;
}
As a programmer you know the absurdity of the code. So how does gcc behave. We can only say by looking into assembly output emitted by gcc. Here is the assembly dump of the program (with default optimization).
<snip>
test:
.LFB0:
.cfi_startproc
pushq %rbp /* Save return pointer */
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp /* New base pointer */
.cfi_def_cfa_register 6
movl %edi, -4(%rbp) /* Copy Argument */
popq %rbp /* Restore base pointer */
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size test, .-test
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $9, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %edi
call test /* Here is call to function */
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
<snip>
As you can see, the entire 'if' block is discarded by gcc :-D. Compilers are smart nowadays ;-). They know how to get rid of weeds and make ELF fertile :-). Even though we inject irrelevant code, compilers (atleast gcc) get rid of them in final binary. Let me see what more weird stuff can be experimented with. Hope you enjoyed this small and simple post. Critiques and comments are always welcome!
No comments:
Post a Comment