【问题标题】:Some memory management trouble: Error AddressSanitizer一些内存管理问题:Error AddressSanitizer
【发布时间】:2021-05-28 08:20:56
【问题描述】:

我正在尝试解决 LeetCode 问题:#14 Longest Common Prefix。这是问题陈述:

编写一个函数来查找字符串数组中最长的公共前缀字符串。如果没有公共前缀,则返回一个空字符串“”。

在解决它时,我遇到了一些错误。从错误消息中,我了解到存在无效的内存操作。但是,仍然无法从错误消息中获得积分:

=================================================================
==29==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000110 at pc 0x55b10cc03190 bp 0x7fff30b617c0 sp 0x7fff30b617b0
READ of size 8 at 0x602000000110 thread T0
    #1 0x7f5a70bb00b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x602000000111 is located 0 bytes to the right of 1-byte region [0x602000000110,0x602000000111)
allocated by thread T0 here:
    #0 0x7f5a717f5bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #3 0x7f5a70bb00b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff8000: fa fa 07 fa fa fa 05 fa fa fa 07 fa fa fa 07 fa
  0x0c047fff8010: fa fa 04 fa fa fa 00 fa fa fa 04 fa fa fa 03 fa
=>0x0c047fff8020: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==29==ABORTING

这是我的 C 代码:

#include <stdio.h>
#include <stdlib.h>

char *func(char ** strs, int strsSize){
    char *ans = strs[0];
    int n, i;

    for(i = 1;i < strsSize;i++){
        n = 0;
        while(1){
            if(ans[n] == strs[i][n]){
                n++;
            }
            else{
                break;
            }
        }
        ans[n] = '\0';
    }

    return ans;
}

int main()
{
    char *s[] = {"flower","flow","flight"};
    printf("%s", func(s, 3));
    return 0;
}

有谁知道我错在哪里?

【问题讨论】:

  • 无法从错误信息中获得分数。什么错误信息?如果您询问具体错误,请显示它们。对于初学者,s 数组中的字符串是文字,不可写。所以ans[n] = '\0'; 在尝试写入文字时是未定义的行为。
  • 开启编译器警告。他们会指出你的问题。如果您仍然遇到问题,请发表评论,我会提供更多帮助。
  • 抱歉,这篇文章不允许我写太多代码内容。错误消息是关于堆缓冲区溢出的。或者有什么方法可以提供大量错误消息?
  • @scorerhsu 我可以看到带有错误消息的编辑。您发布的代码没有堆分配(malloc),所以我很困惑。您发布的代码是否显示错误?

标签: c memory runtime-error address-sanitizer


【解决方案1】:

编译器警告会提示问题。打开编译器警告并不简单,但这是我觉得有用的。

cc -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c11 -pedantic -g   -c -o test.o test.c

您可以查看herehere 的含义。

这些会给出一系列警告。

test.c:26:18: warning: initializing 'char *' with an expression of type 'const char [7]' discards
      qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    char *s[] = {"flower","flow","flight"};
                 ^~~~~~~~
test.c:26:27: warning: initializing 'char *' with an expression of type 'const char [5]' discards
      qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    char *s[] = {"flower","flow","flight"};
                          ^~~~~~
test.c:26:34: warning: initializing 'char *' with an expression of type 'const char [7]' discards
      qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    char *s[] = {"flower","flow","flight"};
                                 ^~~~~~~~

这告诉我们我们有一个const char [],我们将其用作char *。如果我们天真地解决这个问题......

const char *s[] = {"flower","flow","flight"};

现在有一个新的警告。

test.c:27:23: warning: passing 'const char *[3]' to parameter of type 'char **' discards qualifiers
      in nested pointer types [-Wincompatible-pointer-types-discards-qualifiers]
    printf("%s", func(s, 3));
                      ^
test.c:4:20: note: passing argument to parameter 'strs' here
char *func(char ** strs, int strsSize){
                   ^

同样,我们使用const char *[] 作为char **。好的,让我们天真地解决这个问题。

char *func(const char ** strs, int strsSize){

另一个警告。

test.c:5:11: warning: initializing 'char *' with an expression of type 'const char *' discards
      qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    char *ans = strs[0];
          ^     ~~~~~~~

同样的问题,现在我们将const char * 用作char *。让我们天真地解决这个问题。

const char *ans = strs[0];

现在我们得到一个错误

test.c:18:16: error: read-only variable is not assignable
        ans[n] = '\0';
        ~~~~~~ ^

终于有问题了。 {"flower","flow","flight"}string literals which are read-only。这些字符串在可执行文件本身中,无法更改。

$ strings test
flower
flow
flight

当您将它们分配给 char * 时,您正在尝试修改它们,但这是不可能的。 ans[n] = '\0'; 是未定义的行为,您会收到错误。


这些字符串需要是可写的。我不知道这样做的优雅方法,一种方法是使用strdup 将字符串文字复制到动态内存中。

    char *s[] = {
        strdup("flower"),
        strdup("flow"),
        strdup("flight")
    };

由于它们是动态分配的,因此需要释放它们。

    for(int i = 0; i < 3; i++) {
        free(s[i]);
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 2011-01-07
    • 2016-10-20
    相关资源
    最近更新 更多