Skip to content

Commit 6f1c108

Browse files
committed
ext/gettext/gettext.c: fudge bindtextdomain() return value on musl
According to POSIX, bindtextdomain() returns "the implementation- defined default directory pathname used by the gettext family of functions" when its second parameter is NULL (i.e. when you are querying the directory corresponding to some text domain and that directory has not yet been set). But musl does not do this: when no directory has been set, it consults an environment variable (that itself may be unset), and there is no default: if (!libc.secure) path = getenv("MUSL_LOCPATH"); /* FIXME: add a default path? */ Worse, the musl bindtextdomain(..., NULL) query always returns NULL, even when MUSL_LOCPATH is set. This is segfaulting bindtextdomain() in PHP because it tries to RETURN_STRING on the NULL pointer that the C function returns. To work around this, we check for a NULL return from the C function, and then try to return the value of MUSL_LOCPATH. (This still isn't perfect, because MUSL_LOCPATH can contain multiple paths, but at least it's a string.) If MUSL_LOCPATH is unset, we RETURN_FALSE to indicate failure (there's really no default) rather than segfaulting. This partially addresses GH #13696
1 parent fa8c6a5 commit 6f1c108

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

ext/gettext/gettext.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#ifdef HAVE_LIBINTL
2424

2525
#include <stdio.h>
26+
#include <stdlib.h> /* secure_getenv() */
2627
#include <locale.h>
2728
#include "ext/standard/info.h"
2829
#include "php_gettext.h"
@@ -180,7 +181,7 @@ PHP_FUNCTION(dcgettext)
180181
PHP_FUNCTION(bindtextdomain)
181182
{
182183
zend_string *domain, *dir = NULL;
183-
char *retval, dir_name[MAXPATHLEN];
184+
char *retval, dir_name[MAXPATHLEN], *btd_result, *musl_locpath;
184185

185186
ZEND_PARSE_PARAMETERS_START(1, 2)
186187
Z_PARAM_STR(domain)
@@ -191,7 +192,28 @@ PHP_FUNCTION(bindtextdomain)
191192
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
192193

193194
if (dir == NULL) {
194-
RETURN_STRING(bindtextdomain(ZSTR_VAL(domain), NULL));
195+
btd_result = bindtextdomain(ZSTR_VAL(domain), NULL);
196+
if (btd_result == NULL) {
197+
/* It's not POSIX compliant, but musl returns
198+
* NULL rather than an implementation-defined
199+
* default directory when no directory was
200+
* previously bound. Technically there is no
201+
* default directory on musl, but the user can
202+
* provide one (or more) via the MUSL_LOCPATH
203+
* environment variable. For lack of a better
204+
* idea, we return MUSL_LOCPATH if it is set,
205+
* even though it may contain multiple paths.
206+
* We use secure_getenv() because the musl docs
207+
* say that MUSL_LOCPATH will be ignored in the
208+
* scenarios where secure_getenv() will return
209+
* NULL rather than the value of the variable. */
210+
musl_locpath = secure_getenv("MUSL_LOCPATH");
211+
if (musl_locpath == NULL) {
212+
RETURN_FALSE;
213+
}
214+
RETURN_STRING(musl_locpath);
215+
}
216+
RETURN_STRING(btd_result);
195217
}
196218

197219
if (ZSTR_LEN(dir) != 0 && !zend_string_equals_literal(dir, "0")) {

0 commit comments

Comments
 (0)