c

[C] free할 때 주의할 점

ohojee 2022. 12. 28. 15:46

free가 동적할당된 메모리를 free해준다는 개념은 알고 있었는데 자세하게 이해하고 있지는 않았다.

그래서 아래와 같은 코드를 작성했다. 

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

int main(void)
{
	char *str = (char *)malloc(sizeof(char) * 40);
	char *result;
	for (int i = 0; i < 5; i++)
	{
		str[i] = i + '0';
		printf("%c\n", str[i]);
	}
	result = str;
	free(str);
	for (int i = 5; i < 10; i++)
	{
		result[i] = i + '0';
		printf("%c\n", result[i]);
	}
	return ('a');
}

str에 동적할당을 해주고 result에 str을 넘겨줬다.

그 후 str을 free해주고 result에 값을 넣으려고 하니 아래와 같은 메모리 오류가 발생했다. 

==1598==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000355 at pc 0x000104fcddd2 bp 0x7ffeeac35840 sp 0x7ffeeac35838
WRITE of size 1 at 0x604000000355 thread T0
    #0 0x104fcddd1 in main test.c:17
    #1 0x7fff720bbcc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)

0x604000000355 is located 5 bytes inside of 40-byte region [0x604000000350,0x604000000378)
freed by thread T0 here:
    #0 0x1050252c6 in wrap_free+0xa6 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x492c6)
    #1 0x104fcdd60 in main test.c:14
    #2 0x7fff720bbcc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)

previously allocated by thread T0 here:
    #0 0x10502517d in wrap_malloc+0x9d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4917d)
    #1 0x104fcdc58 in main test.c:6
    #2 0x7fff720bbcc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)

SUMMARY: AddressSanitizer: heap-use-after-free test.c:17 in main
Shadow bytes around the buggy address:
  0x1c0800000010: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
  0x1c0800000020: fa fa 00 00 00 00 00 05 fa fa 00 00 00 00 00 00
  0x1c0800000030: fa fa 00 00 00 00 00 05 fa fa 00 00 00 00 00 00
  0x1c0800000040: fa fa 00 00 00 00 00 07 fa fa 00 00 00 00 00 00
  0x1c0800000050: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
=>0x1c0800000060: fa fa 00 00 00 00 00 05 fa fa[fd]fd fd fd fd fa
  0x1c0800000070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0800000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0800000090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c08000000a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c08000000b0: 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
==1598==ABORTING
zsh: abort      ./a.out​

free를 해주고 그 주소에 왜 또 다시 접근하냐는 얘기인데

str과 result의 주소값이 똑같은 상태에서 str을 free해주면 result에 속해있는 주소값이 할당해제 되는 것이다.

애초에 free가 그 주소에 할당된 메모리를 해제해주는 것이기에 아주 당연한 소리지만 나에게는 헷갈리는 개념이었다.