git » libfiu » commit 2b53d12

preload/posix/modules: Fix stale faked ferror entries.

author Ian Blanes
2018-09-30 09:39:25 UTC
committer Alberto Bertogli
2018-09-30 21:50:42 UTC
parent 0d4f662733045f0e3f6e2936e94518cd4186129e

preload/posix/modules: Fix stale faked ferror entries.

This patch fixes a defect where faked errors for ferror() were not properly cleared. Hash table was not properly cleared and entries were not removed during fclose().

preload/posix/modules/posix.custom.c +56 -3
preload/posix/modules/posix.stdio.mod +4 -3

diff --git a/preload/posix/modules/posix.custom.c b/preload/posix/modules/posix.custom.c
index 9c95293..86c6269 100644
--- a/preload/posix/modules/posix.custom.c
+++ b/preload/posix/modules/posix.custom.c
@@ -289,10 +289,22 @@ static void clear_ferror(void * stream)
 
 			for (;;) {
 				int next_index = (index + 1) % MAX_FERROR_TRACKED_FILES;
-				ferror_hash_table[index] = ferror_hash_table[next_index];
 
-				if (ferror_hash_table[index] == NULL)
-					break;
+				/* Break if next entry is not a collision or if there is
+				 * nothing to copy back. */
+
+				int next_hash_value = (int) (
+					(uintptr_t) ferror_hash_table[next_index]
+					% MAX_FERROR_TRACKED_FILES);
+
+				if (next_index == next_hash_value
+						|| ferror_hash_table[next_index] == NULL) {
+
+				    ferror_hash_table[index] = NULL;
+				    break;
+				}
+
+				ferror_hash_table[index] = ferror_hash_table[next_index];
 
 				index = next_index;
 			}
@@ -421,6 +433,47 @@ void clearerr (FILE *stream)
 	rec_dec();
 }
 
+/* Custom wrapper for fclose() that clears ferror_hash_table. */
+mkwrap_top(int , fclose, (FILE *stream), (stream), (FILE *), (EOF))
+	static const int valid_errnos[] = {
+	  #ifdef EAGAIN
+		EAGAIN,
+	  #endif
+	  #ifdef EBADF
+		EBADF,
+	  #endif
+	  #ifdef EFBIG
+		EFBIG,
+	  #endif
+	  #ifdef EFBIG
+		EFBIG,
+	  #endif
+	  #ifdef EINTR
+		EINTR,
+	  #endif
+	  #ifdef EIO
+		EIO,
+	  #endif
+	  #ifdef ENOMEM
+		ENOMEM,
+	  #endif
+	  #ifdef ENOSPC
+		ENOSPC,
+	  #endif
+	  #ifdef EPIPE
+		EPIPE,
+	  #endif
+	  #ifdef ENXIO
+		ENXIO,
+	  #endif
+	};
+mkwrap_body_errno("posix/stdio/oc/fclose", EOF)
+
+/* We need a custom injection of clear_ferror here to prevent stale entries in
+ * ferror_hash_table. */
+	clear_ferror(stream);
+
+mkwrap_bottom(fclose, (stream))
 
 
 /*
diff --git a/preload/posix/modules/posix.stdio.mod b/preload/posix/modules/posix.stdio.mod
index 61e9567..3055536 100644
--- a/preload/posix/modules/posix.stdio.mod
+++ b/preload/posix/modules/posix.stdio.mod
@@ -17,9 +17,10 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream);
 	valid errnos: EACCES EBADF EINTR EISDIR ELOOP EMFILE ENAMETOOLONG ENFILE ENOENT ENOTDIR ENOSPC ENXIO EOVERFLOW EROFS EBADF EINVAL ENOMEM ENXIO ETXTBSY
 	variants: off64_t
 
-int fclose(FILE *stream);
-	on error: EOF
-	valid errnos: EAGAIN EBADF EFBIG EFBIG EINTR EIO ENOMEM ENOSPC EPIPE ENXIO
+# This one needs to be further instrumented.
+# int fclose(FILE *stream);
+# 	on error: EOF
+# 	valid errnos: EAGAIN EBADF EFBIG EFBIG EINTR EIO ENOMEM ENOSPC EPIPE ENXIO
 
 FILE *fdopen(int fd, const char *mode);
 	on error: NULL