[libvirt] [PATCH] Eliminate use of large buffer on stack in virFileMakePath.

virFileMakePath is a recursive function that was creates a buffer PATH_MAX bytes long for each recursion (one recursion for each element in the path). This changes it to have no buffers on the stack, and to allocate just one buffer total, no matter how many elements are in the path. Because the modified algorithm requires a char* to be passed in rather than const char *, it is now 2 functions - a toplevel API function that remains identical in function, and a 2nd helper function called for the recursions, which 1) doesn't allocate anything, and 2) takes a char* arg, so it can modify the contents. src/util/util.c: rewrite virFileMakePath --- src/util/util.c | 58 +++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/util/util.c b/src/util/util.c index 08d74a3..0ce5026 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1443,34 +1443,68 @@ int virDirCreate(const char *path, mode_t mode, } #endif -int virFileMakePath(const char *path) -{ +static int virFileMakePathHelper(char *path) { struct stat st; - char parent[PATH_MAX]; - char *p; + char *p = NULL; int err; if (stat(path, &st) >= 0) return 0; - if (virStrcpyStatic(parent, path) == NULL) - return EINVAL; - - if (!(p = strrchr(parent, '/'))) + if ((p = strrchr(path, '/')) == NULL) return EINVAL; - if (p != parent) { + if (p != path) { *p = '\0'; - if ((err = virFileMakePath(parent))) + err = virFileMakePathHelper(path); + *p = '/'; + if (err != 0) return err; } - if (mkdir(path, 0777) < 0 && errno != EEXIST) + if (mkdir(path, 0777) < 0 && errno != EEXIST) { return errno; - + } return 0; } +int virFileMakePath(const char *path) +{ + struct stat st; + char *parent = NULL; + char *p; + int err = 0; + + if (stat(path, &st) >= 0) + goto cleanup; + + if ((parent = strdup(path)) == NULL) { + err = ENOMEM; + goto cleanup; + } + + if ((p = strrchr(parent, '/')) == NULL) { + err = EINVAL; + goto cleanup; + } + + if (p != parent) { + *p = '\0'; + if ((err = virFileMakePathHelper(parent)) != 0) { + goto cleanup; + } + } + + if (mkdir(path, 0777) < 0 && errno != EEXIST) { + err = errno; + goto cleanup; + } + +cleanup: + VIR_FREE(parent); + return err; +} + /* Build up a fully qualfiied path for a config file to be * associated with a persistent guest or network */ int virFileBuildPath(const char *dir, -- 1.6.6

On Fri, Jan 22, 2010 at 02:04:19PM -0500, Laine Stump wrote:
virFileMakePath is a recursive function that was creates a buffer PATH_MAX bytes long for each recursion (one recursion for each element in the path). This changes it to have no buffers on the stack, and to allocate just one buffer total, no matter how many elements are in the path. Because the modified algorithm requires a char* to be passed in rather than const char *, it is now 2 functions - a toplevel API function that remains identical in function, and a 2nd helper function called for the recursions, which 1) doesn't allocate anything, and 2) takes a char* arg, so it can modify the contents.
src/util/util.c: rewrite virFileMakePath --- src/util/util.c | 58 +++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index 08d74a3..0ce5026 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1443,34 +1443,68 @@ int virDirCreate(const char *path, mode_t mode, } #endif
-int virFileMakePath(const char *path) -{ +static int virFileMakePathHelper(char *path) { struct stat st; - char parent[PATH_MAX]; - char *p; + char *p = NULL; int err;
if (stat(path, &st) >= 0) return 0;
- if (virStrcpyStatic(parent, path) == NULL) - return EINVAL; - - if (!(p = strrchr(parent, '/'))) + if ((p = strrchr(path, '/')) == NULL) return EINVAL;
- if (p != parent) { + if (p != path) { *p = '\0'; - if ((err = virFileMakePath(parent))) + err = virFileMakePathHelper(path); + *p = '/'; + if (err != 0) return err; }
- if (mkdir(path, 0777) < 0 && errno != EEXIST) + if (mkdir(path, 0777) < 0 && errno != EEXIST) { return errno; - + } return 0; }
+int virFileMakePath(const char *path) +{ + struct stat st; + char *parent = NULL; + char *p; + int err = 0; + + if (stat(path, &st) >= 0) + goto cleanup; + + if ((parent = strdup(path)) == NULL) { + err = ENOMEM; + goto cleanup; + } + + if ((p = strrchr(parent, '/')) == NULL) { + err = EINVAL; + goto cleanup; + } + + if (p != parent) { + *p = '\0'; + if ((err = virFileMakePathHelper(parent)) != 0) { + goto cleanup; + } + } + + if (mkdir(path, 0777) < 0 && errno != EEXIST) { + err = errno; + goto cleanup; + } + +cleanup: + VIR_FREE(parent); + return err; +} + /* Build up a fully qualfiied path for a config file to be * associated with a persistent guest or network */ int virFileBuildPath(const char *dir,
ACK, good catch ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Mon, Jan 25, 2010 at 03:36:30PM +0100, Daniel Veillard wrote:
On Fri, Jan 22, 2010 at 02:04:19PM -0500, Laine Stump wrote:
virFileMakePath is a recursive function that was creates a buffer PATH_MAX bytes long for each recursion (one recursion for each element in the path). This changes it to have no buffers on the stack, and to allocate just one buffer total, no matter how many elements are in the path. Because the modified algorithm requires a char* to be passed in rather than const char *, it is now 2 functions - a toplevel API function that remains identical in function, and a 2nd helper function called for the recursions, which 1) doesn't allocate anything, and 2) takes a char* arg, so it can modify the contents.
src/util/util.c: rewrite virFileMakePath
ACK, good catch !
Okay, pushed, thanks ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel Veillard
-
Laine Stump