From eae348ab0aa1e698b1885c62b23ccf944e613b0d Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Mon, 16 Dec 2019 11:53:18 +1300 Subject: [PATCH] Merge allocations in MSVC dirent compat code Make dir->name a one element array member and over-allocate the struct so there's enough room for its actual size, which means we only need one malloc() call. (cherry picked from commit 6c00a75804e8a8605f5d548cb87accc519ee0ac4) --- xapian-core/common/msvc_dirent.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/xapian-core/common/msvc_dirent.cc b/xapian-core/common/msvc_dirent.cc index 41648da29..88d333054 100644 --- a/xapian-core/common/msvc_dirent.cc +++ b/xapian-core/common/msvc_dirent.cc @@ -11,6 +11,8 @@ end of the directory is reached. 2018-04-01 Fix handle to be intptr_t not long to avoid truncation with WIN64 (where long is still 32 bits). + 2019-12-16 Make dir->name a one element array member and over-allocate + the struct so there's enough room for its actual size. Copyright Kevlin Henney, 1997, 2003. All rights reserved. @@ -43,7 +45,7 @@ struct DIR intptr_t handle; /* -1 for failed rewind */ struct _finddata_t info; struct dirent result; /* d_name null iff first time */ - char *name; /* null-terminated char string */ + char name[1];/* null-terminated char string */ }; DIR *opendir(const char *name) @@ -53,13 +55,18 @@ DIR *opendir(const char *name) if(name && name[0]) { size_t base_length = strlen(name); - const char *all = /* search pattern must end with suitable wildcard */ - strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + /* 2 allows for appending `/` and `*`. We don't need to allow + * 1 for the nul here as there will always be at least one byte + * in struct DIR for name (plus padding). */ + size_t alloc_size = sizeof(DIR) + base_length + 2; - if((dir = (DIR *) malloc(sizeof *dir)) != 0 && - (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + if((dir = (DIR *) malloc(alloc_size)) != 0) { - strcat(strcpy(dir->name, name), all); + memcpy(dir->name, name, base_length); + /* Search pattern must end with suitable wildcard */ + if(name[base_length - 1] != '/' && name[base_length - 1] != '\\') + dir->name[base_length++] = '/'; + memcpy(dir->name + base_length, "*", 2); if((dir->handle = _findfirst(dir->name, &dir->info)) != -1) { @@ -67,7 +74,7 @@ DIR *opendir(const char *name) } else /* rollback */ { - free(dir->name); + /* _findfirst() will have set errno suitably. */ free(dir); dir = 0; } @@ -98,7 +105,6 @@ int closedir(DIR *dir) result = _findclose(dir->handle); } - free(dir->name); free(dir); } -- 2.11.4.GIT