首页 > 解决方案 > 是否有检测 C 程序中的内存错误的解决方案?

问题描述

我正在编写 C lib 函数并且有关于内存的问题。对于strcpy()功能:

char *my_strcpy(char *str1, char *str2)
{
    int i = 0;

    for (; str2[i] != 0; i++)
        str1[i] = str2[i];
    str1[i] = 0;
    return (str1);
}

使用以下标准测试:

#include <criterion/criterion.h>

char *my_strcpy(char *str1, char *str2);

Test(my_strcpy, in_allocated_string)
{
    char *src = "Hello World";
    char dest[11];

    my_strcpy(dest, src);
    cr_assert_str_eq(dest, "Hello World");
    cr_assert_eq(dest, my_strcpy(dest, src));
}

目标缓冲区小于源缓冲区,因此它不应该工作......但它可以工作。Valgrind 或扫描构建不会给我任何错误,它编译并运行没有错误......

用于编译和运行测试的 Makefile:

SRC =   code.c          \

SRC_TEST    =   test.c  \

LDFLAGS =   -L./lib/my -lmy

OBJ =   $(SRC:.c=.o)

CC  =   gcc

CFLAGS  =   -W -Wall -Wextra -Werror -fstack-protector -fstack-protector-all -fstack-protector-strong -Wstack-protector

NAME    =   libmy.a

all: $(NAME)

$(NAME):    $(OBJ)
        ar rc   $@ $^

test:   $(SRC) $(SRC_TEST)
        $(CC) -fprofile-arcs -ftest-coverage -Isrc/main -DMOCKING $(CFLAGS) $(shell pkg-config --libs --cflags criterion) $^ -o tests
        ./tests

clean:
        rm -rf *.gcda *.gcno *.info $(OBJ)

fclean: clean
        rm -f $(NAME)
        rm -rf tests

re: fclean all

是否有检测 C 程序中的内存错误的解决方案?

标签: c

解决方案


Valgrind 的 Memcheck对堆栈上分配的数组有一些限制。由于它适用于正常编译的二进制文件,因此在某些情况下它无法知道确切的数组大小。

clang 的AddressSanitizer在这方面做得更好。如果你用 编译-fsanitize=address,你会得到以下错误:

=================================================================
==15908==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffdb7e06beb at pc 0x0000005286d2 bp 0x7ffdb7e06b40 sp 0x7ffdb7e06b38
WRITE of size 1 at 0x7ffdb7e06beb thread T0
    #0 0x5286d1 in my_strcpy (/home/runner/.bin.tio+0x5286d1)
    #1 0x52883d in main (/home/runner/.bin.tio+0x52883d)
    #2 0x7ff3e3fae412 in __libc_start_main (/lib64/libc.so.6+0x24412)
    #3 0x41b33d in _start (/home/runner/.bin.tio+0x41b33d)

Address 0x7ffdb7e06beb is located in stack of thread T0 at offset 43 in frame
    #0 0x5286ff in main (/home/runner/.bin.tio+0x5286ff)

  This frame has 1 object(s):
    [32, 43) '.compoundliteral' <== Memory access at offset 43 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/runner/.bin.tio+0x5286d1) in my_strcpy
Shadow bytes around the buggy address:
  0x100036fb8d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100036fb8d70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00[03]f3 f3
  0x100036fb8d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100036fb8dc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==15908==ABORTING

推荐阅读