diff options
author | Ted Law <tedlaw@cibcwg.com> | 1999-01-27 09:54:03 -0500 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 1999-02-02 17:14:37 +0000 |
commit | e8227f62804a142aaea998dbf5094253becf02f9 (patch) | |
tree | 329a960ef86997bc14d5c98cfb758112d2017f88 /ext | |
parent | 9728b48bb2f227925881e09aa9f9fe69725d8235 (diff) | |
download | perl-e8227f62804a142aaea998dbf5094253becf02f9.tar.gz |
POSIX::strftime buffer overflow problem
Message-Id: <199901271954.OAA07391@dcm2.cibcwg.com>
p4raw-id: //depot/cfgperl@2797
Diffstat (limited to 'ext')
-rw-r--r-- | ext/POSIX/POSIX.xs | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs index c948cc6fad..ae88aefc99 100644 --- a/ext/POSIX/POSIX.xs +++ b/ext/POSIX/POSIX.xs @@ -3631,7 +3631,41 @@ strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) mytm.tm_isdst = isdst; (void) mktime(&mytm); len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm); - ST(0) = sv_2mortal(newSVpv(tmpbuf, len)); + /* + ** The following is needed to handle to the situation where + ** tmpbuf overflows. Basically we want to allocate a buffer + ** and try repeatedly. The reason why it is so complicated + ** is that getting a return value of 0 from strftime can indicate + ** one of the following: + ** 1. buffer overflowed, + ** 2. illegal conversion specifier, or + ** 3. the format string specifies nothing to be returned(not + ** an error). This could be because format is an empty string + ** or it specifies %p that yields an empty string in some locale. + ** If there is a better way to make it portable, go ahead by + ** all means. + */ + if ( ( len > 0 && len < sizeof(tmpbuf) ) + || ( len == 0 && strlen(fmt) == 0 ) ) { + ST(0) = sv_2mortal(newSVpv(tmpbuf, len)); + } else { + /* Possibly buf overflowed - try again with a bigger buf */ + int bufsize = strlen(fmt) + sizeof(tmpbuf); + char* buf = safemalloc(bufsize); + int buflen; + while( buf ) { + buflen = strftime(buf, bufsize, fmt, &mytm); + if ( buflen > 0 && buflen < bufsize ) break; + bufsize *= 2; + buf = saferealloc(buf, bufsize); + } + if ( buf ) { + ST(0) = sv_2mortal(newSVpv(buf, buflen)); + safefree(buf); + } else { + ST(0) = sv_2mortal(newSVpv(tmpbuf, len)); + } + } } void |