diff --git a/contrib/pg_upgrade/file.c b/contrib/pg_upgrade/file.c
index 1dd3722142c9e83c1ec228099c3a3fd302a2179b..962cbaccc53f9d6788b69d151a36e36fb4e3260f 100644
--- a/contrib/pg_upgrade/file.c
+++ b/contrib/pg_upgrade/file.c
@@ -224,13 +224,12 @@ copy_file(const char *srcfile, const char *dstfile, bool force)
 /*
  * load_directory()
  *
- * Returns count of files that meet the selection criteria coded in
- * the function pointed to by selector.  Creates an array of pointers
- * to dirent structures.  Address of array returned in namelist.
+ * Read all the file names in the specified directory, and return them as
+ * an array of "struct dirent" pointers.  The array address is returned in
+ * *namelist, and the function result is the count of file names.
  *
- * Note that the number of dirent structures needed is dynamically
- * allocated using realloc.  Realloc can be inefficient if invoked a
- * large number of times.
+ * To free the result data, free each namelist array member, then free the
+ * namelist array itself.
  */
 int
 load_directory(const char *dirname, struct dirent *** namelist)
@@ -238,43 +237,48 @@ load_directory(const char *dirname, struct dirent *** namelist)
 	DIR		   *dirdesc;
 	struct dirent *direntry;
 	int			count = 0;
-	int			name_num = 0;
+	int			allocsize = 64;
 	size_t		entrysize;
 
-	if ((dirdesc = opendir(dirname)) == NULL)
-		pg_log(PG_FATAL, "could not open directory \"%s\": %s\n", dirname, getErrorText(errno));
+	*namelist = (struct dirent **)
+		pg_malloc(allocsize * sizeof(struct dirent *));
 
-	*namelist = NULL;
+	if ((dirdesc = opendir(dirname)) == NULL)
+		pg_log(PG_FATAL, "could not open directory \"%s\": %s\n",
+			   dirname, getErrorText(errno));
 
-	while ((direntry = readdir(dirdesc)) != NULL)
+	while (errno = 0, (direntry = readdir(dirdesc)) != NULL)
 	{
-		count++;
-
-		*namelist = (struct dirent **) realloc((void *) (*namelist),
-						(size_t) ((name_num + 1) * sizeof(struct dirent *)));
-
-		if (*namelist == NULL)
+		if (count >= allocsize)
 		{
-			closedir(dirdesc);
-			return -1;
+			allocsize *= 2;
+			*namelist = (struct dirent **)
+				pg_realloc(*namelist, allocsize * sizeof(struct dirent *));
 		}
 
-		entrysize = sizeof(struct dirent) - sizeof(direntry->d_name) +
+		entrysize = offsetof(struct dirent, d_name) +
 			strlen(direntry->d_name) + 1;
 
-		(*namelist)[name_num] = (struct dirent *) malloc(entrysize);
-
-		if ((*namelist)[name_num] == NULL)
-		{
-			closedir(dirdesc);
-			return -1;
-		}
+		(*namelist)[count] = (struct dirent *) pg_malloc(entrysize);
 
-		memcpy((*namelist)[name_num], direntry, entrysize);
+		memcpy((*namelist)[count], direntry, entrysize);
 
-		name_num++;
+		count++;
 	}
 
+#ifdef WIN32
+	/*
+	 * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
+	 * released version
+	 */
+	if (GetLastError() == ERROR_NO_MORE_FILES)
+		errno = 0;
+#endif
+
+	if (errno)
+		pg_log(PG_FATAL, "could not read directory \"%s\": %s\n",
+			   dirname, getErrorText(errno));
+
 	closedir(dirdesc);
 
 	return count;
diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h
index 3274227a0a3d516f8ae2b06bfa9fe0152d497e69..4f74c217eed1a9688552cb9719f9e9e75b11febb 100644
--- a/contrib/pg_upgrade/pg_upgrade.h
+++ b/contrib/pg_upgrade/pg_upgrade.h
@@ -429,7 +429,8 @@ prep_status(const char *fmt,...)
 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
 void		check_ok(void);
 char	   *pg_strdup(const char *s);
-void	   *pg_malloc(int size);
+void	   *pg_malloc(size_t size);
+void	   *pg_realloc(void *ptr, size_t size);
 void		pg_free(void *ptr);
 const char *getErrorText(int errNum);
 unsigned int str2uint(const char *str);
diff --git a/contrib/pg_upgrade/util.c b/contrib/pg_upgrade/util.c
index 6977663b63aabca1fff8ff6703461742815278e3..76cd20b23d70869cafa77c1036f559a5d9b1d107 100644
--- a/contrib/pg_upgrade/util.c
+++ b/contrib/pg_upgrade/util.c
@@ -183,7 +183,7 @@ get_user_info(char **user_name)
 
 
 void *
-pg_malloc(int n)
+pg_malloc(size_t n)
 {
 	void	   *p = malloc(n);
 
@@ -193,6 +193,17 @@ pg_malloc(int n)
 	return p;
 }
 
+void *
+pg_realloc(void *ptr, size_t n)
+{
+	void	   *p = realloc(ptr, n);
+
+	if (p == NULL)
+		pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
+
+	return p;
+}
+
 
 void
 pg_free(void *p)