diff options
author | Jonathan Pryor <jpryor@novell.com> | 2005-04-07 18:29:52 +0400 |
---|---|---|
committer | Jonathan Pryor <jpryor@novell.com> | 2005-04-07 18:29:52 +0400 |
commit | 702376ddc120cd545da7355f0ac0a8f9ad205b43 (patch) | |
tree | 83a7f0966d35c5a26082f208e8672ec2358b2437 /support | |
parent | f943410d7265cb08c076852614fe80db63186c77 (diff) |
* errno.c: Use the GNU version of strerror_r if _GNU_SOURCE is defined
(otherwise assume existence of XPG variant). This allows proper
compilation under Red Hat 9.
* fstab.c: protect against users calling setfsent(), setfsent(), ...
endfsent(), which would otherwise leak a FILE handle.
svn path=/trunk/mono/; revision=42642
Diffstat (limited to 'support')
-rw-r--r-- | support/ChangeLog | 8 | ||||
-rw-r--r-- | support/errno.c | 95 | ||||
-rw-r--r-- | support/fstab.c | 3 |
3 files changed, 101 insertions, 5 deletions
diff --git a/support/ChangeLog b/support/ChangeLog index 84ae4c23899..ee4196b63a2 100644 --- a/support/ChangeLog +++ b/support/ChangeLog @@ -1,3 +1,11 @@ +2005-04-07 Zoltan Varga <vargaz@freemail.hu> + + * errno.c: Use the GNU version of strerror_r if _GNU_SOURCE is defined + (otherwise assume existence of XPG variant). This allows proper + compilation under Red Hat 9. + * fstab.c: protect against users calling setfsent(), setfsent(), ... + endfsent(), which would otherwise leak a FILE handle. + 2005-04-05 Zoltan Varga <vargaz@freemail.hu> * mph.h: Apply patch from the freebsd ports collection. diff --git a/support/errno.c b/support/errno.c index a5d215513bb..a28425e03b8 100644 --- a/support/errno.c +++ b/support/errno.c @@ -2,11 +2,6 @@ * <errno.h> wrapper functions. */ -/* to get XPG's strerror_r declaration */ -#undef _GNU_SOURCE -#undef _XOPEN_SOURCE -#define _XOPEN_SOURCE 600 - #include <errno.h> #include <string.h> #include "mph.h" @@ -28,12 +23,102 @@ Mono_Posix_Stdlib_SetLastError (int error_number) } #ifdef HAVE_STRERROR_R + +/* + * There are two versions of strerror_r: + * - the GNU version: char *strerror_r (int errnum, char *buf, size_t n); + * - the XPG version: int strerror_r (int errnum, char *buf, size_t n); + * + * Ideally I could stick with the XPG version, but we need to support + * Red Hat 9, which only supports the GNU version. + * + * Furthermore, I do NOT want to export the GNU version in Mono.Posix.dll, + * as that's supposed to contain *standard* function definitions (give or + * take a few GNU extensions). Portability trumps all. + * + * Consequently, we export the functionality of the XPG version. + * Internally, we se the GNU version if _GNU_SOURCE is defined, otherwise + * we assume that the XPG version is present. + */ + +#ifdef _GNU_SOURCE +#define mph_min(x,y) ((x) <= (y) ? (x) : (y)) + +/* If you pass an invalid errno value to glibc 2.3.2's strerror_r, you get + * back the string "Unknown error" with the error value appended. */ +static const char mph_unknown[] = "Unknown error "; + +/* + * Translate the GNU semantics to the XPG semantics. + * + * From reading the (RH9-using) GLibc 2.3.2 sysdeps/generic/_strerror.c, + * we can say the following: + * - If errnum is a valid error number, a pointer to a constant string is + * returned. Thus, the prototype *lies* (it's not really a char*). + * `buf' is unchanged (WTF?). + * - If errnum is an *invalid* error number, an error message is copied + * into `buf' and `buf' is returned. The error message returned is + * "Unknown error %i", where %i is the input errnum. + * + * Meanwhile, XPG always modifies `buf' if there's enough space, and either + * returns 0 (success) or -1 (error) with errno = EINVAL (bad errnum) or + * ERANGE (`buf' isn't big enough). Also, GLibc 2.3.3 (which has the XPG + * version) first checks the validity of errnum first, then does the copy. + * + * Assuming that the GNU implementation doesn't change much (ha!), we can + * check for EINVAL by comparing the strerror_r return to `buf', OR by + * comparing the return value to "Uknown error". (This assumes that + * strerror_r will always only return the input buffer for errors.) + * + * Check for ERANGE by comparing the string length returned by strerror_r to + * `n'. + * + * Then pray that this actually works... + */ +gint32 +Mono_Posix_Syscall_strerror_r (int errnum, char *buf, mph_size_t n) +{ + char *r; + char ebuf [sizeof(mph_unknown)]; + size_t len; + size_t blen; + + mph_return_if_size_t_overflow (n); + + /* first, check for valid errnum */ + r = strerror_r (errnum, ebuf, sizeof(ebuf)); + len = strlen (r); + + if (r == ebuf || + strncmp (r, mph_unknown, mph_min (len, sizeof(mph_unknown))) == 0) { + errno = EINVAL; + return -1; + } + + /* valid errnum (we hope); is buffer big enough? */ + blen = (size_t) n; + if ((len+1) > blen) { + errno = ERANGE; + return -1; + } + + strncpy (buf, r, len); + buf[len] = '\0'; + + return 0; +} + +#else /* !def _GNU_SOURCE */ + gint32 Mono_Posix_Syscall_strerror_r (int errnum, char *buf, mph_size_t n) { mph_return_if_size_t_overflow (n); return strerror_r (errnum, buf, (size_t) n); } + +#endif /* def _GNU_SOURCE */ + #endif /* def HAVE_STRERROR_R */ G_END_DECLS diff --git a/support/fstab.c b/support/fstab.c index c9ff50547a8..2fb79be2671 100644 --- a/support/fstab.c +++ b/support/fstab.c @@ -174,6 +174,9 @@ etc_fstab; static int setfsent (void) { + /* protect from bad users calling setfsent(), setfsent(), ... endfsent() */ + if (etc_fstab != NULL) + fclose (etc_fstab); etc_fstab = fopen ("/etc/vfstab", "r"); if (etc_fstab != NULL) return 1; |