Revision: 1045
Author: [email protected]
Date: Mon Feb 8 06:49:33 2010
Log: Convert NYTProf_gets() to dynamically resize the read buffer, so that
it can
read arbitrary length attributes and comments.
They aren't usually a problem, but user input can provoke nytprofmerge into
generating some very long values.
http://code.google.com/p/perl-devel-nytprof/source/detail?r=1045
Modified:
/trunk/FileHandle.h
/trunk/FileHandle.xs
/trunk/NYTProf.xs
=======================================
--- /trunk/FileHandle.h Fri Dec 18 07:09:33 2009
+++ /trunk/FileHandle.h Mon Feb 8 06:49:33 2010
@@ -25,7 +25,7 @@
void NYTP_start_inflate(NYTP_file file);
NYTP_file NYTP_open(const char *name, const char *mode);
-char *NYTP_gets(NYTP_file ifile, char *buffer, unsigned int len);
+char *NYTP_gets(NYTP_file ifile, char **buffer, size_t *len);
size_t NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len);
size_t NYTP_read(NYTP_file ifile, void *buffer, size_t len, const char
*what);
size_t NYTP_write(NYTP_file ofile, const void *buffer, size_t len);
=======================================
--- /trunk/FileHandle.xs Mon Dec 28 14:24:20 2009
+++ /trunk/FileHandle.xs Mon Feb 8 06:49:33 2010
@@ -191,12 +191,35 @@
return file;
}
+
+/* This isn't exactly fgets. It will resize the buffer as needed, and
returns
+ a pointer to one beyond the read data (usually the terminating '\0'), or
+ NULL if it hit error/EOF */
char *
-NYTP_gets(NYTP_file ifile, char *buffer, unsigned int len) {
+NYTP_gets(NYTP_file ifile, char **buffer_p, size_t *len_p) {
+ char *buffer = *buffer_p;
+ size_t len = *len_p;
+ size_t prev_len = 0;
+
CROAK_IF_NOT_STDIO(ifile, "NYTP_gets");
- return fgets(buffer, len, ifile->file);
+ while(fgets(buffer + prev_len, len - prev_len, ifile->file)) {
+ /* We know that there are no '\0' bytes in the part we've already
+ read, so don't bother running strlen() over that part. */
+ char *end = buffer + prev_len + strlen(buffer + prev_len);
+ if (end[-1] == '\n') {
+ *buffer_p = buffer;
+ *len_p = len;
+ return end;
+ }
+ prev_len = len - 1; /* -1 to take off the '\0' at the end */
+ len *= 2;
+ buffer = saferealloc(buffer, len);
+ }
+ *buffer_p = buffer;
+ *len_p = len;
+ return NULL;
}
#ifdef HAS_ZLIB
=======================================
--- /trunk/NYTProf.xs Fri Feb 5 09:56:52 2010
+++ /trunk/NYTProf.xs Mon Feb 8 06:49:33 2010
@@ -3615,16 +3615,17 @@
SV *cb_TIME_LINE_tag = NULL;
SV *cb_args[12]; /* must be large enough for the largest callback
argument list */
+ size_t buffer_len = MAXPATHLEN * 2;
+ char *buffer = safemalloc(buffer_len);
+
av_extend(fid_fileinfo_av, 64); /* grow them up front. */
av_extend(fid_srclines_av, 64);
av_extend(fid_line_time_av, 64);
if (1) {
- char header[7+1+3+1+3+1+1];
-
- if (NULL == NYTP_gets(in, header, sizeof(header)))
+ if (!NYTP_gets(in, &buffer, &buffer_len))
croak("NYTProf data format error while reading header");
- if (2 != sscanf(header, "NYTProf %d %d\n", &file_major,
&file_minor))
+ if (2 != sscanf(buffer, "NYTProf %d %d\n", &file_major,
&file_minor))
croak("NYTProf data format error while parsing header");
if (file_major != 3)
croak("NYTProf data format version %d.%d is not supported by
NYTProf %s (which expects version %d.%d)",
@@ -4216,37 +4217,36 @@
case NYTP_TAG_ATTRIBUTE:
{
- char text[MAXPATHLEN*2];
- char *value, *end, *text_end;
- if (NULL == NYTP_gets(in, text, sizeof(text)))
+ char *value, *key_end;
+ char *end = NYTP_gets(in, &buffer, &buffer_len);
+ if (NULL == end)
/* probably EOF */
croak("Profile format error reading attribute");
- if ((NULL == (value = strchr(text, '=')))
- || (NULL == (end = strchr(text, '\n')))
- ) {
- logwarn("attribute malformed '%s'\n", text);
+ --end; /* End, as returned, points 1 after the \n */
+ if ((NULL == (value = memchr(buffer, '=', end - buffer))))
{
+ logwarn("attribute malformed '%s'\n", buffer);
continue;
}
- text_end = value++;
+ key_end = value++;
if (cb) {
PUSHMARK(SP);
i = 0;
sv_setpvs(cb_args[i], "ATTRIBUTE");
XPUSHs(cb_args[i++]);
- sv_setpvn(cb_args[i], text, text_end - text);
XPUSHs(cb_args[i++]);
+ sv_setpvn(cb_args[i], buffer, key_end - buffer);
XPUSHs(cb_args[i++]);
sv_setpvn(cb_args[i], value, end - value);
XPUSHs(cb_args[i++]);
PUTBACK;
call_sv(cb, G_DISCARD);
SPAGAIN;
} else {
- store_attrib_sv(aTHX_ attr_hv, text, text_end - text,
newSVpvn(value, end - value));
- }
- if (memEQs(text, text_end - text, "ticks_per_sec")) {
+ store_attrib_sv(aTHX_ attr_hv, buffer, key_end -
buffer, newSVpvn(value, end - value));
+ }
+ if (memEQs(buffer, key_end - buffer, "ticks_per_sec")) {
ticks_per_sec = (unsigned int)atoi(value);
}
- else if (memEQs(text, text_end - text, "nv_size")) {
+ else if (memEQs(buffer, key_end - buffer, "nv_size")) {
if (sizeof(NV) != atoi(value))
croak("Profile data created by incompatible perl
config (NV size %d but ours is %d)",
atoi(value), (int)sizeof(NV));
@@ -4257,8 +4257,8 @@
case NYTP_TAG_COMMENT:
{
- char text[MAXPATHLEN*2];
- if (NULL == NYTP_gets(in, text, sizeof(text)))
+ char *end = NYTP_gets(in, &buffer, &buffer_len);
+ if (!end)
/* probably EOF */
croak("Profile format error reading comment");
@@ -4267,7 +4267,7 @@
i = 0;
sv_setpvs(cb_args[i], "COMMENT"); XPUSHs(cb_args[i++]);
- sv_setpv(cb_args[i], text); XPUSHs(cb_args[i++]);
+ sv_setpvn(cb_args[i], buffer, end - buffer);
XPUSHs(cb_args[i++]);
PUTBACK;
call_sv(cb, G_DISCARD);
@@ -4276,7 +4276,7 @@
}
if (trace_level >= 1)
- logwarn("# %s", text); /* includes \n */
+ logwarn("# %s", buffer); /* includes \n */
break;
}
--
You've received this message because you are subscribed to
the Devel::NYTProf Development User group.
Group hosted at: http://groups.google.com/group/develnytprof-dev
Project hosted at: http://perl-devel-nytprof.googlecode.com
CPAN distribution: http://search.cpan.org/dist/Devel-NYTProf
To post, email: [email protected]
To unsubscribe, email: [email protected]