Device Test Error Conditions - EINTR

In short, how do you unit test fulfill an error condition such as EINTR on a system call.

One specific example I'm working on, which may be one case in itself, is to need to call fclose again when it returns EOF with (errno == EINTR). The behavior depends on the implementation of fclose:

// Given an open FILE *fp while (fclose(fp)==EOF && errno==EINTR) { errno = 0; } 

This call may be unsafe if fp is freed when an EINTR occurs. How can I check error handling when (errno == EINTR)?

+6
c unit-testing errno
source share
8 answers

In this particular case, it is not safe to call fclose () again, since the C standard says that the stream is disconnected from the file (and becomes undefined), even if the call fails.

+4
source share

Use the construction of function pointers to abstract system functions. Replace the call to flcose (fp) with something like sys-> fclose (fp). In unit test, create an fclose implementation that always returns EINTR, then set sys-> fclose to this version.

+3
source share

Looking at the source code of the Linux kernel, I can not find any drivers that even return EINTR when closing the file.

If you needed to reproduce this event, you can write your own driver in Linux to return -EINTR in the .release method. Take a look at the sample code from O'Reilly Linux Device Drivers. The scull project is one of the easiest. You would change it like this:

 int scull_release(struct inode *inode, struct file *filp) { return -EINTR; } 

Again, grepping through the linux source tree, I cannot find a driver that returns EINTR when closing.

EDIT - OK, it looks like a fuse - perhaps a user-space file system. This is used for things like sshfs. However, the edge.

+3
source share

I don’t think there is an easy way to verify this on my own.

An EINTR will be generated if the fclose operation is interrupted by a signal. This means that fclose was in the background thread that received the signal when it was processing a close request.

Good luck trying to reproduce this set of circumstances.

+2
source share

As Chris suggests, temporarily replace the calls with "real" fclose() your own implementation defined in the unit test code. Your implementation may do something simple:

 int my_fclose(FILE *fp) { errno = EINTR; return EOF; } 

But, as the fizzer points out, you shouldn't call fclose() again, as the behavior is undefined, so you don't even need to check the condition.

Another question is to ask if you really need to worry about it; if your application code had to block all possible signals (except SIGKILL and SIGSTOP) during your fclose() , then you would not receive an EINTR and you should not have to worry at all.

+1
source share

This is how I would experience it, just for testing, since the physicist reminded that calling fclose() twice unsafe.

You can override fclose() (or any other libc function) in your program with your own behavior. On Unix-like systems, the linker does not complain - I have never tried Windows, but with cygwin. Of course, this does not allow your other tests to use real fclose() , so such a test should be placed in a separate test executable.

Here is an all-in-one example with minunit .

 #include <errno.h> #include <stdio.h> #include <stdbool.h> /* from minunit.h : http://www.jera.com/techinfo/jtns/jtn002.html */ #define mu_assert(message, test) do { if (!(test)) return message; } while (0) #define mu_run_test(test) do { char *message = test(); tests_run++; \ if (message) return message; } while (0) int tests_run = 0; bool fclose_shall_fail_on_EINTR = false; //--- our implemention of fclose() int fclose(FILE *fp) { if (fclose_shall_fail_on_EINTR) { errno = EINTR; fclose_shall_fail_on_EINTR = false; //--- reset for next call return EOF; } else { return 0; } } //--- this is the "production" function to be tested void uninterruptible_close(FILE *fp) { // Given an open FILE *fp while (fclose(fp)==EOF && errno==EINTR) { errno = 0; } } char *test_non_interrupted_fclose(void) { FILE *theHandle = NULL; //--- don't care here uninterruptible_close(theHandle); mu_assert("test fclose wo/ interruption", 0 == errno); return 0; } char *test_interrupted_fclose(void) { FILE *theHandle = NULL; //--- don't care here fclose_shall_fail_on_EINTR = true; uninterruptible_close(theHandle); mu_assert("test fclose wo/ interruption", 0 == errno); return 0; } char *test_suite(void) { mu_run_test(test_non_interrupted_fclose); mu_run_test(test_interrupted_fclose); return 0; } int main(int ac, char **av) { char *result = test_suite(); printf("number of tests run: %d\n", tests_run); if (result) { printf("FAIL: %s\n", result); } return 0 != result; } 
+1
source share

Um, I think you all ignore something very important.

fclose () cannot return an EINTR. There is also no fopen (), fwrite (), fread (), or any of the standard C I / O functions.

Only if you are mistaken in low-level I / O calls such as open (2), write (2) and select (2) that you need to handle EINTR.

Read the [funny] man pages

+1
source share

I think that there may be a problem with the simultaneous processing of signals and confirmation of error conditions.

+1
source share

All Articles