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]

Reply via email to