我的任务是在以下代码中找到错误并修复它:
/* $Id: count-words.c 858 2010-02-21 10:26:22Z tolpin $ */
#include <stdio.h>
#include <string.h>
/* return string "word" if the count is 1 or "words" otherwise */
char *words(int count) {
char *words = "words";
if(count==1)
words[strlen(words)-1] = '\0';
return words;
}
/* print a message reportint the number of words */
int print_word_count(char **argv) {
int count = 0;
char **a = argv;
while(*(a++))
++count;
printf("The sentence contains %d %s.\n", count, words(count));
return count;
}
/* print the number of words in the command line and return the number as the exit code */
int main(int argc, char **argv) {
return print_word_count(argv+1);
}
除了一个单词外,该程序适用于提供给它的每个单词。使用./count-words hey
运行它会导致分段错误。
我正在使用官方的Ubuntu应用程序在Windows 10上的Linux子系统上运行我的代码(这就是我所知道的至少被称为...)。
从终端运行程序时,我确实得到了分段错误,但是使用gdb,出于某种原因,程序运行正常:
(gdb) r hey
Starting program: .../Task 0/count-words hey
The sentence contains 1 word.
[Inferior 1 (process 87) exited with code 01]
(gdb)
在第9行添加断点并单步执行代码后,我得到了这个:
(gdb) b 9
Breakpoint 1 at 0x400579: file count-words.c, line 9.
(gdb) r hey
Starting program: /mnt/c/Users/tfrei/Google Drive/BGU/Semester F/Computer Architecture/Labs/Lab 2/Task 0/count-words hey
Breakpoint 1, words (count=1) at count-words.c:9
9 if(count==1)
(gdb) s
10 words[strlen(words)-1] = '\0';
(gdb) s
strlen () at ../sysdeps/x86_64/strlen.S:66
66 ../sysdeps/x86_64/strlen.S: No such file or directory.
(gdb) s
67 in ../sysdeps/x86_64/strlen.S
(gdb) s
68 in ../sysdeps/x86_64/strlen.S
(gdb)
奇怪的是,当我从“真正的”Ubuntu(在Windows 10上使用虚拟机)运行相同的东西时,分段错误确实发生在gdb上。
我倾向于认为其原因在某种程度上与我的运行时环境(“Windows上的Ubuntu”)相关,但找不到任何可以帮助我的东西。
这是我的makefile:
all:
gcc -g -Wall -o count-words count-words.c
clean:
rm -f count-words
提前致谢
答案 0 :(得分:1)
我问为什么gdb没有发生
在真实(或虚拟)UNIX系统上运行时, 与GDB一起发生。
在Windows下的#Ubuntu&#34; Ubuntu下运行时并没有发生这种情况。环境,因为那个环境正在疯狂sh * t。特别是,出于某种原因,Windows子系统通常只读取具有可写权限的部分(.rodata
,可能还有.text
)(这就是程序不再崩溃的原因),但只有在运行时调试器下的程序。
我不知道为什么Windows会这样做。
请注意,调试器执行需要写入(只读).text
部分才能插入断点。在真正的UNIX系统上,这是通过ptrace(PTRACE_POKETEXT, ...)
系统调用来实现的,该系统调用会更新只读页面,但为只有(正在调试)的过程保留只读。
我猜测Windows不能完全模仿这种行为(特别是在更新后不会对页面进行写保护)。
P.S。一般来说,在Windows上使用&#34; Ubuntu&#34;学习Ubuntu会充满像这样的陷阱。
,使用虚拟机可能会更好地 。答案 1 :(得分:0)
此功能错误
char *words(int count) {
char *words = "words";
if(count==1)
words[strlen(words)-1] = '\0';
return words;
}
指针words
指向字符串文字"words"
。修改字符串
literal是未定义的行为,并且在大多数系统字符串文字中存储
只读内存,所以这样做
words[strlen(words)-1] = '\0';
将导致段错误。这就是你在Ubuntu中看到的行为。我不知道 字符串文字存储在Windows可执行文件中,但修改字符串 文字是未定义的行为,任何事情都可能发生,尝试是没有意义的 推断为什么有时候事情会起作用,为什么有时事情不起作用。那是 未定义行为的本质。
修改强>
巴勃罗谢谢,但我不是在问这个错误本身,以及为什么发生了分段错误。我问为什么gdb不会发生这种情况。对不起,如果那还不够清楚。
我不知道为什么它不会发生在您身上,但是当我在我的gdb上运行您的代码时,我得到:
Reading symbols from ./bug...done.
(gdb) b 8
Breakpoint 1 at 0x6fc: file bug.c, line 8.
(gdb) r hey
Starting program: /tmp/bug hey
Breakpoint 1, words (count=1) at bug.c:8
8 words[strlen(words)-1] = '\0';
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554713 in words (count=1) at bug.c:8
8 words[strlen(words)-1] = '\0';
(gdb)