diff --git a/main/file.c b/main/file.c
index 37b9e791177b94bee43961159cb9909d3078e880..fb4ede6c88ba486f6fe8a5f03e93517550263286 100644
--- a/main/file.c
+++ b/main/file.c
@@ -1093,27 +1093,27 @@ int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
 	return filehelper(filename, filename2, fmt, ACTION_COPY);
 }
 
-static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
+static int __ast_file_read_dirs(const char *path, ast_file_on_file on_file,
 				void *obj, int max_depth)
 {
 	DIR *dir;
 	struct dirent *entry;
-	size_t size;
 	int res;
 
-	if (!(dir = opendir(ast_str_buffer(*path)))) {
+	if (!(dir = opendir(path))) {
 		ast_log(LOG_ERROR, "Error opening directory - %s: %s\n",
-			ast_str_buffer(*path), strerror(errno));
+			path, strerror(errno));
 		return -1;
 	}
-	size = ast_str_strlen(*path);
 
 	--max_depth;
 
 	res = 0;
 
 	while ((entry = readdir(dir)) != NULL && !errno) {
-		int is_file, is_dir, used_stat = 0;
+		int is_file = 0;
+		int is_dir = 0;
+		RAII_VAR(char *, full_path, NULL, ast_free);
 
 		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
 			continue;
@@ -1128,23 +1128,24 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
 		if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) {
 			is_file = entry->d_type == DT_REG;
 			is_dir = entry->d_type == DT_DIR;
-			ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, NO USE STAT used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat);
 		} else
 #endif
 		{
 			struct stat statbuf;
 
 			/*
-			 * If using the stat function the file needs to be appended to the
-			 * path so it can be found. However, before appending make sure the
-			 * path contains only the directory for this depth level.
+			 * Don't use alloca or we risk blowing out the stack if recursing
+			 * into subdirectories.
 			 */
-			ast_str_truncate(*path, size);
-			ast_str_append(path, 0, "/%s", entry->d_name);
+			full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2);
+			if (!full_path) {
+				return -1;
+			}
+			sprintf(full_path, "%s/%s", path, entry->d_name);
 
-			if (stat(ast_str_buffer(*path), &statbuf)) {
+			if (stat(full_path, &statbuf)) {
 				ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n",
-					ast_str_buffer(*path), strerror(errno));
+					full_path, strerror(errno));
 				/*
 				 * Output an error, but keep going. It could just be
 				 * a broken link and other files could be fine.
@@ -1154,13 +1155,11 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
 
 			is_file = S_ISREG(statbuf.st_mode);
 			is_dir = S_ISDIR(statbuf.st_mode);
-			used_stat = 1;
-			ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, WE USED IT YO used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat);
 		}
 
 		if (is_file) {
 			/* If the handler returns non-zero then stop */
-			if ((res = on_file(ast_str_buffer(*path), entry->d_name, obj))) {
+			if ((res = on_file(path, entry->d_name, obj))) {
 				break;
 			}
 			/* Otherwise move on to next item in directory */
@@ -1168,25 +1167,22 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
 		}
 
 		if (!is_dir) {
-			ast_debug(5, "Skipping %s: not a regular file or directory\n",
-				  ast_str_buffer(*path));
+			ast_debug(5, "Skipping %s: not a regular file or directory\n", full_path);
 			continue;
 		}
 
 		/* Only re-curse into sub-directories if not at the max depth */
 		if (max_depth != 0) {
-			/*
-			 * If the stat function was used then the sub-directory has
-			 * already been appended, otherwise append it.
-			 */
-			ast_log(LOG_VERBOSE, "!###### do dir d_name=%s, path=%s, used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat);
-			if (!used_stat) {
-				ast_str_truncate(*path, size);
-				ast_str_append(path, 0, "/%s", entry->d_name);
-				ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s\n", entry->d_name, ast_str_buffer(*path));
+			if (!full_path) {
+				/* Don't use alloca.  See note above. */
+				full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2);
+				if (!full_path) {
+					return -1;
+				}
+				sprintf(full_path, "%s/%s", path, entry->d_name);
 			}
 
-			if ((res = __ast_file_read_dirs(path, on_file, obj, max_depth))) {
+			if ((res = __ast_file_read_dirs(full_path, on_file, obj, max_depth))) {
 				break;
 			}
 		}
@@ -1196,7 +1192,7 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
 
 	if (!res && errno) {
 		ast_log(LOG_ERROR, "Error while reading directories - %s: %s\n",
-			ast_str_buffer(*path), strerror(errno));
+			path, strerror(errno));
 		res = -1;
 	}
 
@@ -1217,27 +1213,20 @@ AST_MUTEX_DEFINE_STATIC(read_dirs_lock);
 
 int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
 {
-	struct ast_str *path;
 	int res;
 
-	if (!(path = ast_str_create(256))) {
-		return -1;
-	}
-
-	ast_str_set(&path, 0, "%s", dir_name);
 	errno = 0;
 
 #if !defined(__GLIBC__)
 	ast_mutex_lock(&read_dirs_lock);
 #endif
 
-	res = __ast_file_read_dirs(&path, on_file, obj, max_depth);
+	res = __ast_file_read_dirs(dir_name, on_file, obj, max_depth);
 
 #if !defined(__GLIBC__)
 	ast_mutex_unlock(&read_dirs_lock);
 #endif
 
-	ast_free(path);
 	return res;
 }
 
diff --git a/tests/test_file.c b/tests/test_file.c
index 64bad9218d9139d615e4ff3f95b2676870309aeb..bb8a99584d13139c71d8165ebcab4fe83761bdbe 100644
--- a/tests/test_file.c
+++ b/tests/test_file.c
@@ -21,7 +21,10 @@
 	<support_level>core</support_level>
  ***/
 
+
 #include "asterisk.h"
+#include <sys/stat.h>
+#include <stdio.h>
 
 #include "asterisk/file.h"
 #include "asterisk/paths.h"
@@ -115,6 +118,17 @@ static char *test_files_get_one(struct _filenames *filenames, int num)
 
 static int handle_find_file(const char *dir_name, const char *filename, void *obj)
 {
+	struct stat statbuf;
+	char *full_path = ast_alloca(strlen(dir_name) + strlen(filename) + 2);
+
+	sprintf(full_path, "%s/%s", dir_name, filename);
+
+	errno = 0;
+	if (stat(full_path, &statbuf)) {
+		ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n",
+			full_path, strerror(errno));
+		return 0;
+	}
 	/* obj contains the name of the file we are looking for */
 	return strcmp(obj, filename) ? 0 : FOUND;
 }