share a bug:when you return a structure in C functions
Posted: Sun Apr 13, 2014 1:40 am
this is my first attempt to return a structure in C functions, and was confronted by strange problems.To be brief:the way gcc implements 'structure return' is a little hack. for example, if you write 'struct typenumber tn = parse_type(parser);', gcc will pass a ponter to 'tn'(the l-value) as the first argument when calling parse_type, although it's transparent to programmers, the 'parser' turned into the second argument anyhow.
when we disassemble the following code:
struct typenumber parse_type(strparser_t *parser){
parser->....
}
we will find within function body, the argument 'parser' is accessed using 'mov 0xc(%ebp),%eax', obviously gcc treats it as the second argument:
>>>>>>>>stack grow>>>>>>>>>>>>>>>>>>>>>
|parser| xxx | eip | ebp | ...
>>>>>>>>stack grow>>>>>>>>>>>>>>>>>>>>>
(xxx is a transparent pointer)
but this stack frame layout just came from gcc's view, because he saw the function returned 'struct typenumber' and he had promised himself every time he called a structure-returned function he would pass an additional pointer. only when he fulfiled the promise would the real layout be consistent with how he treated it. but sometimes he was not aware of being calling a structure-returned function.for example, we wrote in another source file:
parse_type(parser);
we compiled it without the protocol declaration of parse_type, so gcc regarded it as a impicit declaration which returned 'int'. now the tragedy happened, gcc only performed a common call:
lea `parser's address`, %eax
mov %eax, (%esp)
call parse_type
this caused a segment fault in my project.
I hope this article may help you.
when we disassemble the following code:
struct typenumber parse_type(strparser_t *parser){
parser->....
}
we will find within function body, the argument 'parser' is accessed using 'mov 0xc(%ebp),%eax', obviously gcc treats it as the second argument:
>>>>>>>>stack grow>>>>>>>>>>>>>>>>>>>>>
|parser| xxx | eip | ebp | ...
>>>>>>>>stack grow>>>>>>>>>>>>>>>>>>>>>
(xxx is a transparent pointer)
but this stack frame layout just came from gcc's view, because he saw the function returned 'struct typenumber' and he had promised himself every time he called a structure-returned function he would pass an additional pointer. only when he fulfiled the promise would the real layout be consistent with how he treated it. but sometimes he was not aware of being calling a structure-returned function.for example, we wrote in another source file:
parse_type(parser);
we compiled it without the protocol declaration of parse_type, so gcc regarded it as a impicit declaration which returned 'int'. now the tragedy happened, gcc only performed a common call:
lea `parser's address`, %eax
mov %eax, (%esp)
call parse_type
this caused a segment fault in my project.
I hope this article may help you.