free 에러 문제

bluebear2706의 이미지

int main(void){
Data_b* data_b = NULL;
Data_a* data_a = NULL;

CreateDataA(&data_a);
CreateDataB(&data_b, &data_a);

printf("1 wrappedkey = %p, pData = %p\n", data_a, data_a->pData);
printf("1 data_b = %p, pData = %p\n", data_b, data_b->pData);
Data_b_Release(data_b);
Data_a_Release(data_a);
printf("1 wrappedkey = %p, pData = %p\n", data_a, data_a->pData);
printf("1 data_b = %p, pData = %p\n", data_b, data_b->pData);

return 0;
}

yhsuk의 이미지

포인터 변수들은 주소값을 담고 있는 변수에 불과합니다.
복사된 변수값은 한쪽이 변해도 안변하죠.

int a = 5;
int b = 0;
b = a;
a = 9;

이렇게 해도 b는 여전히 5를 가집니다. 포인터 변수도 마찬가지입니다.
무언가 알아서 잘 좀 해줬으면 싶지만, 그렇지 못하죠.

이미 free된 메모리 주소값을 담고 있는 포인터 변수가 되고, 이런 포인터 변수를 지칭하는 용어는 dangling pointer 입니다.
그리고 이런 dangling pointer 를 역참조(dereference)하게 되면 segfault가 됩니다.

Signature :) - "여유를 갖고 행동하되 게을러지지 말자"

klara의 이미지

자바 프로그래머신가요? 질문 수준에 비해서 코딩이 깔끔한걸로 봐서는 다른거하시다가 C를 공부하시나 봅니다.
포인터는 객체 그 자체가 아니라 어떤 정수값일 뿐입니다. 그 정수값이 메모리의 어떤 번지수에 대응된다는게 일반적인 정수와 다른 점입니다.
'객체 o를 가리키는 포인터 p'라고 자주 표현을 하지만, 그렇다고 정말로 그 포인터가 곧 그 객체를 나타내는게 아닙니다.
포인터는 어떤 주소값을 담고 있을 뿐이고, '객체 o를 가리키는 포인터 p'라는 표현은 단순히 포인터 p의 값과 객체 o의 주소값이 일치한다는 것의 관용적인 표현입니다. 포인터 p1과 p2가 모두 같은 객체 o를 가리키고 있다고 해도, p1의 값을 바꾼다고 p2의 값이 바뀌지는 않습니다. p1과 p2는 그냥 서로다른 정수 변수일 뿐이니까요.
이는 함수 인자에 대해서도 마찬가지입니다. C의 모든 함수 인자는 call-by-value로 넘어가기 때문에, Data_a_Release(Data_a *pSecureData) 에서 pSecureData는 함수로 넘긴 변수(이경우에는 main함수내의 data_a)와 값이 같은 또 다른 변수입니다. 따라서 pSecureData의 값이 바뀐다고 해서 전혀 다른 변수인 data_a의 값이 바뀌지 않습니다. 자바에서도 primitive-type은 call-by-value라고 알고 있는데, 포인터를 넘기고 그 안에서 포인터에 대입하는 건, 그냥 정수하나 넘기고 그안에서 대입하는 것과 동작원리가 동일합니다.

bluebear2706의 이미지

이해가 잘 되었어요. 그런데, 그럼 Release함수에서 free를 하더라도 메모리 헤재가 되지 않나요?

그러면 free해주고 싶을 땐 어떻게 해야 하나요

klara의 이미지

메모리는 해제됩니다. 메모리를 해제하는 것과, 포인터의 값을 바꾸는 건 별개입니다. 다시 강조하지만 포인터는 그냥 어떤 주소값을 담고 있는 정수 변수일 뿐입니다. free의 인자로 포인터를 넘기는 것은 포인터를 해제하라는 뜻이 아니라 이 포인터의 값에 해당하는 주소에 할당된 메모리를 해제하라는 겁니다. 포인터 변수자체는 그냥 주소값이니까 그 주소에 어떤 객체가 할당되어있던 안되어있던 아무상관이 없습니다.
함수안에서 함수로 넘긴 변수의 값을 바꾸고 싶을 때 사용하는게 포인터인데, 함수안에서 포인터가 가리키는 메모리를 해제한 후에 이 포인터의 값이 NULL로 바뀌도록 하고 싶으신거라면 포인터의 포인터(이중 포인터)를 사용해야 합니다. 함수를 호출할때에는 포인터가 아니라 포인터의 주소값을 넘겨줘야하고요.

bluebear2706의 이미지

slice_sd는 Data_b* 형태이고, 사용하다가 헤재하려 합니다.

printf("slice_sd = %p, slice_sd->pData = %p\n", slice_sd, slice_sd->pData);
sres = Data_a_Release(slice_sd);
printf("slice_sd = %p, slice_sd->pData = %p\n", slice_sd, slice_sd->pData);
slice_sd->size = 3;
printf("slice_sd->size = %d\n", slice_sd->size);

이렇게 테스트를 해봤습니다.

slice_sd = 0x98dca78, slice_sd->pData = 0x98dca90
slice_sd = 0x98dca78, slice_sd->pData = (nil)
slice_sd->size = 3

결과는 이렇구요.

왜 slice_sd는 값이 (nil)이 아닌가요?

만약, slice_sd가 해제 되었다면 slice_sd->size는 값이 들어가면 안될텐데요

klara의 이미지

free한다고 자동으로 포인터가 NULL로 바뀌지 않습니다. 그 이유는 앞에서 전부 설명했습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.