summaryrefslogtreecommitdiff
path: root/main/utils.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2014-07-03 11:27:25 +0000
committerMatthew Jordan <mjordan@digium.com>2014-07-03 11:27:25 +0000
commitd1c6a9e69ed7fedfe2b61e8cd99093011573f587 (patch)
tree14b0573dcfeb8e0da03a3e1c7c9ba5a32d431757 /main/utils.c
parenta69e0cd32a208d077a3b0fcb2d7d21846a711a89 (diff)
main/untils: Prevent potential infinite loop in ast_careful_fwrite
A loop in ast_careful_fwrite exists that will continually attempt to write to a file stream, even in the presence of EAGAIN/EINTR errors. However, if a connection that uses ast_careful_fwrite closes suddenly, ast_careful_fwrite's call to fflush may return EAGAIN/EINTER along with EOF. A subsequent call to fflush will return EOF but not clear errno, resulting in an infinite loop. This patch clears errno after it is detected and handled the loop, such that any subsequent call to fflush will not get erroneously stuck. Review: https://reviewboard.asterisk.org/r/3704 #ASTERISK-23984 #close Reported by: Steve Davies patches: fflush_loop_fix uploaded by one47 (License 5012) ........ Merged revisions 417797 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 417798 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 417799 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417800 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/utils.c')
-rw-r--r--main/utils.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/main/utils.c b/main/utils.c
index 467f9f13c..b32e71b6c 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1411,11 +1411,18 @@ int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeout
}
}
+ errno = 0;
while (fflush(f)) {
if (errno == EAGAIN || errno == EINTR) {
+ /* fflush() does not appear to reset errno if it flushes
+ * and reaches EOF at the same time. It returns EOF with
+ * the last seen value of errno, causing a possible loop.
+ * Also usleep() to reduce CPU eating if it does loop */
+ errno = 0;
+ usleep(1);
continue;
}
- if (!feof(f)) {
+ if (errno && !feof(f)) {
/* Don't spam the logs if it was just that the connection is closed. */
ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
}