Skip to content

Commit 66809c0

Browse files
authored
Fix usage of reentrant functions in ext/posix (#13921)
- It's not necessarily an error of sysconf(_SC_GETPW_R_SIZE_MAX) returns -1, as specified by posix (and the musl implementation always returns -1). Pick an initial buffer size in this case. - Reentrant variants return an error number an may not set errno - Implement retry logic for ttyname_r() - Fix retry logic for getpwnam_r() (pw would be NULL after the first try) - Test retry logic by setting the initial buffer size to 1 in debug builds
1 parent ea927ca commit 66809c0

File tree

1 file changed

+55
-23
lines changed

1 file changed

+55
-23
lines changed

ext/posix/posix.c

+55-23
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ PHP_FUNCTION(posix_ttyname)
447447
int fd;
448448
#if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
449449
zend_long buflen;
450+
int err;
450451
#endif
451452

452453
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -465,12 +466,23 @@ PHP_FUNCTION(posix_ttyname)
465466
#if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
466467
buflen = sysconf(_SC_TTY_NAME_MAX);
467468
if (buflen < 1) {
468-
RETURN_FALSE;
469+
buflen = 32;
469470
}
471+
#if ZEND_DEBUG
472+
/* Test retry logic */
473+
buflen = 1;
474+
#endif
470475
p = emalloc(buflen);
471476

472-
if (ttyname_r(fd, p, buflen)) {
473-
POSIX_G(last_error) = errno;
477+
try_again:
478+
err = ttyname_r(fd, p, buflen);
479+
if (err) {
480+
if (err == ERANGE) {
481+
buflen *= 2;
482+
p = erealloc(p, buflen);
483+
goto try_again;
484+
}
485+
POSIX_G(last_error) = err;
474486
efree(p);
475487
RETURN_FALSE;
476488
}
@@ -719,6 +731,7 @@ PHP_FUNCTION(posix_getgrnam)
719731
struct group gbuf;
720732
long buflen;
721733
char *buf;
734+
int err;
722735
#endif
723736

724737
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -728,19 +741,24 @@ PHP_FUNCTION(posix_getgrnam)
728741
#if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
729742
buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
730743
if (buflen < 1) {
731-
RETURN_FALSE;
744+
buflen = 1024;
732745
}
746+
#if ZEND_DEBUG
747+
/* Test retry logic */
748+
buflen = 1;
749+
#endif
733750
buf = emalloc(buflen);
734751
try_again:
735752
g = &gbuf;
736753

737-
if (getgrnam_r(name, g, buf, buflen, &g) || g == NULL) {
738-
if (errno == ERANGE) {
754+
err = getgrnam_r(name, g, buf, buflen, &g);
755+
if (err || g == NULL) {
756+
if (err == ERANGE) {
739757
buflen *= 2;
740758
buf = erealloc(buf, buflen);
741759
goto try_again;
742760
}
743-
POSIX_G(last_error) = errno;
761+
POSIX_G(last_error) = err;
744762
efree(buf);
745763
RETURN_FALSE;
746764
}
@@ -768,7 +786,7 @@ PHP_FUNCTION(posix_getgrgid)
768786
{
769787
zend_long gid;
770788
#if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
771-
int ret;
789+
int err;
772790
struct group _g;
773791
struct group *retgrptr = NULL;
774792
long grbuflen;
@@ -784,20 +802,24 @@ PHP_FUNCTION(posix_getgrgid)
784802

785803
grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
786804
if (grbuflen < 1) {
787-
RETURN_FALSE;
805+
grbuflen = 1024;
788806
}
807+
#if ZEND_DEBUG
808+
/* Test retry logic */
809+
grbuflen = 1;
810+
#endif
789811

790812
grbuf = emalloc(grbuflen);
791813

792814
try_again:
793-
ret = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr);
794-
if (ret || retgrptr == NULL) {
795-
if (errno == ERANGE) {
815+
err = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr);
816+
if (err || retgrptr == NULL) {
817+
if (err == ERANGE) {
796818
grbuflen *= 2;
797819
grbuf = erealloc(grbuf, grbuflen);
798820
goto try_again;
799821
}
800-
POSIX_G(last_error) = ret;
822+
POSIX_G(last_error) = err;
801823
efree(grbuf);
802824
RETURN_FALSE;
803825
}
@@ -849,6 +871,7 @@ PHP_FUNCTION(posix_getpwnam)
849871
struct passwd pwbuf;
850872
long buflen;
851873
char *buf;
874+
int err;
852875
#endif
853876

854877
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -858,20 +881,25 @@ PHP_FUNCTION(posix_getpwnam)
858881
#if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
859882
buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
860883
if (buflen < 1) {
861-
RETURN_FALSE;
884+
buflen = 1024;
862885
}
886+
#if ZEND_DEBUG
887+
/* Test retry logic */
888+
buflen = 1;
889+
#endif
863890
buf = emalloc(buflen);
864-
pw = &pwbuf;
865891

866892
try_again:
867-
if (getpwnam_r(name, pw, buf, buflen, &pw) || pw == NULL) {
868-
if (errno == ERANGE) {
893+
pw = &pwbuf;
894+
err = getpwnam_r(name, pw, buf, buflen, &pw);
895+
if (err || pw == NULL) {
896+
if (err == ERANGE) {
869897
buflen *= 2;
870898
buf = erealloc(buf, buflen);
871899
goto try_again;
872900
}
873901
efree(buf);
874-
POSIX_G(last_error) = errno;
902+
POSIX_G(last_error) = err;
875903
RETURN_FALSE;
876904
}
877905
#else
@@ -902,7 +930,7 @@ PHP_FUNCTION(posix_getpwuid)
902930
struct passwd *retpwptr = NULL;
903931
long pwbuflen;
904932
char *pwbuf;
905-
int ret;
933+
int err;
906934
#endif
907935
struct passwd *pw;
908936

@@ -913,19 +941,23 @@ PHP_FUNCTION(posix_getpwuid)
913941
#if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
914942
pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
915943
if (pwbuflen < 1) {
916-
RETURN_FALSE;
944+
pwbuflen = 1024;
917945
}
946+
#if ZEND_DEBUG
947+
/* Test retry logic */
948+
pwbuflen = 1;
949+
#endif
918950
pwbuf = emalloc(pwbuflen);
919951

920952
try_again:
921-
ret = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr);
922-
if (ret || retpwptr == NULL) {
953+
err = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr);
954+
if (err || retpwptr == NULL) {
923955
if (errno == ERANGE) {
924956
pwbuflen *= 2;
925957
pwbuf = erealloc(pwbuf, pwbuflen);
926958
goto try_again;
927959
}
928-
POSIX_G(last_error) = ret;
960+
POSIX_G(last_error) = err;
929961
efree(pwbuf);
930962
RETURN_FALSE;
931963
}

0 commit comments

Comments
 (0)