Skip to content

Conversation

NattyNarwhal
Copy link
Member

Some systems (older NetBSD pre-10, Solaris) may have a non-standard const parameter with iconv. Instead of hardcoding the OS check, move this to a feature check performed by autoconf.

autoconf doesn't have a nicer way of checking this (well, except for AM_ICONV, which is part of gettext and we're presumably not using it), so we have to repeat the function signature and check for it with a mismatched signature.

Tested on NetBSD/amd64 9.4 (for const) and macOS/arm64 14 (for non-const).

@NattyNarwhal
Copy link
Member Author

I added @devnexen and @petk for review since this basically obsoletes GH-16619.

@NattyNarwhal
Copy link
Member Author

I suspect the Windows failure is because AC_DEFINE in the Windows build system will expand an empty string into a "" even if quote is false:

        if (quote && typeof(value) == "string") {
                value = '"' + value.replace(new RegExp('(["\\\\])', "g"), '\\$1') + '"';
        } else if (typeof(value) != "undefined" && value.length == 0) {
                value = '""';
        }

@petk
Copy link
Member

petk commented Nov 20, 2024

I should check this compilation test in more details but something like this can be done here:

  • instead of defining a configuration preprocessor macro, a simple compile definition can be added to CFLAGS only in Autotools.
index 4d0dc36489..4aab9945ca 100644
--- a/ext/iconv/config.m4
+++ b/ext/iconv/config.m4
@@ -83,6 +83,18 @@ int main(void) {
   AS_VAR_IF([php_cv_iconv_errno], [yes],,
     [AC_MSG_FAILURE([The iconv check failed, 'errno' is missing.])])
 
+  dnl Some systems (older NetBSD pre-10, Solaris) may have a non-standard iconv
+  dnl signagure with const parameter. libiconv tends to match the system iconv
+  dnl too.
+  AC_CACHE_CHECK([if iconv has non-standard input parameter],
+    [php_cv_iconv_const],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+      #include <iconv.h>
+      size_t iconv(iconv_t cd, const char **src, size_t *srcleft, char **dst, size_t *dstleft);])],
+    [php_cv_iconv_const=yes],
+    [php_cv_iconv_const=no])])
+  AS_VAR_IF([php_cv_iconv_const], [yes], [ICONV_CFLAGS="-DICONV_CONST=const"])
+
   AC_CACHE_CHECK([if iconv supports //IGNORE], [php_cv_iconv_ignore],
     [AC_RUN_IFELSE([AC_LANG_SOURCE([
 #include <iconv.h>
@@ -120,7 +132,7 @@ int main(void) {
   PHP_NEW_EXTENSION([iconv],
     [iconv.c],
     [$ext_shared],,
-    [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+    [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 $ICONV_CFLAGS])
   PHP_SUBST([ICONV_SHARED_LIBADD])
   PHP_INSTALL_HEADERS([ext/iconv], [php_iconv.h])
 fi
diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c
index 4241b7c288..e1cb5ef3f5 100644
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@ -43,12 +43,8 @@
 #undef iconv
 #endif
 
-#if defined(__NetBSD__)
-// unfortunately, netbsd has still the old non posix conformant signature
-// libiconv tends to match the eventual system's iconv too.
-#define ICONV_CONST const
-#else
-#define ICONV_CONST
+#ifndef ICONV_CONST
+# define ICONV_CONST
 #endif
 
 #include "zend_smart_str.h"

Yes, that GNU lib's iconv check looks like some all-in-one solution with all edge cases considered but it would be also probably a bit over-engineered to add it into PHP: https://git.savannah.gnu.org/cgit/gnulib.git/tree/m4/iconv.m4

@NattyNarwhal
Copy link
Member Author

instead of defining a configuration preprocessor macro, a simple compile definition can be added to CFLAGS only in Autotools.

Good point, I kept it defined in a header since that's what it does normally. This would sidestep the AC_DEFINE weirdness on Windows too.

Yes, that GNU lib's iconv check looks like some all-in-one solution with all edge cases considered but it would be also probably a bit over-engineered to add it into PHP

Right, it also introduces a (build, albeit not runtime) dependency on gettext as well.

@petk
Copy link
Member

petk commented Oct 15, 2025

This has been added via #18933 in the meantime... I guess it should be enough to only do the preprocessor check in the C code as it is done in the PHP-8.5 and master branch?

Edit: I see, there is now also #20089

Yes, then let's go with this PR... I'll recheck it again what's happening.

Edit 2:
No wonder this is so messy. POSIX had a non-consistent documentation in the past :D
In version 2, here is specified without const:
https://pubs.opengroup.org/onlinepubs/7908799/xsh/iconv.h.html

In version 2, here is const:
https://pubs.opengroup.org/onlinepubs/7908799/xsh/iconv.html

Latest version has this fixed (no const)...

Some systems (older NetBSD pre-10, Solaris) may have a non-standard
const parameter with iconv. Instead of hardcoding the OS check, move
this to a feature check performed by autoconf.

autoconf doesn't have a nicer way of checking this (well, except for
AM_ICONV, which is part of gettext and we're presumably not using it),
so we have to repeat the function signature and check for it with a
mismatched signature.
Avoids AC_DEFINE weirdness on Windows.
Copy link
Member

@petk petk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here this works as it should I think. It would be only nicer for the configuration log to adjust this a bit further (to have "yes" or "no" as a result for that cache variable) but it's fine also as it is now.

checking for iconv support... yes
checking for iconv... yes
checking for iconv implementation... glibc
checking if iconv supports errno... yes
checking if iconv input parameter is const (non-standard)... 
checking if iconv supports //IGNORE... no

And I'm not sure if this might cause error in the future on some compilers (meaning, if this is for PHP-8.3 branch and up or for master only), so it's up to you to decide where it needs to be merged. Thanks.
EDIT: Yes, I think PHP-8.3 could be done here (on NetBSD 10 error is emitted and not only a warning).

@petk
Copy link
Member

petk commented Oct 19, 2025

I've remembered also this now: In the issue #20089 by @0-wiz-0

there is suggested to also add the <sys/param.h> header (for NetBSD 10+):

#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif

is this something that needs to be also added here?

@0-wiz-0
Copy link

0-wiz-0 commented Oct 19, 2025

The header is needed if you want to check the __NetBSD_Version__ define, otherwise not.

@petk
Copy link
Member

petk commented Oct 19, 2025

The header is needed if you want to check the __NetBSD_Version__ define, otherwise not.

I see. Thanks for the info. All good then here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants