-2

I'm coding C lib functions and have a problem about the memory. For the strcpy() function:

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

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

With the Criterion test below:

#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));
}

The destination buffer is smaller than the source so it should not work... But it works. Valgrind or scan build don't give me any error, it compiles and runs without error...

A Makefile for compile and run with test:

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

Is there a solution to detect memory error in a C program?

jjrv
  • 4,211
  • 2
  • 40
  • 54
Maxime
  • 29
  • 2

2 Answers2

1

This C analyzer can tell you that there is something wrong when your function is misused:

https://taas.trust-in-soft.com/tsnippet/t/cf1e64df

It tells you, when applied to dest and src, that an invalid write happens inside your function at str1[i] = 0;.

screenshot of Tsnippet finding a bug

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
1

Valgrind's Memcheck has some limitations regarding arrays allocated on the stack. Since it works with normally compiled binaries, it can't know the exact array sizes under certain circumstances.

clang's AddressSanitizer is better in this regard. If you compile with -fsanitize=address, you'll get the following error:

=================================================================
==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
nwellnhof
  • 32,319
  • 7
  • 89
  • 113