From fe0d12d4f82269096f8d0cffc51ca9590814c284 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Fri, 26 Jun 2020 12:59:32 +0200
Subject: [PATCH 821/863] libmount: (parser) fix memory leak on error before
 end-of-file

Let's simplify the loop where we add FS to the table. The optimization
for recoverable errors is a fragile overkill. The new code always
allocates and unrefs FS for each loop.

Addresses: https://github.com/karelzak/util-linux/pull/1068
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 libmount/src/fs.c        |  2 +-
 libmount/src/tab_parse.c | 49 ++++++++++++++++++++++++++----------------------
 2 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/libmount/src/fs.c b/libmount/src/fs.c
index bcc8273..52f937a 100644
--- a/libmount/src/fs.c
+++ b/libmount/src/fs.c
@@ -39,7 +39,7 @@ struct libmnt_fs *mnt_new_fs(void)
 
 	fs->refcount = 1;
 	INIT_LIST_HEAD(&fs->ents);
-	/*DBG(FS, ul_debugobj(fs, "alloc"));*/
+	DBG(FS, ul_debugobj(fs, "alloc"));
 	return fs;
 }
 
diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
index 3b52f6b..e3f30c2 100644
--- a/libmount/src/tab_parse.c
+++ b/libmount/src/tab_parse.c
@@ -703,7 +703,6 @@ static int __table_parse_stream(struct libmnt_table *tb, FILE *f, const char *fi
 	int rc = -1;
 	int flags = 0;
 	pid_t tid = -1;
-	struct libmnt_fs *fs = NULL;
 	struct libmnt_parser pa = { .line = 0 };
 
 	assert(tb);
@@ -723,19 +722,25 @@ static int __table_parse_stream(struct libmnt_table *tb, FILE *f, const char *fi
 	if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0)
 		flags = MNT_FS_KERNEL;
 
-	while (!feof(f)) {
-		if (!fs) {
-			fs = mnt_new_fs();
-			if (!fs)
-				goto err;
+	do {
+		struct libmnt_fs *fs;
+
+		if (feof(f)) {
+			DBG(TAB, ul_debugobj(tb, "end-of-file"));
+			break;
 		}
+		fs = mnt_new_fs();
+		if (!fs)
+			goto err;
 
+		/* parse */
 		rc = mnt_table_parse_next(&pa, tb, fs);
 
-		if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data))
-			rc = 1;	/* filtered out by callback... */
+		if (rc != 0 && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data))
+			rc = 1;	/* error filtered out by callback... */
 
-		if (!rc) {
+		/* add to the table */
+		if (rc == 0) {
 			rc = mnt_table_add_fs(tb, fs);
 			fs->flags |= flags;
 
@@ -746,21 +751,21 @@ static int __table_parse_stream(struct libmnt_table *tb, FILE *f, const char *fi
 			}
 		}
 
-		if (rc) {
-			if (rc > 0) {
-				mnt_reset_fs(fs);
-				assert(fs->refcount == 1);
-				continue;	/* recoverable error, reuse fs*/
-			}
+		/* remove refernece (or deallocate on error) */
+		mnt_unref_fs(fs);
 
-			mnt_unref_fs(fs);
-			if (feof(f))
-				break;
-			goto err;		/* fatal error */
+		/* recoverable error */
+		if (rc > 0) {
+			DBG(TAB, ul_debugobj(tb, "recoverable error (continue)"));
+			continue;
 		}
-		mnt_unref_fs(fs);
-		fs = NULL;
-	}
+
+		/* fatal errors */
+		if (rc < 0 && !feof(f)) {
+			DBG(TAB, ul_debugobj(tb, "fatal error"));
+			goto err;
+		}
+	} while (1);
 
 	DBG(TAB, ul_debugobj(tb, "%s: stop parsing (%d entries)",
 				filename, mnt_table_get_nents(tb)));
-- 
1.8.3.1

