• Welcome to Valhalla Legends Archive.
 

C Question

Started by FrOzeN, May 29, 2006, 05:21 PM

Previous topic - Next topic

FrOzeN

With the following code:
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
    char strTemp[11];

    sGetMessage(strTemp);
    printf("%s\n", strTemp);

    system("PAUSE");
    return 0;
}

sGetMessage(char* Message) {
    strcpy(Message, "Hello World!");
}


Should the sGetMessage function have a data type scope?

Eg,
int sGetMessage(char* Message) {
    strcpy(Message, "Hello World!");
    return 0;
}
~ FrOzeN

Rule

#1
Well, ISO C "forbids a definition without a datatype or storage class."

So, yes, you should definitely declare a return type for sGetMessage, even if it's void.  If you're compiling with gcc, it's good to use the flags "-ansi -Wall -pedantic" to check for such things.  Also, since you're using system, you should include stdlib.h. 

It seems strange that char strTemp[11] works to hold "Hello World!".... Doesn't it make sense that you should need a character array of size [13], to hold the
characters in "Hello World!" as well as the null terminating character?  I tried playing around with the size of strTemp; I don't get a segmentation fault (when copying "Hello World! into strTemp) unless strTemp is less than 3 in size. Why is this?!

Edit: if I declare char strTemp[0], the program still prints "Hello World!"
If I declare char strTemp[1], the program prints "Hello World!" and gives me a segmentation fault.

How can this be explained?



FrOzeN

I didn't pay much attention to the character array. I originally just typed strTemp[11] thinking it would work like:

QuotestrTemp[0] ="H"
strTemp[1] ="e"
strTemp[2] ="l"
strTemp[3] ="l"
strTemp[4] ="o"
strTemp[5] =" " // (Space)
strTemp[6] ="W"
strTemp[7] ="o"
strTemp[8] ="r"
strTemp[9] ="l"
strTemp[10] ="d"
strTemp[11] ="!"

Though, now that I think of it. Declaring [11] would make [10] the highest as it starts for zero. Wasn't really thinking about it at the time because it worked when I compiled it. (I have no idea why it works either, maybe strcpy resizes the array?)

I'm using Dev-Cpp and in the IDE I just click the "Compile and Run" option on the toolbar, so I'm not exactly sure which compiler it's using (I think it's MingW/GCC).
~ FrOzeN

Rule

Quote from: FrOzeN on May 29, 2006, 07:23 PM
I didn't pay much attention to the character array. I originally just typed strTemp[11] thinking it would work like:

QuotestrTemp[0] ="H"
strTemp[1] ="e"
strTemp[2] ="l"
strTemp[3] ="l"
strTemp[4] ="o"
strTemp[5] =" " // (Space)
strTemp[6] ="W"
strTemp[7] ="o"
strTemp[8] ="r"
strTemp[9] ="l"
strTemp[10] ="d"
strTemp[11] ="!"

Though, now that I think of it. Declaring [11] would make [10] the highest as it starts for zero. Wasn't really thinking about it at the time because it worked when I compiled it.
You'd need 12 places for the characters, and 1 space for the null terminating character, '\0'.
Try:
printf("%d\n", sizeof("Hello World!"));

Quote from: FrOzeN on May 29, 2006, 07:23 PM
(I have no idea why it works either, maybe strcpy resizes the array?)
Nope, I checked this...

Quote from: FrOzeN on May 29, 2006, 07:23 PM
I'm using Dev-Cpp and in the IDE I just click the "Compile and Run" option on the toolbar, so I'm not exactly sure which compiler it's using (I think it's MingW/GCC).
In that case you can probably turn on some helpful compiling/debugging options that will provide you with warnings in certain situations.

Kp

The compiler is placing the array on the stack in such a way that there's some slack space between the last cell you requested ([10]), and the last cell which can be overwritten without destroying something important.  When you make strTemp small enough, the padding is no longer sufficient and writing into the array smashes the return address.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Rule

#5
Quote from: Kp on May 29, 2006, 09:19 PM
The compiler is placing the array on the stack in such a way that there's some slack space between the last cell you requested ([10]), and the last cell which can be overwritten without destroying something important.  When you make strTemp small enough, the padding is no longer sufficient and writing into the array smashes the return address.

Makes sense, although why would strTemp[0] not cause a segmentation fault (and work fine), yet strTemp[a] (where 0<a<4) does (but still works properly)?
I imagine the memory that had those last characters stored in it previously (e.g. in the padding space) is still being called, and that is why both work.  Although it's puzzling why strTemp[0] would not cause a segmentation fault and strTemp[1] would.

 



Kp

That is best answered by examining the code generated by the compiler.  Run gcc -S str.c and post the results.  The output of gcc -v may also be enlightening.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Rule

#7
Diffs of .s files at end of post.

frq1.c:

#include <stdio.h>
#include <string.h>

void sGetMessage(char* Message);

int main(int argc, char* argv[]) {
    char asdf[1];

    sGetMessage(asdf);
    printf("%s\n", asdf);
   
    return 0;
}

void sGetMessage(char* Message) {
    strcpy(Message, "Hello World!");
}


Output:
Quote
Hello World!
Segmentation fault

frq1.s:

.file "frq1.c"
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
leal -1(%ebp), %eax
pushl %eax
call sGetMessage
addl $16, %esp
subl $8, %esp
leal -1(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.LC1:
.string "Hello World!"
.text
.globl sGetMessage
.type sGetMessage, @function
sGetMessage:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $8, %esp
pushl $.LC1
pushl 8(%ebp)
call strcpy
addl $16, %esp
leave
ret
.size sGetMessage, .-sGetMessage
.section .note.GNU-stack,"",@progbits


Modified frq.c so that strTemp is declared to be size 0.  (char strTemp[0])

Output:
Quote
Hello World!

New frq.s:

.file "frq.c"
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
leal -24(%ebp), %eax
pushl %eax
call sGetMessage
addl $16, %esp
subl $8, %esp
leal -24(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.LC1:
.string "Hello World!"
.text
.globl sGetMessage
.type sGetMessage, @function
sGetMessage:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $8, %esp
pushl $.LC1
pushl 8(%ebp)
call strcpy
addl $16, %esp
leave
ret
.size sGetMessage, .-sGetMessage
.section .note.GNU-stack,"",@progbits


frq100.s       (changed strTemp to size 100):

.file "frq100.c"
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $120, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
leal -120(%ebp), %eax
pushl %eax
call sGetMessage
addl $16, %esp
subl $8, %esp
leal -120(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.LC1:
.string "Hello World!"
.text
.globl sGetMessage
.type sGetMessage, @function
sGetMessage:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $8, %esp
pushl $.LC1
pushl 8(%ebp)
call strcpy
addl $16, %esp
leave
ret
.size sGetMessage, .-sGetMessage
.section .note.GNU-stack,"",@progbits


Differences between frq.s and frq1.s

diff frq.s frq1.s
1c1
<       .file   "frq.c"
---
>       .file   "frq1.c"
11c11
<       subl    $24, %esp
---
>       subl    $8, %esp
20c20
<       leal    -24(%ebp), %eax
---
>       leal    -1(%ebp), %eax
25c25
<       leal    -24(%ebp), %eax
---
>       leal    -1(%ebp), %eax


Differences between frq1.s and frq100.s:

diff frq1.s frq100.s
1c1
<       .file   "frq1.c"
---
>       .file   "frq100.c"
11c11
<       subl    $8, %esp
---
>       subl    $120, %esp
20c20
<       leal    -1(%ebp), %eax
---
>       leal    -120(%ebp), %eax
25c25
<       leal    -1(%ebp), %eax
---
>       leal    -120(%ebp), %eax



It looks as though strTemp[0] has an effective size  of "24" (bytes?) , while strTemp[1] has 8?     Why leal -1(%ebp), %eax for strTemp[1] though, and leal -24... for strTemp[0],
-120 for strTemp[100]?

Note: only differences between frq1.s and frq2.s (strTemp size 2),

diff frq2.s frq1.s
1c1
<       .file   "frq2.c"
---
>       .file   "frq1.c"
20c20
<       leal    -2(%ebp), %eax
---
>       leal    -1(%ebp), %eax
25c25
<       leal    -2(%ebp), %eax
---
>       leal    -1(%ebp), %eax


e.g. no subl difference