#26847 [Opn]: memory leak with to_r and subject_r in mail() function

2004-01-08 Thread nutbar at innocent dot com
 ID:   26847
 User updated by:  nutbar at innocent dot com
 Reported By:  nutbar at innocent dot com
 Status:   Open
 Bug Type: Mail related
 Operating System: any - source code issue
 PHP Version:  4.3.4
 New Comment:

By the way, very simple fix:

Add this to the variable declarations:

int j = 0;

Then the lines of code as mentioned before, but fixed:

if (to_len  0) {
to_r = estrndup(to, to_len);

for (j = to_len; j  0; j--) {
if (!isspace((unsigned char) to_r[j - 1])) {
break;
}

to_r[j - 1] = '\0';
}



and:

if (subject_len  0) {
subject_r = estrndup(subject, subject_len);

for (j = subject_len; j  0; j--) {
if (!isspace((unsigned char) subject_r[j - 1]))
{
break;
}

subject_r[j - 1] = '\0';
}


I just initialized j in the for loop to be the value of to_len and
subject_len, then I use j everywhere rather than to_len or subject_len
so that they stay unmodified.


Previous Comments:


[2004-01-08 13:22:55] nutbar at innocent dot com

Description:

In the actual source code for the PHP mail() function
(ext/standard/mail.c), it sets some variables up to hold the To: and
Subject: headers up, and other stuff.

The problem is that if you look at the initial code that checks if the
to_len count is greater than 0, it duplicates the to string to
to_r and does some stuff to it.

It does the same sort of thing with subject_len, subject, and subject_r
in the exact same fashion.

After the new to_r and subject_r strings are used, it goes to free
them, but it does an if () test to see if it should or not - the if
test compares to_len and subject_len to see if they are greater than 0
and if so, efree()'s them.

The problem is that in the code that does stuff with to_r and
subject_r, there are for loops which decrement to_len and subject_len
so it can walk the strings.  By doing this, you bring the to_len and
subject_len variables to 0, thus nothing is ever efree()'d in the end,
and you've got a memory leak.

The leak is small and not noticable typically, but with mass mailing
scripts that loop using mail(), it could be huge.

Reproduce code:
---
See mail.c - lines 106 to 113, 129 to 136, and then 160 to 165.

Actual result:
--
I have not tested for an actual memory leak by calling mail() in a loop
- I was just going to write my own mail() function and was using the
code in mail.c to do it with, and came across this.

If this is a false report, I am sorry, but I do believe it's real.





-- 
Edit this bug report at http://bugs.php.net/?id=26847edit=1


#26847 [Opn]: memory leak with to_r and subject_r in mail() function

2004-01-08 Thread nutbar at innocent dot com
 ID:   26847
 User updated by:  nutbar at innocent dot com
 Reported By:  nutbar at innocent dot com
 Status:   Open
 Bug Type: Mail related
 Operating System: any - source code issue
 PHP Version:  4.3.4
 New Comment:

I guess an alternate fix would also be when the efree()'s are called. 
If you init all your char *'s to NULL, then you can simply do:

if (to_r != NULL) {
 efree(to_r);
}

if (subject_r != NULL) {
 efree(subject_r);
}


Previous Comments:


[2004-01-08 15:31:12] nutbar at innocent dot com

By the way, very simple fix:

Add this to the variable declarations:

int j = 0;

Then the lines of code as mentioned before, but fixed:

if (to_len  0) {
to_r = estrndup(to, to_len);

for (j = to_len; j  0; j--) {
if (!isspace((unsigned char) to_r[j - 1])) {
break;
}

to_r[j - 1] = '\0';
}



and:

if (subject_len  0) {
subject_r = estrndup(subject, subject_len);

for (j = subject_len; j  0; j--) {
if (!isspace((unsigned char) subject_r[j - 1]))
{
break;
}

subject_r[j - 1] = '\0';
}


I just initialized j in the for loop to be the value of to_len and
subject_len, then I use j everywhere rather than to_len or subject_len
so that they stay unmodified.



[2004-01-08 13:22:55] nutbar at innocent dot com

Description:

In the actual source code for the PHP mail() function
(ext/standard/mail.c), it sets some variables up to hold the To: and
Subject: headers up, and other stuff.

The problem is that if you look at the initial code that checks if the
to_len count is greater than 0, it duplicates the to string to
to_r and does some stuff to it.

It does the same sort of thing with subject_len, subject, and subject_r
in the exact same fashion.

After the new to_r and subject_r strings are used, it goes to free
them, but it does an if () test to see if it should or not - the if
test compares to_len and subject_len to see if they are greater than 0
and if so, efree()'s them.

The problem is that in the code that does stuff with to_r and
subject_r, there are for loops which decrement to_len and subject_len
so it can walk the strings.  By doing this, you bring the to_len and
subject_len variables to 0, thus nothing is ever efree()'d in the end,
and you've got a memory leak.

The leak is small and not noticable typically, but with mass mailing
scripts that loop using mail(), it could be huge.

Reproduce code:
---
See mail.c - lines 106 to 113, 129 to 136, and then 160 to 165.

Actual result:
--
I have not tested for an actual memory leak by calling mail() in a loop
- I was just going to write my own mail() function and was using the
code in mail.c to do it with, and came across this.

If this is a false report, I am sorry, but I do believe it's real.





-- 
Edit this bug report at http://bugs.php.net/?id=26847edit=1


#26847 [Opn]: memory leak with to_r and subject_r in mail() function

2004-01-08 Thread nutbar at innocent dot com
 ID:   26847
 User updated by:  nutbar at innocent dot com
 Reported By:  nutbar at innocent dot com
 Status:   Open
 Bug Type: Mail related
 Operating System: any - source code issue
 PHP Version:  4.3.4
 New Comment:

Ok, maybe I am wrong?

I wrote a PHP script which *should* leak memory if this is indeed not
efree()'ing stuff, but it doesn't seem to.

I noticed it would only potentially (if I was right!) leak ram if say,
the subject was entirely space characters, so I made a script that
called mail() 1000 times roughly, and made a subject that was all
spaces that was 1k long - it should have set me off by 1mb, but instead
I see nothing of the sort.

I'm running the script from the command line (CGI, not CLI though!) if
it makes any difference (I don't believe it does).

Either way, I can't seem to leak the ram, so I guess I was wrong - but
can someone explain to me why it wouldn't?  What am I missing here that
wouldn't allow it to leak ram?


Previous Comments:


[2004-01-08 16:17:25] nutbar at innocent dot com

Here, maybe this will help a bit...  Here it assigns values to to_len
and subject_len (among others):

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, sss|ss,
  to,
to_len,
  subject,
subject_len,
  message,
message_len,
  headers,
headers_len,
  extra_cmd,
extra_cmd_len
  ) == FAILURE)
{
return;
}


Then, they check to_len and do stuff if it's greater than 0:

if (to_len  0) {
to_r = estrndup(to, to_len);
for (; to_len; to_len--) {
if (!isspace((unsigned char) to_r[to_len - 1]))
{
break;
}
to_r[to_len - 1] = '\0';
}
...


Do you see the for loop in there... this one:

for (; to_len; to_len--) {...}

It is modifying to_len itself, which means that to_len, although was
NOT 0 to begin with (and thus, to_r was estrndup()'d and we have to
efree() it later), but IS 0 in the end once the for loop is finished.

Either the for loop must be changed to not modify to_len, or the
efree() statement must be changed to test to_r, not to_len.

Or am I just really out of my mind?  I'm not anywhere near as good as
you programmers, but this seems to be sticking out for me quite a bit
(I'm not trying to come off rude!  I just think I found something here
and it's not bogus).



[2004-01-08 16:07:29] nutbar at innocent dot com

I know they check to_len and subject_len - that's not really the
problem.

The problem is that the for loops above that decrement to_len and
subject_len - thus modifying them from their original values.

to_len and subject_len will always be 0, even if they weren't 0 to
begin with.  Do you see what I'm referring to?



[2004-01-08 15:38:41] [EMAIL PROTECTED]

Impossible leak. 
if (to_len  0) { 
efree(to_r); 
} 
if (subject_len  0) { 
efree(subject_r); 
} 
Is what the code in CVS does. If to_len or subject_len are 
 1 then no allocation happens in the 1st place. 



[2004-01-08 15:34:23] nutbar at innocent dot com

I guess an alternate fix would also be when the efree()'s are called. 
If you init all your char *'s to NULL, then you can simply do:

if (to_r != NULL) {
 efree(to_r);
}

if (subject_r != NULL) {
 efree(subject_r);
}



[2004-01-08 15:31:12] nutbar at innocent dot com

By the way, very simple fix:

Add this to the variable declarations:

int j = 0;

Then the lines of code as mentioned before, but fixed:

if (to_len  0) {
to_r = estrndup(to, to_len);

for (j = to_len; j  0; j--) {
if (!isspace((unsigned char) to_r[j - 1])) {
break;
}

to_r[j - 1] = '\0';
}



and:

if (subject_len  0) {
subject_r = estrndup(subject, subject_len);

for (j = subject_len; j  0; j--) {
if (!isspace((unsigned char) subject_r[j - 1]))
{
break;
}

subject_r[j - 1] = '\0';
}


I just initialized