C 在windows上使用ubunutu中的gdb消除分段错误

C 在windows上使用ubunutu中的gdb消除分段错误,c,linux,windows,ubuntu,gdb,C,Linux,Windows,Ubuntu,Gdb,我的任务是在以下代码中查找bug,并修复它: /* $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";

我的任务是在以下代码中查找bug,并修复它:

/* $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);
}
在第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(在Windows10上使用虚拟机)运行同样的东西时,分割错误确实发生在gdb上

我倾向于认为这与我的运行时环境有关(“Windows上的Ubuntu”一词),但找不到任何对我有帮助的东西

这是我的生成文件:

all: 
    gcc -g -Wall -o count-words count-words.c 

clean: 
    rm -f count-words 
提前感谢

此功能错误

char *words(int count) {
  char *words = "words";
  if(count==1) 
    words[strlen(words)-1] = '\0';
  return words;
}
指针
words
指向字符串literal
“words”
。修改字符串 文字是未定义的行为,在大多数系统中,字符串文字存储在 只读存储器,就是这样

    words[strlen(words)-1] = '\0';
将导致一个错误。这就是你在Ubuntu中看到的行为。我不知道 其中字符串文本存储在windows可执行文件中,但修改字符串 文字是未定义的行为,任何事情都可能发生,尝试都是毫无意义的 推断为什么有时事情会起作用,为什么有时事情不起作用。那是 未定义行为的性质

编辑

Pablo谢谢,但我不是在问bug本身,也不是在问为什么会出现分段错误。我在问为什么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) 
我在问为什么gdb没有发生这种情况

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

在奇怪的“Windows上的Ubuntu”环境下运行时没有发生这种情况,因为该环境正在进行疯狂的sh*t。特别是,由于某些原因,Windows子系统通常将只读部分(
.rodata
,也可能是
.text
)映射为可写权限(这就是程序不再崩溃的原因),但仅当您在调试器下运行程序时才映射

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

请注意,调试器确实需要写入(只读)
.text
部分才能插入断点。在真正的UNIX系统上,这是通过
ptrace(ptrace\u POKETEXT,…)
system调用来实现的,该调用更新只读页面,但将其保留为只读,供低级(正在调试的)进程使用

我猜Windows没有完全模拟这种行为(尤其是在更新页面后没有写保护页面)


另外,一般来说,使用“Windows上的Ubuntu”来学习Ubuntu将会充满像这样的陷阱。使用虚拟机可能会更好。

char*words=“words”
是指向字符串文字的指针,修改它是未定义的行为,在大多数情况下会导致segfault,因为它是只读内存。你不能修改它。不要写这样的代码。@Michi我觉得很奇怪OP的gdb没有显示SEGFULT。这就是UB。不要要求解释为什么错误代码有时会起作用。有更好的方法可以实现多元化,例如
char*plural[]={”,“s};printf(“%d个单词%s”,count,复数[count!=1])“但是修改字符串文字是未定义的行为,任何事情都有可能发生。”,也许OP会幸运地看到他的PC是如何燃烧的。他永远不会那样写代码。那会很有趣;)事实上,我没有写那个代码。它是由我的课程导师编写的,作为指针和gdb调试的练习。它的一些要点是教你不要写那样的代码。谢谢你,我现在明白了。我想我将不得不适应虚拟机(对我来说,它的运行速度相对较慢,尽管我给了它大量的内存…我不知道为什么它很慢,但我没有仔细考虑。这就是为什么我选择在Windows上使用Ubuntu的原因)。再次感谢
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)