Hi,
I've been trying to cleanup uClibc test-suite failures on ARC and when debugging test-double ran into a totally unrelated issue where it fails as
| testing double (without inline functions) | Failure: finite (0): errno set to 11, expected 0 (unchanged)
Turns out the test harness uses asprintf() which seems to be fudging errno causing test harness to erroneously declare failure:
Here's a simple test case which shows the problem:
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <errno.h>
void main(void) { const char *this_func = "finite"; char *test_name;
errno = 0; if (asprintf (&test_name, "%s (%s)", this_func, "my-str") == -1) abort ();
printf("%d\n", errno); // <-- prints 11 }
The errno unconditionally being set to EAGAIN seems to have been introduced in commit 568ceebf6adfc58c64a95133311268db6 ("Fix infinite loop when fopencookie custom write returns 0 on error") bakc in 2016.
+#define __STDIO_STREAM_CUSTOM_WRITE_FUNC(S, ARGS...) \ + if (__STDIO_STREAM_IS_CUSTOM((S))) { \ + _IO_cookie_file_t *cfile = (_IO_cookie_file_t *) (S); \ + if (cfile->__gcs.write == NULL) { \ + __set_errno(EINVAL); \ + return -1; \ + } \ + __set_errno(EAGAIN); \ + ssize_t w = cfile->__gcs.write(cfile->__cookie, ##ARGS); \ + return (w == 0 ? -1 : w); \ + }
I don't understand all the logic but shouldn't it be set after __gcs.write() call ?
Thx, -Vineet
* Vineet Gupta:
Here's a simple test case which shows the problem:
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <errno.h>
void main(void) { const char *this_func = "finite"; char *test_name;
errno = 0; if (asprintf (&test_name, "%s (%s)", this_func, "my-str") == -1) abort (); printf("%d\n", errno); // <-- prints 11
}
The errno unconditionally being set to EAGAIN seems to have been introduced in commit 568ceebf6adfc58c64a95133311268db6 ("Fix infinite loop when fopencookie custom write returns 0 on error") bakc in 2016.
For functions specified by standards, successful calls can alter errno unless specified otherwise. asprintf is not a standardized function, but it is reasonable to expect that a similar rule applies.
On 12/14/19 1:37 AM, Florian Weimer wrote:
- Vineet Gupta:
Here's a simple test case which shows the problem:
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <errno.h>
void main(void) { const char *this_func = "finite"; char *test_name;
errno = 0; if (asprintf (&test_name, "%s (%s)", this_func, "my-str") == -1) abort (); printf("%d\n", errno); // <-- prints 11
}
The errno unconditionally being set to EAGAIN seems to have been introduced in commit 568ceebf6adfc58c64a95133311268db6 ("Fix infinite loop when fopencookie custom write returns 0 on error") bakc in 2016.
For functions specified by standards, successful calls can alter errno unless specified otherwise. asprintf is not a standardized function, but it is reasonable to expect that a similar rule applies.
Right, but ...
1. Don't those standards specify the exact errno for specific scenarios and that typically errno won't be changed to !0 if there was no error. 2. The EAGAIN being returned can be seen as "leaking" out of internal details of the ensuing call stack. 3. This breaks the way uclibc test harness works. It clears the errno at the start of a call sequence and in the end when notices the change it trips. It expects the errno to be set (or not set) by the math routines and asprintf changing them trips it. glibc test harness is no different - it would have failed in similar way had similar errno fudging existed there !
At any rate the fix is simple to only change errno in case of a failure.
Thx, -Vineet