Bladeren bron

Merge pull request #882 from civetweb/pr-fix-scan-dir

handle_directory_request() might leak memory
bel2125 5 jaren geleden
bovenliggende
commit
fe1eef775b
1 gewijzigde bestanden met toevoegingen van 32 en 35 verwijderingen
  1. 32 35
      src/civetweb.c

+ 32 - 35
src/civetweb.c

@@ -9701,7 +9701,10 @@ scan_directory(struct mg_connection *conn,
 				                strerror(ERRNO));
 				                strerror(ERRNO));
 			}
 			}
 			de.file_name = dp->d_name;
 			de.file_name = dp->d_name;
-			cb(&de, data);
+			if (cb(&de, data)) {
+				/* stopped */
+				break;
+			}
 		}
 		}
 		(void)mg_closedir(dirp);
 		(void)mg_closedir(dirp);
 	}
 	}
@@ -9781,44 +9784,37 @@ remove_directory(struct mg_connection *conn, const char *dir)
 
 
 struct dir_scan_data {
 struct dir_scan_data {
 	struct de *entries;
 	struct de *entries;
-	unsigned int num_entries;
-	unsigned int arr_size;
+	size_t num_entries;
+	size_t arr_size;
 };
 };
 
 
 
 
-/* Behaves like realloc(), but frees original pointer on failure */
-static void *
-realloc2(void *ptr, size_t size)
-{
-	void *new_ptr = mg_realloc(ptr, size);
-	if ((new_ptr == NULL) && (size > 0)) {
-		mg_free(ptr);
-	}
-	return new_ptr;
-}
-
-
 #if !defined(NO_FILESYSTEMS)
 #if !defined(NO_FILESYSTEMS)
 static int
 static int
 dir_scan_callback(struct de *de, void *data)
 dir_scan_callback(struct de *de, void *data)
 {
 {
 	struct dir_scan_data *dsd = (struct dir_scan_data *)data;
 	struct dir_scan_data *dsd = (struct dir_scan_data *)data;
-
-	if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
+	struct de *entries = dsd->entries;
+
+	if ((entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
+		entries =
+		    (struct de *)mg_realloc(entries,
+		                            dsd->arr_size * 2 * sizeof(entries[0]));
+		if (entries == NULL) {
+			/* stop scan */
+			return 1;
+		}
+		dsd->entries = entries;
 		dsd->arr_size *= 2;
 		dsd->arr_size *= 2;
-		dsd->entries =
-		    (struct de *)realloc2(dsd->entries,
-		                          dsd->arr_size * sizeof(dsd->entries[0]));
 	}
 	}
-	if (dsd->entries == NULL) {
-		/* TODO(lsm, low): propagate an error to the caller */
-		dsd->num_entries = 0;
-	} else {
-		dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
-		dsd->entries[dsd->num_entries].file = de->file;
-		dsd->entries[dsd->num_entries].conn = de->conn;
-		dsd->num_entries++;
+	entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
+	if (entries[dsd->num_entries].file_name == NULL) {
+		/* stop scan */
+		return 1;
 	}
 	}
+	entries[dsd->num_entries].file = de->file;
+	entries[dsd->num_entries].conn = de->conn;
+	dsd->num_entries++;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -9827,13 +9823,17 @@ dir_scan_callback(struct de *de, void *data)
 static void
 static void
 handle_directory_request(struct mg_connection *conn, const char *dir)
 handle_directory_request(struct mg_connection *conn, const char *dir)
 {
 {
-	unsigned int i;
+	size_t i;
 	int sort_direction;
 	int sort_direction;
 	struct dir_scan_data data = {NULL, 0, 128};
 	struct dir_scan_data data = {NULL, 0, 128};
 	char date[64], *esc, *p;
 	char date[64], *esc, *p;
 	const char *title;
 	const char *title;
 	time_t curtime = time(NULL);
 	time_t curtime = time(NULL);
 
 
+	if (!conn) {
+		return;
+	}
+
 	if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
 	if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
 		mg_send_http_error(conn,
 		mg_send_http_error(conn,
 		                   500,
 		                   500,
@@ -9845,10 +9845,6 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
 
 
 	gmt_time_string(date, sizeof(date), &curtime);
 	gmt_time_string(date, sizeof(date), &curtime);
 
 
-	if (!conn) {
-		return;
-	}
-
 	esc = NULL;
 	esc = NULL;
 	title = conn->request_info.local_uri;
 	title = conn->request_info.local_uri;
 	if (title[strcspn(title, "&<>")]) {
 	if (title[strcspn(title, "&<>")]) {
@@ -9912,7 +9908,7 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
 	/* Sort and print directory entries */
 	/* Sort and print directory entries */
 	if (data.entries != NULL) {
 	if (data.entries != NULL) {
 		qsort(data.entries,
 		qsort(data.entries,
-		      (size_t)data.num_entries,
+		      data.num_entries,
 		      sizeof(data.entries[0]),
 		      sizeof(data.entries[0]),
 		      compare_dir_entries);
 		      compare_dir_entries);
 		for (i = 0; i < data.num_entries; i++) {
 		for (i = 0; i < data.num_entries; i++) {
@@ -12481,7 +12477,8 @@ print_dav_dir_entry(struct de *de, void *data)
 	if (!de || !conn
 	if (!de || !conn
 	    || !print_props(
 	    || !print_props(
 	           conn, conn->request_info.local_uri, de->file_name, &de->file)) {
 	           conn, conn->request_info.local_uri, de->file_name, &de->file)) {
-		return -1;
+		/* stop scan */
+		return 1;
 	}
 	}
 	return 0;
 	return 0;
 }
 }