banner

[Rule] Rules  [Home] Main Forum  [Portal] Portal  
[Members] Member Listing  [Statistics] Statistics  [Search] Search  [Reading Room] Reading Room 
[Register] Register  
[Login] Loginhttp  | https  ]
 
Forum Index Thảo luận hệ điều hành Windows gỡ rối giùm mình chương trình C  XML
  [Programming]   gỡ rối giùm mình chương trình C 19/02/2009 00:59:47 (+0700) | #1 | 169926
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Chào các bạn,

Mình có chương trình C đơn giản thế này mà không hiểu sao khi biên dịch bằng gcc-4.x rồi chạy thì nó cứ đứng khựng lại, không biết sai chỗ nào?

Code:
void weird_print(char *str)
{
        char buffer[100];
        int n=0;
        
        for (n=0; n<=100;n++)
                buffer[n]=str[n];        

        printf("%s\n", buffer);
}

int main(int argc, char *argv[])
{
        if (argc>1) weird_print(argv[1]);

        return 0;
}
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 01:01:53 (+0700) | #2 | 169927
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
Test case ra sao? "Đứng khựng lại" là sao? Không có gì output ra màn hình?
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 01:05:40 (+0700) | #3 | 169928
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@lamer: đúng rồi đó bạn. Thí dụ mình chạy thế này:

Code:
$ ./test `perl -e 'print "A" x 10'`


Lẽ ra nó phải xuất ra 10 chữ A, nhưng đằng này nó đứng luôn, không xuất gì ra màn hình. strace cũng không thấy gì hết, cứ đứng im.
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 01:47:11 (+0700) | #4 | 169939
[Avatar]
secmask
Elite Member

[Minus]    0    [Plus]
Joined: 29/10/2004 13:52:24
Messages: 553
Location: graveyard
Offline
[Profile] [PM] [WWW]
tớ test với gcc version 4.1.2 20071124 vẫn chạy bình thường

[secmask@secmask-home setup]$ ./wprint
[secmask@secmask-home setup]$ ./wprint `perl -e 'print "A" x 10'`
AAAAAAAAAA
 

[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 01:50:09 (+0700) | #5 | 169940
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@secmask: chạy thử lại nhiều lần xem sao? Xem có lần nào bị đứng im không?
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 02:05:05 (+0700) | #6 | 169941
[Avatar]
secmask
Elite Member

[Minus]    0    [Plus]
Joined: 29/10/2004 13:52:24
Messages: 553
Location: graveyard
Offline
[Profile] [PM] [WWW]

choc_ wrote:
@secmask: chạy thử lại nhiều lần xem sao? Xem có lần nào bị đứng im không? 

tớ lặp lại gần chục lần vẫn vậy smilie.
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 06:26:50 (+0700) | #7 | 169979
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@secmask: có thể gcc của mình nó tạo kết quả khác. Để thuận tiện, mình gửi binary lên đây cho các bạn xem thử: http://www.mediafire.com/?ytodbt4nhwl

Nhớ cẩn thận nha, mình ít bao giờ chạy binary lạ mà không xem xét trước lắm.
[Up] [Print Copy]
  [Question]   gỡ rối giùm mình chương trình C 19/02/2009 07:09:10 (+0700) | #8 | 169980
[Avatar]
secmask
Elite Member

[Minus]    0    [Plus]
Joined: 29/10/2004 13:52:24
Messages: 553
Location: graveyard
Offline
[Profile] [PM] [WWW]

choc_ wrote:
Chào các bạn,

Mình có chương trình C đơn giản thế này mà không hiểu sao khi biên dịch bằng gcc-4.x rồi chạy thì nó cứ đứng khựng lại, không biết sai chỗ nào?

Code:
void weird_print(char *str)
{
        char buffer[100];
        int n=0;
        
        for (n=0; n<=100;n++)
                buffer[n]=str[n];        

        printf("%s\n", buffer);
}

int main(int argc, char *argv[])
{
        if (argc>1) weird_print(argv[1]);

        return 0;
}
 

thử bỏ dấu "=" ở chỗ này " for (n=0; n<=100;n++)" đi coi, chắc nó overwrite lên "n" mất rồi.
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 09:38:23 (+0700) | #9 | 169992
mfeng
Researcher

Joined: 29/10/2004 15:16:29
Messages: 243
Offline
[Profile] [PM]
Tớ dịch trên CentOS, gcc-4.x thì đúng có hiện tượng trên, chương trình bị lặp không thoát được.

Disassemble bằng gdb thấy có đoạn này:
Code:
mov	0xfffffffc(%ebp),%eax                ;lấy giá trị n từ bộ nhớ ra thanh ghi eax.
....                                                    ; thực hiện đọc 1 byte từ str & copy sang buffer.
addl	$0x1, 0xfffffffc(%ebp)                ; tăng giá trị nằm trong vùng nhớ n lên 1 & so sánh
cmp	$0x64, 0xfffffffc(%ebp)
jle	...

Stack của hàm weird_print ở đây nó thế này:
buffer[0-100]: từ [ebp-0x68] đến [ebp-0x05];
n: bắt đầu từ [ebp-0x04].

Khi ghi vào byte thứ 100 (ebp-0x04), vùng nhớ này trùng với địa chỉ của n nên giá trị n bị ghi đè.

Tuy nhiên, điều lý thú lại như thế này, tớ viết thêm 2 dòng code in địa chỉ của n & buffer[100]:
Code:
void weird_print(char *str)
 {
         char buffer[100];
         int n=0;
         printf("Address of n:%p\n",&n);
         printf("Address of buffer[100]:%p\n",&buffer[100]);
         for (n=0; n<=100;n++)
                 buffer[n]=str[n];        
 
         printf("%s\n", buffer);
 }


Thì đoạn code kiểm tra điều kiện <=100 nó lại như sau:
Code:
mov  0xffffff98(%ebp), eax
....
[color=red]add 	$0x1, %eax
mov 	%eax, 0xffffff98(%ebp)
mov 	0xffffff98(%ebp), %eax[/color]
cmp	$0x64, %eax
jle	....

Stack map có thứ tự như sau:
n: [ebp-68];
buffer[0-100]: [ebp-64]

Vì thứ tự biến bị thay đổi trên stack, n đứng dưới buffer nên n không thể bị ghi đè. Nếu giả sử stack vẫn như cũ thì cũng không bị ghi đè bới hai dòng code màu đỏ ở trên. Vì thế chương trình không bị loop nữa smilie.
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/02/2009 11:59:37 (+0700) | #10 | 170011
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
Bug, thông báo cho GCC đi mọi người.
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 20/02/2009 02:46:20 (+0700) | #11 | 170107
TQN
Elite Member

[Minus]    0    [Plus]
Joined: 29/06/2006 22:28:01
Messages: 888
Location: Biết làm chi ?
Offline
[Profile] [PM] [WWW] [Yahoo!]
Bug à, thằng compiler muốn sinh mã ra sao thì tùy nó chứ, đứng trước đứng sau trong stack có quan trong đâu hè ?
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 20/02/2009 09:34:30 (+0700) | #12 | 170166
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
À, cái này thì không đồng ý.

1. Để tránh lỗi BO thì các trình dịch hiện đại sẽ đặt các biến đơn ở trước các bộ đệm. Khi bộ đệm bị trà thì giá trị các biến đơn có thể vẫn được giữ nguyên.

2. Việc đặt trước hay sau cũng phải thống nhất. Lẽ nào chỉ vì hai dòng lệnh không liên quan đến việc khai báo và khởi tạo biến lại làm thay đổi vị trí của hai biến này?
[Up] [Print Copy]
  [Question]   Re: gỡ rối giùm mình chương trình C 19/03/2009 06:22:15 (+0700) | #13 | 173706
TQN
Elite Member

[Minus]    0    [Plus]
Joined: 29/06/2006 22:28:01
Messages: 888
Location: Biết làm chi ?
Offline
[Profile] [PM] [WWW] [Yahoo!]
Cái này cũng không phải là lỗi. Thử xóa dòng
Code:
printf("Address of buffer[100]:%p\n",&buffer[100]);

đi và compile lại thử xem.
Trên gcc thì tui không biết, nhưng với VC++ 200x trở đi, compiler có thể detect các risk nguy hiểm trong hàm và tự hoán đổi vị trí của biến trong stack.
Trong trường hợp này ta thấy có hai risk: printf và truy xuất &buffer.

[Up] [Print Copy]
[digg] [delicious] [google] [yahoo] [technorati] [reddit] [stumbleupon]
Go to: 
 Users currently in here 
1 Anonymous

Powered by JForum - Extended by HVAOnline
 hvaonline.net  |  hvaforum.net  |  hvazone.net  |  hvanews.net  |  vnhacker.org
1999 - 2013 © v2012|0504|218|