diff options
author | Ludovic Courtès <ludo@gnu.org> | 2017-12-22 11:12:57 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2018-08-07 11:34:02 +0200 |
commit | a4c4deb5b0cf1633e748eed3e722e3ee74e89242 (patch) | |
tree | 2f5dcb839fe001db1391cd5258069232a6bc72e7 /libguile/posix.c | |
parent | f7e306b8630373d1860093b8c46205523ee7c3a0 (diff) | |
download | guile-a4c4deb5b0cf1633e748eed3e722e3ee74e89242.tar.gz |
Fix 'crypt' deadlock upon error.
* libguile/posix.c (scm_crypt): Take 'scm_i_misc_mutex' right before
calling 'crypt'. Move 'SCM_SYSERROR' call after 'scm_dynwind_end'.
* test-suite/tests/posix.test ("crypt"): New test prefix.
Diffstat (limited to 'libguile/posix.c')
-rw-r--r-- | libguile/posix.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/libguile/posix.c b/libguile/posix.c index 497896b0e..b35dfbd80 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -1,4 +1,4 @@ -/* Copyright 1995-2014,2016,2018 +/* Copyright 1995-2014,2016-2018 Free Software Foundation, Inc. This file is part of Guile. @@ -1936,26 +1936,43 @@ SCM_DEFINE (scm_crypt, "crypt", 2, 0, 0, "crypt(3) library call.") #define FUNC_NAME s_scm_crypt { + int err; SCM ret; char *c_key, *c_salt, *c_ret; scm_dynwind_begin (0); - scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex); c_key = scm_to_locale_string (key); scm_dynwind_free (c_key); c_salt = scm_to_locale_string (salt); scm_dynwind_free (c_salt); + /* Take the lock because 'crypt' uses a static buffer. */ + scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex); + /* The Linux crypt(3) man page says crypt will return NULL and set errno on error. (Eg. ENOSYS if legal restrictions mean it cannot be implemented). */ c_ret = crypt (c_key, c_salt); + if (c_ret == NULL) - SCM_SYSERROR; + /* Note: Do not throw until we've released 'scm_i_misc_mutex' since + this would cause a deadlock down the path. */ + err = errno; + else + { + err = 0; + ret = scm_from_locale_string (c_ret); + } - ret = scm_from_locale_string (c_ret); scm_dynwind_end (); + + if (err != 0) + { + errno = err; + SCM_SYSERROR; + } + return ret; } #undef FUNC_NAME |