c - 分段错误消失,gdb 在 ubunutu 在 Windows 上



我的任务是在以下代码中找到错误并修复它:

/* $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] = '';
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] = '';
(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"的事情)有关,但找不到任何对我有帮助的东西。

这是我的制作文件:

all: 
gcc -g -Wall -o count-words count-words.c 
clean: 
rm -f count-words 

提前致谢

我在问为什么 gdb 没有发生这种情况

在真实(或虚拟)UNIX系统上运行时,GDB确实发生了这种情况。

在奇怪的"Ubuntu on Windows"环境下运行时,它并没有发生,因为那个环境正在做疯狂的sh*t。特别是,由于某种原因,Windows子系统通常映射具有可写权限的只读部分(.rodata,可能也是.text),但仅在调试器下运行程序时。

我不知道Windows为什么这样做。

请注意,调试器确实需要写入(只读).text节才能插入断点。在真正的 UNIX 系统上,这是通过ptrace(PTRACE_POKETEXT, ...)系统调用来实现的,系统调用更新只读页面,但对于较差(正在调试)进程将其保留为只读

我猜 Windows 没有完美地模拟这种行为(特别是在更新页面后不会对页面进行写保护)。

附言一般来说,使用"Ubuntu on Windows"来学习Ubuntu会充满像这样的陷阱。改用虚拟机可能会好得多

这个函数是错误的

char *words(int count) {
char *words = "words";
if(count==1) 
words[strlen(words)-1] = '';
return words;
}

指针words指向字符串文本"words"。修改字符串 文本是未定义的行为,在大多数系统中,字符串文本存储在 只读内存,如此

words[strlen(words)-1] = '';

将导致段错误。这就是你在 Ubuntu 中看到的行为。我不知道 其中字符串文本存储在 Windows 可执行文件中,但修改字符串 字面意思是未定义的行为,任何事情都可能发生,尝试是没有意义的 推断为什么有时事情有效,为什么有时事情不起作用。那是 未定义行为的本质。

编辑

Pablo 谢谢,但我不是在问错误本身,以及为什么会发生分段错误。我在问为什么 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] = '';
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554713 in words (count=1) at bug.c:8
8       words[strlen(words)-1] = '';
(gdb) 

最新更新