微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

一些内存管理问题:Error AddressSanitizer

如何解决一些内存管理问题:Error AddressSanitizer

我试图解决 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;
}

有谁知道我哪里错了?

解决方法

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

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","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","flight"};
                                 ^~~~~~~~

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

const char *s[] = {"flower","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","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]);
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。