Package: zlib1g-dev
Version: 1:1.2.3.4.dfsg-3
Severity: wishlist
Hi,
zlib’s gzFile interface provides no way I can see to recover from
EINTR.
Context:
When library code makes syscalls, I live in constant danger that the
application may have installed a signal handler with SA_RESTART
disabled. If the system call is interrupted by a signal, depending
on the application, one of three behaviors would be appropriate:
a. if the goal is to walk the stack after a SIGINT and clean up
before exiting, my function should return quickly to the
application with an error;
b. if the interruption is just a side effect of something else (maybe
this is a System V-based system and the application writer forgot
to use SA_RESTART, or maybe the interruption was intended for some
other thread), my function should restart the call and return with
success once the operation succeeds.
c. if the interruption (perhaps from SIGIO) represents some
high-priority job that needs to be done soon, my function should
let that job finish and then resume.
The usual way to handle this is to either pick one or leave it to the
application by returning with enough information to resume the
operation later.
In my case, the library was libdpkg, and the chosen behavior was
option b. Simple, right?
char buffer[BUFSZ];
int actualread;
gzFile gzfile = gzdopen(fd_in, "r");
for (;;) {
int actualread = gzread(gzfile, &buffer[0], sizeof(buffer));
if (actualread < 0) {
int err;
const char *errmsg = gzerror(gzfile, &err);
if (err == Z_ERRNO && errno == EINTR)
continue;
errx(_("read error: %s"), errmsg);
}
if (actualread == 0) /* EOF! */
break;
write(fd_out, &buffer[0], actualread);
}
int err = gzclose(gzfile);
// handle error or return
Unfortunately, when zlib hits its first EINTR, two bad things happen:
- the error indicator for the underlying stdio stream is set;
- the error number for the gzFile is set
and there is no way to undo either. So in fact this is an infinite
loop.
Thoughts about fix:
I would love it if zlib just cleared the error indicator before each
potentially resumable operation (gzread(), gzwrite(), gzseek()). But
probably someone out there is relying on zlib _not_ to do that, as
part of his implementation of error recovery plan a above, so such a
change would be dangerous.
Better would be to add a new gzclearerr() function to allow the two
error indicators to be explicitly cleared.
void Z_EXPORT gzclearerr (file)
gzFile file;
{
gz_stream *s = (gz_stream*)file;
if (s == NULL) return;
s->z_err = Z_OK;
clearerr(s->file);
}
What do you think?
Jonathan
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]