메모리 누수현상 찾기..

leolo의 이미지

다음은 C로 작성한 CGI파일 입니다..
다음을 연속적으로 여러번 실행하면
메모리 누수 현상이 발생합니다.
도대체 어디에서 발생하는지 좀 알려주세요.
아님.. httpd 데몬에 문제인지 알고 싶습니다.
지금과 같은 경우는 입력폼으로 부터 어떠한 값도 받지 않으므로
결과는 다음과 같이 나옵니다. "Got 0 pairs"

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define TEST 1

struct cgi_object {
	char *name;
	char *value;
	
	struct cgi_object *next;
};

static struct cgi_object *list=NULL;

/* function to remove url encoding */
int url_decode(char *dst, char *src, int len)
{
	int a=0, b=0;
	int c;

	while (b<len)
	{
		if (src[b]=='+')
		{
			dst[a++]=' ';
			b++; 
		}
		else if (src[b]=='%')
		{
			if (sscanf(&src[b+1],"%2x",&c)>0)
				dst[a++]=c;
			b+=3;
		}
		else dst[a++]=src[b++];
	}
	dst[a++]=0;
	return (a);
}
void cgi_free(struct cgi_object *ptr)
{
	struct cgi_object *current = ptr;
	struct cgi_object *next;

	while(current != NULL){
		next = current->next;
		if(current->name) free(current->name);
		if(current->value) free(current->value);
		if(current->next) free(current->next);
		free(current);
		current = next;
	}
	ptr = NULL;
}

/* destructive to the query string */
static int cgi_split_pairs(char *query)
{
	char *start = NULL, *mid = NULL, *end = NULL;
	struct cgi_object *new = NULL;
	int count = 0;

	start=query;
	while (start!=NULL && *start!=0)
	{
		int len;
		if ((end=strchr(start, '&'))==NULL)
			end=start+strlen(start);

		if ((mid=strchr(start, '='))==NULL)
			mid=end;
	
		if (mid > end) mid=end;

		if (start == mid) 
		{
			start=end+1;
			continue;
		}

		new=(struct cgi_object *)malloc(sizeof(*new));
		if(new==NULL)
			exit(1);
		len=mid-start;
		new->name=(char *)malloc(len+1);
		if(new->name==NULL)
			exit(1);
		url_decode(new->name, start, len);
	
		if (end > mid)
		{
			mid++;
			len=end-mid;
			new->value=(char *)malloc(len+1);
			url_decode(new->value, mid, len);
			new->value[len]=0;
		}else
			new->value=NULL;
	
		new->next=list;
		list=new;
		start=end;
		if (*start=='&') start++;
		count++;
	}
	return (count);
}	
			
#if 0
char *cgi_find(char *what)
{
	struct cgi_object *ptr;

	ptr=list;
	while (ptr!=NULL)
	{
		if (!strcasecmp(what, ptr->name))
			return(ptr->value);
		ptr=ptr->next;
	}
	return(NULL);
}

char *cgi_nfind(char *what, int which)
{
	struct cgi_object *ptr;
	int i=1;

	ptr=list;
	while (ptr!=NULL)
	{
		if (!strcasecmp(what, ptr->name))
		{	
			if (i==which)
				return(ptr->value);
			i++;
		}
		ptr=ptr->next;
	}
	return(NULL);
}
#endif

/* count the number of arguments,
   or number of arguments with a specific name */
int cgi_count(char *what)
{
	struct cgi_object *ptr;
	int count=0;

	ptr=list;
	while (ptr!=NULL)
	{
		if (what==NULL || !strcmp(what, ptr->name))
			count++;
		ptr=ptr->next;
	}
	return (count);
}
/* master processing function */
int cgi_process(void)
{
	static int done=0;
	char *method, *query;
	int count=0;

	if (done) return ( cgi_count(NULL) );

	if ((method=getenv("REQUEST_METHOD"))==NULL)
		return(0);

	if (!strcasecmp(method, "GET"))
	{
		if ((query=getenv("QUERY_STRING"))==NULL)
			return(0);
		query=strdup(query);
		count=cgi_split_pairs(query);	
		free(query);
	}else
	if (!strcasecmp(method, "POST"))
	{
		int len;
		if ((query=getenv("CONTENT_LENGTH"))==NULL)
			return(0);
		if ((len=atoi(query))<=0) return(0);
		query=(char *)malloc(len+1);
		if(query==NULL)
			exit(1);
		read(fileno(stdin), query, len);
		query[len+1]=0;
		count=cgi_split_pairs(query);	
		free(query);
	}else
	{
		fprintf(stderr, "Unknown REQUEST_METHOD of '%s'\n", method);
		return(0);
	}

	done=1;
	return ( count );
}

#ifdef TEST

int main()
{
	int i;
	struct cgi_object *ptr;

	i = cgi_process();
	
	printf("Content-type: text/html\n\n");
	printf("<html><body>\n");
	printf("Got %d pairs<br>\n",i);

	if (i>0)
	{
		printf("<ol>\n");
		ptr=list;
		while (ptr!=NULL)
		{
			printf("<li> %s", ptr->name);
			if (ptr->value!=NULL)
				printf(" = '%s'", ptr->value);
			printf("\n");
			ptr=ptr->next;
		}
		printf("</ol>\n");
	}
	printf("</body></html>\n");
	cgi_free(list);
	exit(0);
}

#endif	
stoneshim의 이미지

void cgi_free(struct cgi_object *ptr) 
{ 
   struct cgi_object *current = ptr; 
   struct cgi_object *next; 

   while(current != NULL){ 
      next = current->next; 
      if(current->name) free(current->name); 
      if(current->value) free(current->value); 
      /* 이 라인이 빠져야 할것 같은데요... */
      /*
      if(current->next) free(current->next); 
      */
      free(current); 
      current = next; 
   } 
   ptr = NULL; 
} 

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

stoneshim의 이미지

지금 저번에 질문하신 글을 봤는데 거기엔 if(current->next) free(current->next);
이부분이 없더군요.

이 부분이 없을때에도 문제가 있었다는 것으로 생각되어서 다시 좀 봤더니... list에다가 추가하는 부분도 이상합니다.

static int cgi_split_pairs(char *query) 
{ 
....
   while (...) {
      ...
      new->next=list; 
      list=new;      ...
   }
....
} 

이 부분에서 보면 input name/value pair가 여러개 오는 경우 list는 항상 마지막 하나의 cgiobject(마지막 new)를 가리키게 되지 않나요?
list에 이미 append되어 있는 마지막 item( cgiobject )을 찾아가서 그 뒤에 append 해주어야 하는것 아닌가요?

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

서지원의 이미지

cgi 프로그램이면, memory leak은 생각할 필요 없습니다. cgi는 요청이 들어오면 새 process 가 생성되었다가 죽으므로, 웹서버의 메모리 릭이랑은 무관합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.