git: bdf56c40600a - main - www/node2{2,4,6}: Use bundled merve to avoid loading two simdutfs
Date: Sun, 18 Oct 2026 00:19:42 UTC
The branch main has been updated by dch:
URL: https://cgit.FreeBSD.org/ports/commit/?id=bdf56c40600a34c93ce4badad821d77ad8025535
commit bdf56c40600a34c93ce4badad821d77ad8025535
Author: Dave Cottlehuber <dch@FreeBSD.org>
AuthorDate: 2026-10-17 21:33:46 +0000
Commit: Dave Cottlehuber <dch@FreeBSD.org>
CommitDate: 2026-10-18 00:19:17 +0000
www/node2{2,4,6}: Use bundled merve to avoid loading two simdutfs
node dies with SIGBUS (signal 10) the first time it lexes the exports
of a CommonJS module, e.g. early in any `npm install`, for example
www/tailwindcss4 fails to build, reporting "*** Signal 10".
Running lldb inside poudriere build, because we get a core dump:
frame #0 libsimdutf.so.36 simdutf::detail::find(...) +77: jmpq *%rax
frame #1 libmerve.so.1 lexer::CJSLexer::addReexport(...)
...
frame #6 node node::cjs_lexer::Parse(...)
rax = 0x4444444443434343 ("CCCCDDDD", string data)
This appears to be caused by having two different simdutf versions
loaded into one process:
- node is configured with --shared-merve but not --shared-simdutf, so
it statically includes its own simdutf (7.7.0 in 26.10.0, from
deps/v8/third_party/simdutf), and exports those symbols for native
addons (`nm -D node | grep -c simdutf` = 686).
- devel/merve is built with MERVE_USE_SIMDUTF=ON and links the system
libsimdutf.so.36 from converters/simdutf (9.2.1).
Both define simdutf::get_active_implementation() and friends. rtld
searches the executable first, so references made from inside
libsimdutf.so.36 can bind to node's 7.7.0 copy. The 9.2.1 code then
reads a 7.7.0 implementation object with its own layout, loads string
data where it expects a function pointer, and jumps to it.
I tried dropping shared-merve from the port and corresponding
LIB_DEPENDS, and now things work again.
Alternatively both --shared-merve and --shared-simdutf could be used,
but this may result in behavioural changes for consumers. This should
probably be done in the next minor nodejs version bump.
Approved by: portmgr (fix blanket)
MFH: 2026Q4
PR: 299170
Reported by: poudriere
Sponsored by: SkunkWerks, GmbH
---
www/node22/Makefile | 7 ++++++-
www/node24/Makefile | 14 ++++++++++----
www/node26/Makefile | 14 ++++++++++----
3 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/www/node22/Makefile b/www/node22/Makefile
index b335f838c430..e5fa7af1a437 100644
--- a/www/node22/Makefile
+++ b/www/node22/Makefile
@@ -1,7 +1,7 @@
PORTNAME= node
PORTVERSION= ${NODEJS_PORTVERSION}
DISTVERSIONPREFIX= v
-PORTREVISION= 1
+PORTREVISION= 2
CATEGORIES= www
MASTER_SITES= https://nodejs.org/dist/v${PORTVERSION}/
PKGNAMESUFFIX= ${PORTVERSION:R:R}
@@ -119,6 +119,11 @@ post-configure:
post-install:
${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/node
+# Fail if two simdutf copies end up in one process (node exports its bundled
+# simdutf; a DSO linking the system libsimdutf.so, e.g. libmerve, then binds
+# to the wrong one and CJS export lexing SIGBUSes). Importing a CommonJS
+# module from ESM runs that lexer; stdin avoids a temp file.
+ ${ECHO_CMD} 'exports.ok = 1' | ${STAGEDIR}${PREFIX}/bin/node --input-type=module -e 'import "/dev/stdin"'
post-install-BUNDLED_SSL-on:
cd ${STAGEDIR}${PREFIX} && ${FIND} include/node/openssl/ -type f >> ${TMPPLIST}
diff --git a/www/node24/Makefile b/www/node24/Makefile
index 7daf88f8f17b..bcb88f6bcdac 100644
--- a/www/node24/Makefile
+++ b/www/node24/Makefile
@@ -1,7 +1,7 @@
PORTNAME= node
PORTVERSION= ${NODEJS_PORTVERSION}
DISTVERSIONPREFIX= v
-PORTREVISION= 1
+PORTREVISION= 3
CATEGORIES= www
MASTER_SITES= https://nodejs.org/dist/v${PORTVERSION}/
PKGNAMESUFFIX= ${PORTVERSION:R:R}
@@ -26,7 +26,6 @@ LIB_DEPENDS= libada.so:devel/libada \
libhdr_histogram.so:graphics/hdr_histogram \
libicui18n.so:devel/icu \
libllhttp.so:www/llhttp \
- libmerve.so:devel/merve \
libnbytes.so:www/nbytes \
libnghttp2.so:www/libnghttp2 \
libnghttp3.so:www/libnghttp3 \
@@ -40,6 +39,10 @@ RUN_DEPENDS= corepack>=0:www/corepack
USES= compiler:c++20-lang gmake localbase pkgconfig python:build shebangfix tar:xz
+# merve stays bundled: devel/merve links the system libsimdutf, while node
+# bundles and exports its own simdutf. rtld binds libsimdutf's internal calls
+# to node's copy, the dispatch tables disagree, and CJS export lexing jumps
+# to garbage (SIGBUS). Revisit together with --shared-simdutf.
CONFIGURE_ARGS= --prefix=${PREFIX:S|^${DESTDIR}||} \
--shared-ada \
--shared-brotli \
@@ -48,7 +51,6 @@ CONFIGURE_ARGS= --prefix=${PREFIX:S|^${DESTDIR}||} \
--shared-hdr-histogram \
--shared-http-parser \
--shared-libuv \
- --shared-merve \
--shared-nbytes \
--shared-nghttp2 \
--shared-nghttp3 \
@@ -107,7 +109,6 @@ post-patch:
@${RM} -r ${WRKSRC}/deps/histogram/
@${RM} -r ${WRKSRC}/deps/icu-small/
@${RM} -r ${WRKSRC}/deps/llhttp/
- @${RM} -r ${WRKSRC}/deps/merve/
@${RM} -r ${WRKSRC}/deps/nbytes/
@${RM} -r ${WRKSRC}/deps/nghttp2/
@${RM} -r ${WRKSRC}/deps/ngtcp2/
@@ -130,6 +131,11 @@ post-configure:
post-install:
${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/node
+# Fail if two simdutf copies end up in one process (node exports its bundled
+# simdutf; a DSO linking the system libsimdutf.so, e.g. libmerve, then binds
+# to the wrong one and CJS export lexing SIGBUSes). Importing a CommonJS
+# module from ESM runs that lexer; stdin avoids a temp file.
+ ${ECHO_CMD} 'exports.ok = 1' | ${STAGEDIR}${PREFIX}/bin/node --input-type=module -e 'import "/dev/stdin"'
post-install-BUNDLED_SSL-on:
cd ${STAGEDIR}${PREFIX} && ${FIND} include/node/openssl/ -type f >> ${TMPPLIST}
diff --git a/www/node26/Makefile b/www/node26/Makefile
index 9005c32c007b..608fdb17926b 100644
--- a/www/node26/Makefile
+++ b/www/node26/Makefile
@@ -1,7 +1,7 @@
PORTNAME= node
PORTVERSION= ${NODEJS_PORTVERSION}
DISTVERSIONPREFIX= v
-PORTREVISION= 1
+PORTREVISION= 3
CATEGORIES= www
MASTER_SITES= https://nodejs.org/dist/v${PORTVERSION}/
PKGNAMESUFFIX= ${PORTVERSION:R:R}
@@ -29,7 +29,6 @@ LIB_DEPENDS= libada.so:devel/libada \
libicui18n.so:devel/icu \
libLIEF.so:devel/lief \
libllhttp.so:www/llhttp \
- libmerve.so:devel/merve \
libnbytes.so:www/nbytes \
libnghttp2.so:www/libnghttp2 \
libnghttp3.so:www/libnghttp3 \
@@ -43,6 +42,10 @@ RUN_DEPENDS= corepack>=0:www/corepack
USES= compiler:c++20-lang gmake localbase pkgconfig python:build shebangfix tar:xz
+# merve stays bundled: devel/merve links the system libsimdutf, while node
+# bundles and exports its own simdutf. rtld binds libsimdutf's internal calls
+# to node's copy, the dispatch tables disagree, and CJS export lexing jumps
+# to garbage (SIGBUS). Revisit together with --shared-simdutf.
CONFIGURE_ARGS= --prefix=${PREFIX:S|^${DESTDIR}||} \
--shared-ada \
--shared-brotli \
@@ -54,7 +57,6 @@ CONFIGURE_ARGS= --prefix=${PREFIX:S|^${DESTDIR}||} \
--shared-http-parser \
--shared-libuv \
--shared-lief \
- --shared-merve \
--shared-nbytes \
--shared-nghttp2 \
--shared-nghttp3 \
@@ -112,7 +114,6 @@ post-patch:
@${RM} -r ${WRKSRC}/deps/icu-small/
@${RM} -r ${WRKSRC}/deps/LIEF/
@${RM} -r ${WRKSRC}/deps/llhttp/
- @${RM} -r ${WRKSRC}/deps/merve/
@${RM} -r ${WRKSRC}/deps/nbytes/
@${RM} -r ${WRKSRC}/deps/nghttp2/
@${RM} -r ${WRKSRC}/deps/ngtcp2/
@@ -136,6 +137,11 @@ post-configure:
post-install:
${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/node
+# Fail if two simdutf copies end up in one process (node exports its bundled
+# simdutf; a DSO linking the system libsimdutf.so, e.g. libmerve, then binds
+# to the wrong one and CJS export lexing SIGBUSes). Importing a CommonJS
+# module from ESM runs that lexer; stdin avoids a temp file.
+ ${ECHO_CMD} 'exports.ok = 1' | ${STAGEDIR}${PREFIX}/bin/node --input-type=module -e 'import "/dev/stdin"'
post-install-BUNDLED_SSL-on:
cd ${STAGEDIR}${PREFIX} && ${FIND} include/node/openssl/ -type f >> ${TMPPLIST}