bugfix> c > 投稿

私は使用しています gdb を使用して変数の変更を監視するスクリプト awatch

#!/bin/bash
# Compile
gcc -Wall -pedantic -g -o demo demo.c
# Exit on compile error
if [ $? -ne 0 ]; then
    exit
fi
# Overwrite the contents of trace.gdb with a title
echo "# Watch var" > trace.gdb
# Don't stop each time there is a pagination
echo "set pagination off" >> trace.gdb
# Set a breakpoint in order to read the var address
echo "break main" >> trace.gdb
# Run the debugger
echo "run" >> trace.gdb
# Set watchpoint
echo "awatch var" >> trace.gdb
# Don't stop on each watchpoint (just show the trace)
echo "commands" >> trace.gdb
echo "continue" >> trace.gdb
echo "end" >> trace.gdb
# Start monitoring
echo "continue" >> trace.gdb
# Exit the debugger
echo "quit" >> trace.gdb
# Run the generated script
gdb -quiet -command=trace.gdb demo

プログラム:

/* demo.c */
#include <stdio.h>
int main(void)
{
    int var = 0;
    for (int i = 0; i < 5; i++)
    {
        var++;
    }
    printf("%d\n", var);
    return 0;
}

ouptutは正しいようです:

Hardware access (read/write) watchpoint 2: var
Value = 0
main () at demo.c:7
7       for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 0
New value = 1
main () at demo.c:7
7       for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 1
New value = 2
main () at demo.c:7
7       for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 2
New value = 3
main () at demo.c:7
7       for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 3
New value = 4
main () at demo.c:7
7       for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 4
New value = 5
main () at demo.c:7
7       for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Value = 5
0x0000555555555176 in main () at demo.c:11
11      printf("%d\n", var);
5

しかし、私がこのコードに切り替えると rand()

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
    int var = 0;
    srand((unsigned)time(NULL));
    for (int i = 0; i < 10; i++)
    {
        var = rand() % 10;
    }
    printf("%d\n", var);
    return 0;
}

同じスクリプトを実行し、 gdb 間違った値の印刷を開始します:

Breakpoint 1, main () at demo.c:6
6   {
Hardware access (read/write) watchpoint 2: var
Hardware access (read/write) watchpoint 2: var
Value = 0
main () at demo.c:9
9       srand((unsigned)time(NULL));
Hardware access (read/write) watchpoint 2: var
Old value = 0
New value = 32015002
0x00005555555551f8 in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Value = 32015002
0x00005555555551fb in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Old value = 32015002
New value = 7
main () at demo.c:10
10      for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 7
New value = 84992124
0x00005555555551f8 in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Value = 84992124
0x00005555555551fb in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Old value = 84992124
New value = 6
main () at demo.c:10
10      for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 6
New value = 55442740
0x00005555555551f8 in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Value = 55442740
0x00005555555551fb in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Old value = 55442740
New value = 0
main () at demo.c:10
10      for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 0
New value = 208731384
0x00005555555551f8 in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Value = 208731384
0x00005555555551fb in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Old value = 208731384
New value = 3
main () at demo.c:10
10      for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Old value = 3
New value = 114916873
0x00005555555551f8 in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Value = 114916873
0x00005555555551fb in main () at demo.c:12
12          var = rand() % 10;
Hardware access (read/write) watchpoint 2: var
Old value = 114916873
New value = 9
main () at demo.c:10
10      for (int i = 0; i < 5; i++)
Hardware access (read/write) watchpoint 2: var
Value = 9
0x0000555555555216 in main () at demo.c:14
14      printf("%d\n", var);
9

私はこの投稿を読みました:引数を変更すると、gdbが間違った値を出力します とコンパイル -fvar-tracking しかし、それは役に立ちません。

なぜこの振る舞いは rand()

回答 1 件
  • 最適化されていないgccアセンブリは奇妙な場合があります。

           jmp     .L2
    .L3:
            call    rand
            movl    %eax, %edx
            movslq  %edx, %rax
            imulq   $1717986919, %rax, %rax
            shrq    $32, %rax
            sarl    $2, %eax
            movl    %edx, %ecx
            sarl    $31, %ecx
            subl    %ecx, %eax
            movl    %eax, -4(%rbp)
            movl    -4(%rbp), %ecx
            movl    %ecx, %eax
            sall    $2, %eax
            addl    %ecx, %eax
            addl    %eax, %eax
            subl    %eax, %edx
            movl    %edx, -4(%rbp)
            addl    $1, -8(%rbp)
    .L2:
            cmpl    $9, -8(%rbp)
            jle     .L3
    
    

    そして、あなたはワーチングしているようです -4(%rbp) 。だからあります movl %eax, -4(%rbp) ここに「大きな数」が置かれ、次に読み込まれます movl -4(%rbp), %ecx その後 movl %edx, -4(%rbp) ここでの結果 % 10 そこに置かれます。したがって、計算の途中からいくつかの数値が表示されます。つまり、 1つのループは以下に対応します:

    New value = 32015002
    0x00005555555551f8 in main () at demo.c:12
    12          var = rand() % 10;
    Hardware access (read/write) watchpoint 2: var
    Value = 32015002
    0x00005555555551fb in main () at demo.c:12
    12          var = rand() % 10;
    Hardware access (read/write) watchpoint 2: var
    Old value = 32015002
    New value = 7
    main () at demo.c:10
    10      for (int i = 0; i < 5; i++)
    Hardware access (read/write) watchpoint 2: var
    
    

あなたの答え