Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ocaml for openSUSE:Factory checked 
in at 2026-09-28 10:36:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ocaml (Old)
 and      /work/SRC/openSUSE:Factory/.ocaml.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ocaml"

Mon Sep 28 10:36:43 2026 rev:97 rq:1380249 version:5.5.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/ocaml/ocaml.changes      2026-08-12 
16:11:07.326966982 +0200
+++ /work/SRC/openSUSE:Factory/.ocaml.new.383539/ocaml.changes  2026-09-28 
10:37:23.243172534 +0200
@@ -1,0 +2,6 @@
+Thu Sep 17 17:17:17 UTC 2026 - [email protected]
+
+- update to version 5.5.1
+  See included Changes for benefits and breaking changes
+
+-------------------------------------------------------------------

Old:
----
  ocaml-5.5.0.tar.xz

New:
----
  ocaml-5.5.1.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ocaml.spec ++++++
--- /var/tmp/diff_new_pack.ak2JhH/_old  2026-09-28 10:37:24.166211133 +0200
+++ /var/tmp/diff_new_pack.ak2JhH/_new  2026-09-28 10:37:24.167211174 +0200
@@ -45,7 +45,7 @@
 %bcond_without suse_ocaml_use_rpm_license_macro
 
 Name:           ocaml
-Version:        5.5.0
+Version:        5.5.1
 Release:        0
 Summary:        OCaml Compiler and Programming Environment
 %if %{with suse_ocaml_use_rpm_license_macro}

++++++ _service ++++++
--- /var/tmp/diff_new_pack.ak2JhH/_old  2026-09-28 10:37:24.200212554 +0200
+++ /var/tmp/diff_new_pack.ak2JhH/_new  2026-09-28 10:37:24.204212722 +0200
@@ -166,7 +166,7 @@
     <param name="exclude">utils/HACKING.adoc</param>
     <param name="exclude">utils/dune</param>
     <param name="filename">ocaml</param>
-    <param name="revision">f5238509da6029a44ba0eb648f5dff7d9c89f519</param>
+    <param name="revision">46e1c324fb9e9f21f52c9cc3399020f7ef8b9b91</param>
     <param name="scm">git</param>
     <param name="submodules">disable</param>
     <param name="url">https://github.com/ocaml/ocaml.git</param>

++++++ ocaml-5.5.0.tar.xz -> ocaml-5.5.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/Changes new/ocaml-5.5.1/Changes
--- old/ocaml-5.5.0/Changes     2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/Changes     2026-09-04 13:16:34.000000000 +0200
@@ -1,3 +1,78 @@
+OCaml 5.5.1 (4 September 2026)
+------------------------------
+
+### Bug fixes:
+
+- #14891, #14982: fix scope error leading to an erroneous typechecking for
+  non-dependent application of module-dependent function in presence of
+  dependent first-class module types:
+  ```ocaml
+  module type T = sig module type S end
+  let f (module M:T) (m: (module M.S)) = m
+  module type P = sig type 'a t end
+  let error =
+    f (module struct module type S = P end) (module List)
+  ````
+  (Florian Angeletti, report by Hazem ElMasry, review by Gabriel Scherer)
+
+- #14872: harden loading of bytecode executable files against corrupted
+  or malicious files having 2^29 TOC entries or more.
+  (Xavier Leroy, review by Nicolás Ojeda Bär)
+
+- #14883, #14884: fix Windows cross-compilation with older mingw32-gcc versions
+  (Brian Ward, review by Antonin Décimo and Stefan Muenzel)
+
+- #14881, #14882: fix printing of external types that are subject to module
+  constraints.
+  (Stefan Muenzel, review by Florian Angeletti)
+
+- #14871, #14914: Ignore OCAMLTOP_INCLUDE_PATH during the build.
+  (David Allsopp, report by Andreas Rossberg, review by Florian Angeletti)
+
+- #14901, #14923: Fix the generated installation script to cope with macOS's
+  geriatric version of bash when executing in opam's sandbox.
+  (David Allsopp, report by Julian Fondren and Sacha-Élie Ayoun, investigation
+   and initial fix by Kate Deplaix, review by Florian Angeletti)
+
+- #14933: Respect `sysconf(_SC_SIGSTKSZ)` when choosing the size for the
+  alternate signal stack, avoiding fatal errors when linked against musl libc 
on
+  some Intel CPUs.
+  (Nat Mote, review by Florian Angeletti and Miod Vallat)
+
+- #14940, fix a memory leak in the OCaml runtime by bounding the size
+  of the internal cache of stacks.
+  (Vesa Karvonen, Florian Angeletti, review by Gabriel Scherer)
+
+- #14966: add the missing EV_MINOR_EPHE_CLEAN constructor to
+  Runtime_events.runtime_phase, introduced in #13643. The runtime has emitted
+  this phase since 5.4, when a minor collection has to clean locked ephemerons,
+  but the OCaml type had no constructor for it, so consumers were handed an
+  out-of-range value and crashed when matching on it.
+  (Tim McGilchrist, review by Florian Angeletti)
+
+- #14969: Fix the units of the runtime events counter 
EV_C_MINOR_ALLOCATED_WORDS
+  to report as the number of words of minor heap consumed, including headers.
+  (Tim McGilchrist, review by Nicolás Ojeda Bär)
+
+- #14989: Improve build reproducibility by letting only otherlibs/{str,unix}
+  build their own .cmi and .cmx. The generic %.cmi/%.cmx rules of the root
+  Makefile were racing with them under make -j and recorded a different source
+  path, which changed the interface digest (and, through it, most other 
compiled
+  artefacts) as well as the debug info packed into str.a and unix.a.
+  (Bernhard M. Wiedemann, review by David Allsopp and Stefan Muenzel)
+
+- #15019: `Marshal.from_{string,bytes}`: guard against overflow in
+  the computation of the total data length.
+  (Xavier Leroy, report by Akshay Singh, review by Nicolás Ojeda Bär
+  and Antonin Décimo)
+
+- #15029: Fix a regression on Windows where an OCaml thread that never
+  yielded voluntarily would keep the runtime lock forever, so that the other
+  threads of its domain never ran. Preemptive switching between systhreads had
+  no effect; only explicit calls to `Thread.yield` or blocking sections would
+  let other threads run.
+  (Nicolás Ojeda Bär, report by Daniel Larraz, review by Antonin Décimo)
+
 OCaml 5.5.0 (19 June 2026)
 -------------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/Makefile new/ocaml-5.5.1/Makefile
--- old/ocaml-5.5.0/Makefile    2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/Makefile    2026-09-04 13:16:34.000000000 +0200
@@ -2196,6 +2196,12 @@
 otherlibs/unix/unix.cma: otherlibraries
 otherlibs/str/str.cma: otherlibraries
 
+# Root-directory targets depend on these .cmi/.cmx via .depend. The empty
+# recipes keep the generic %.cmi/%.cmx rules from racing with the otherlibs
+# sub-make, which records a different source path and digest in the artefacts.
+otherlibs/unix/unix.cmi otherlibs/str/str.cmi: otherlibraries ;
+otherlibs/unix/unix.cmx otherlibs/str/str.cmx: otherlibrariesopt ;
+
 debugger/%: VPATH += otherlibs/unix otherlibs/dynlink
 
 ocamldebug_COMPILER_SOURCES = $(addprefix toplevel/, \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/Makefile.common 
new/ocaml-5.5.1/Makefile.common
--- old/ocaml-5.5.0/Makefile.common     2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/Makefile.common     2026-09-04 13:16:34.000000000 +0200
@@ -867,3 +867,9 @@
 export MSYS := $(strip \
   $(filter-out winsymlinks winsymlinks:%, $(MSYS)) winsymlinks:nativestrict)
 endif
+
+# Invocations of the compilers during the build use -nostdlib which ensures 
that
+# existing installations and the OCAMLLIB/CAMLLIB environment variables don't
+# affect the build. There isn't an equivalent flag for the toplevel's
+# OCAMLTOP_INCLUDE_PATH, so it's scrubbed from the environment instead.
+unexport OCAMLTOP_INCLUDE_PATH
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/VERSION new/ocaml-5.5.1/VERSION
--- old/ocaml-5.5.0/VERSION     2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/VERSION     2026-09-04 13:16:34.000000000 +0200
@@ -1,4 +1,4 @@
-5.5.0
+5.5.1
 
 # Starting with OCaml 4.14, although the version string that appears above is
 # still correct and this file can thus still be used to figure it out,
Binary files old/ocaml-5.5.0/boot/ocamlc and new/ocaml-5.5.1/boot/ocamlc differ
Binary files old/ocaml-5.5.0/boot/ocamllex and new/ocaml-5.5.1/boot/ocamllex 
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/build-aux/ocaml_version.m4 
new/ocaml-5.5.1/build-aux/ocaml_version.m4
--- old/ocaml-5.5.0/build-aux/ocaml_version.m4  2026-06-19 13:32:53.000000000 
+0200
+++ new/ocaml-5.5.1/build-aux/ocaml_version.m4  2026-09-04 13:16:34.000000000 
+0200
@@ -35,7 +35,7 @@
 m4_define([OCAML__VERSION_MAJOR], [5])
 m4_define([OCAML__VERSION_MINOR], [5])
 m4_define([OCAML__RELEASE_NUMBER], [21])
-m4_define([OCAML__VERSION_PATCHLEVEL], [0])
+m4_define([OCAML__VERSION_PATCHLEVEL], [1])
 
 # Note that the OCAML__VERSION_EXTRA string defined below is always empty
 # for officially-released versions of OCaml.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/configure new/ocaml-5.5.1/configure
--- old/ocaml-5.5.0/configure   2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/configure   2026-09-04 13:16:34.000000000 +0200
@@ -56,7 +56,7 @@
   fi
 fi
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for OCaml 5.5.0.
+# Generated by GNU Autoconf 2.71 for OCaml 5.5.1.
 #
 # Report bugs to <[email protected]>.
 #
@@ -677,8 +677,8 @@
 # Identity of this package.
 PACKAGE_NAME='OCaml'
 PACKAGE_TARNAME='ocaml'
-PACKAGE_VERSION='5.5.0'
-PACKAGE_STRING='OCaml 5.5.0'
+PACKAGE_VERSION='5.5.1'
+PACKAGE_STRING='OCaml 5.5.1'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL='http://www.ocaml.org'
 
@@ -1653,7 +1653,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures OCaml 5.5.0 to adapt to many kinds of systems.
+\`configure' configures OCaml 5.5.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1720,7 +1720,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of OCaml 5.5.0:";;
+     short | recursive ) echo "Configuration of OCaml 5.5.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1923,7 +1923,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-OCaml configure 5.5.0
+OCaml configure 5.5.1
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2580,7 +2580,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by OCaml $as_me 5.5.0, which was
+It was created by OCaml $as_me 5.5.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3343,8 +3343,8 @@
 
 
 
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configuring OCaml version 5.5.0" 
>&5
-printf "%s\n" "$as_me: Configuring OCaml version 5.5.0" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configuring OCaml version 5.5.1" 
>&5
+printf "%s\n" "$as_me: Configuring OCaml version 5.5.1" >&6;}
 
 # It's important for the setting up of defaults and the checking of the
 # --with-relative-libdir option to know whether the user specified --libdir.
@@ -3444,7 +3444,7 @@
 
 
 
-VERSION=5.5.0
+VERSION=5.5.1
 
 OCAML_DEVELOPMENT_VERSION=false
 
@@ -3454,7 +3454,7 @@
 
 OCAML_VERSION_MINOR=5
 
-OCAML_VERSION_PATCHLEVEL=0
+OCAML_VERSION_PATCHLEVEL=1
 
 OCAML_VERSION_EXTRA=
 
@@ -3695,15 +3695,15 @@
 
 printf "%s\n" "#define OCAML_VERSION_MINOR 5" >>confdefs.h
 
-printf "%s\n" "#define OCAML_VERSION_PATCHLEVEL 0" >>confdefs.h
+printf "%s\n" "#define OCAML_VERSION_PATCHLEVEL 1" >>confdefs.h
 
 printf "%s\n" "#define OCAML_VERSION_ADDITIONAL \"\"" >>confdefs.h
 
   printf "%s\n" "#define OCAML_VERSION_EXTRA \"\"" >>confdefs.h
 
-printf "%s\n" "#define OCAML_VERSION 50500" >>confdefs.h
+printf "%s\n" "#define OCAML_VERSION 50501" >>confdefs.h
 
-printf "%s\n" "#define OCAML_VERSION_STRING \"5.5.0\"" >>confdefs.h
+printf "%s\n" "#define OCAML_VERSION_STRING \"5.5.1\"" >>confdefs.h
 
 printf "%s\n" "#define OCAML_RELEASE_NUMBER 21" >>confdefs.h
 
@@ -4587,13 +4587,13 @@
     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the installed 
OCaml compiler can build the cross compiler" >&5
 printf %s "checking if the installed OCaml compiler can build the cross 
compiler... " >&6; }
     already_installed_version="$(ocamlc -vnum)"
-    if test x"5.5.0" = x"$already_installed_version"
+    if test x"5.5.1" = x"$already_installed_version"
 then :
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (5.5.0)" >&5
-printf "%s\n" "yes (5.5.0)" >&6; }
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (5.5.1)" >&5
+printf "%s\n" "yes (5.5.1)" >&6; }
 else $as_nop
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (5.5.0 vs 
$already_installed_version)" >&5
-printf "%s\n" "no (5.5.0 vs $already_installed_version)" >&6; }
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (5.5.1 vs 
$already_installed_version)" >&5
+printf "%s\n" "no (5.5.1 vs $already_installed_version)" >&6; }
       as_fn_error $? "exiting" "$LINENO" 5
 fi
     cross_compiler=true
@@ -25143,7 +25143,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by OCaml $as_me 5.5.0, which was
+This file was extended by OCaml $as_me 5.5.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25216,7 +25216,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-OCaml config.status 5.5.0
+OCaml config.status 5.5.1
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/ocaml-variants.opam 
new/ocaml-5.5.1/ocaml-variants.opam
--- old/ocaml-5.5.0/ocaml-variants.opam 2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/ocaml-variants.opam 2026-09-04 13:16:34.000000000 +0200
@@ -1,7 +1,7 @@
 opam-version: "2.0"
-version: "5.5.0"
+version: "5.5.1"
 license: "LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception"
-synopsis: "Official release of OCaml 5.5.0"
+synopsis: "Official release of OCaml 5.5.1"
 maintainer: "[email protected]"
 authors: [
   "Xavier Leroy"
@@ -16,7 +16,7 @@
 bug-reports: "https://github.com/ocaml/ocaml/issues";
 depends: [
   # This is OCaml 5.5.0
-  "ocaml" {= "5.5.0" & post}
+  "ocaml" {= "5.5.1" & post}
 
   # General base- packages
   "base-unix" {post}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/otherlibs/runtime_events/runtime_events.ml 
new/ocaml-5.5.1/otherlibs/runtime_events/runtime_events.ml
--- old/ocaml-5.5.0/otherlibs/runtime_events/runtime_events.ml  2026-06-19 
13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/otherlibs/runtime_events/runtime_events.ml  2026-09-04 
13:16:34.000000000 +0200
@@ -95,6 +95,7 @@
 | EV_COMPACT_FORWARD
 | EV_COMPACT_RELEASE
 | EV_EMPTY_MINOR
+| EV_MINOR_EPHE_CLEAN
 
 type lifecycle =
   EV_RING_START
@@ -206,6 +207,7 @@
   | EV_COMPACT_FORWARD -> "compaction_forward"
   | EV_COMPACT_RELEASE -> "compaction_release"
   | EV_EMPTY_MINOR -> "empty_minor"
+  | EV_MINOR_EPHE_CLEAN -> "minor_ephe_clean"
 
 let lifecycle_name lifecycle =
   match lifecycle with
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/otherlibs/runtime_events/runtime_events.mli 
new/ocaml-5.5.1/otherlibs/runtime_events/runtime_events.mli
--- old/ocaml-5.5.0/otherlibs/runtime_events/runtime_events.mli 2026-06-19 
13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/otherlibs/runtime_events/runtime_events.mli 2026-09-04 
13:16:34.000000000 +0200
@@ -469,6 +469,13 @@
 This includes time spent trying to become stop-the-world leader.
 @since 5.4
 *)
+| EV_MINOR_EPHE_CLEAN
+(**
+Event spanning the cleaning of ephemerons whose keys were locked during a minor
+GC. Keys that were promoted are updated to their new location and ephemerons
+whose keys were collected are emptied.
+@since 5.4
+*)
 
 (** Lifecycle events for Runtime_events and domains. *)
 type lifecycle =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/otherlibs/unix/system.c 
new/ocaml-5.5.1/otherlibs/unix/system.c
--- old/ocaml-5.5.0/otherlibs/unix/system.c     2026-06-19 13:32:53.000000000 
+0200
+++ new/ocaml-5.5.1/otherlibs/unix/system.c     2026-09-04 13:16:34.000000000 
+0200
@@ -23,6 +23,7 @@
 #include "caml/unixsupport.h"
 #include <process.h>
 #include <stdio.h>
+#include <errno.h>
 
 CAMLprim value caml_unix_system(value command)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/caml/fiber.h 
new/ocaml-5.5.1/runtime/caml/fiber.h
--- old/ocaml-5.5.0/runtime/caml/fiber.h        2026-06-19 13:32:53.000000000 
+0200
+++ new/ocaml-5.5.1/runtime/caml/fiber.h        2026-09-04 13:16:34.000000000 
+0200
@@ -262,6 +262,7 @@
 void caml_change_max_stack_size (uintnat new_max_wsize);
 void caml_maybe_expand_stack(void);
 CAMLextern void caml_free_stack(struct stack_info* stk);
+CAMLextern void caml_free_stack_cache(struct stack_info** cache);
 
 /* gc_regs_buckets is allocated on-demand by [maybe_expand_stack]. */
 CAMLextern void caml_free_gc_regs_buckets(value *gc_regs_buckets);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/caml/memory.h 
new/ocaml-5.5.1/runtime/caml/memory.h
--- old/ocaml-5.5.0/runtime/caml/memory.h       2026-06-19 13:32:53.000000000 
+0200
+++ new/ocaml-5.5.1/runtime/caml/memory.h       2026-09-04 13:16:34.000000000 
+0200
@@ -96,22 +96,14 @@
 CAMLmalloc(caml_stat_free, 1, 1)
 CAMLextern caml_stat_block caml_stat_alloc_noexc(asize_t);
 
-/* [caml_stat_alloc_aligned(size, modulo, block*)] allocates a memory block of
-   the requested [size] (in bytes), the starting address of which is aligned to
-   the provided [modulo] value. The function returns the aligned address, as
-   well as the unaligned [block] (as an output parameter). It throws an OCaml
-   exception in case the request fails, and so requires the runtime lock.
-*/
-CAMLaligned_alloc(caml_stat_free, 1, 1, 2) CAMLreturns_nonnull()
-CAMLextern void* caml_stat_alloc_aligned(asize_t, int modulo, 
caml_stat_block*);
-
-/* [caml_stat_alloc_aligned_noexc] is a variant of [caml_stat_alloc_aligned]
-   that returns NULL in case the request fails, and doesn't require the runtime
-   lock to be held.
+/* [caml_stat_calloc(num, size)] allocates a block of memory for an array
+   of [num] elements, each of them [size] bytes long, and initializes all its
+   bits to zero, effectively allocating a zero-initialized memory block of
+   [num * size] bytes. It throws an OCaml exception in case
+   the request fails, and so requires the runtime lock to be held.
 */
-CAMLaligned_alloc(caml_stat_free, 1, 1, 2)
-CAMLextern void* caml_stat_alloc_aligned_noexc(asize_t, int modulo,
-                                               caml_stat_block*);
+CAMLcalloc(caml_stat_free, 1, 1, 2)
+CAMLextern caml_stat_block caml_stat_calloc(asize_t, asize_t);
 
 /* [caml_stat_calloc_noexc(num, size)] allocates a block of memory for an array
    of [num] elements, each of them [size] bytes long, and initializes all its
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/domain.c 
new/ocaml-5.5.1/runtime/domain.c
--- old/ocaml-5.5.0/runtime/domain.c    2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/domain.c    2026-09-04 13:16:34.000000000 +0200
@@ -190,7 +190,6 @@
   struct interruptor interruptor;
 
   /* backup thread */
-  caml_plat_thread backup_thread;
   atomic_uintnat backup_thread_msg;
   caml_plat_mutex domain_lock;
   caml_plat_cond domain_cond;
@@ -203,6 +202,7 @@
 typedef struct dom_internal dom_internal;
 
 static CAMLthread_local dom_internal* domain_self;
+static CAMLthread_local bool is_backup_thread;
 
 static struct {
   /* enter barrier for STW sections, participating domains arrive into
@@ -1168,6 +1168,7 @@
 
   domain_self = di;
   caml_state = di->state;
+  is_backup_thread = true;
 
   msg = atomic_load_acquire (&di->backup_thread_msg);
   while (msg != BT_TERMINATE) {
@@ -1222,6 +1223,7 @@
 static value install_backup_thread_exn (dom_internal* di)
 {
   int err;
+  caml_plat_thread backup_thread;
 #ifndef _WIN32
   sigset_t mask, old_mask;
 #endif
@@ -1244,7 +1246,7 @@
 #endif
 
   atomic_store_release(&di->backup_thread_msg, BT_ENTERING_OCAML);
-  err = caml_plat_thread_create(&di->backup_thread, 0, backup_thread_func,
+  err = caml_plat_thread_create(&backup_thread, 0, backup_thread_func,
                                 (void*)di);
 
 #ifndef _WIN32
@@ -1253,7 +1255,7 @@
 
   if (err != 0)
       return caml_check_error_exn(err, "failed to create domain backup 
thread");
-  caml_plat_thread_detach(di->backup_thread);
+  caml_plat_thread_detach(backup_thread);
   return Val_unit;
 }
 
@@ -2177,8 +2179,7 @@
 
 CAMLexport int caml_bt_is_self(void)
 {
-  return caml_plat_thread_equal(domain_self->backup_thread,
-                                caml_plat_thread_self());
+  return is_backup_thread;
 }
 
 CAMLexport intnat caml_domain_is_multicore (void)
@@ -2408,6 +2409,8 @@
   if(domain_state->current_stack != NULL) {
     caml_free_stack(domain_state->current_stack);
   }
+  caml_free_stack_cache(domain_state->stack_cache);
+  domain_state->stack_cache = NULL;
   caml_free_backtrace_buffer(domain_state->backtrace_buffer);
   caml_free_gc_regs_buckets(domain_state->gc_regs_buckets);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/fiber.c 
new/ocaml-5.5.1/runtime/fiber.c
--- old/ocaml-5.5.0/runtime/fiber.c     2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/fiber.c     2026-09-04 13:16:34.000000000 +0200
@@ -181,6 +181,8 @@
       cache[cache_bucket] != NULL) {
     stack = cache[cache_bucket];
     cache[cache_bucket] =
+      /* In the cache, reuse the exception_ptr field as an internal
+         linked-list next pointer. */
       (struct stack_info*)stack->exception_ptr;
     CAMLassert(stack->cache_bucket == stack_cache_bucket(wosize));
     hand = stack->handler;
@@ -560,6 +562,43 @@
   return stk;
 }
 
+atomic_uintnat caml_cache_stacks_per_class =
+#if defined(USE_MMAP_MAP_STACK)
+  1
+#else
+  128
+#endif
+  ;
+
+void caml_free_stack_memory(struct stack_info* stack) {
+  atomic_fetch_sub(&live_stack_counter,
+                   (value*)(stack->handler+1) - (value*)stack);
+#ifdef DEBUG
+  memset(stack, 0x42, (char*)stack->handler - (char*)stack);
+#endif
+#ifdef USE_MMAP_MAP_STACK
+  munmap(stack, stack->size);
+#else
+  caml_stat_free(stack);
+#endif
+}
+
+void caml_free_stack_cache (struct stack_info** stack_cache)
+{
+  if (stack_cache == NULL)
+    return;
+
+  struct stack_info* stored_stack;
+  for (int i = 0; i < NUM_STACK_SIZE_CLASSES; i++) {
+    while (stack_cache[i] != NULL) {
+      stored_stack = stack_cache[i];
+      stack_cache[i] = (struct stack_info*) stored_stack->exception_ptr;
+      caml_free_stack_memory(stored_stack);
+    };
+  }
+  caml_stat_free(stack_cache);
+}
+
 void caml_free_stack (struct stack_info* stack)
 {
   CAMLnoalloc;
@@ -568,24 +607,24 @@
   CAMLassert(stack->magic == 42);
   CAMLassert(cache != NULL);
   if (stack->cache_bucket != -1) {
-    stack->exception_ptr =
-      (void*)(cache[stack->cache_bucket]);
-    cache[stack->cache_bucket] = stack;
+    struct stack_info* top = (struct stack_info*)cache[stack->cache_bucket];
+    /* When stored inside the cache, the fiber id field is reused to count
+       the number of fibers in the bucket */
+    int64_t count = top ? top->id : 0;
+    if (count < caml_cache_stacks_per_class) {
+      /* Reuse exception_ptr to point to the next fiber in the bucket. */
+      stack->exception_ptr = (void *)top;
+      stack->id = count + 1;
+      cache[stack->cache_bucket] = stack;
 #ifdef DEBUG
     memset(Stack_base(stack), 0x42,
            (Stack_high(stack)-Stack_base(stack))*sizeof(value));
 #endif
+    } else {
+      caml_free_stack_memory(stack);
+    }
   } else {
-    atomic_fetch_sub(&live_stack_counter,
-                     (value*)(stack->handler+1) - (value*)stack);
-#ifdef DEBUG
-    memset(stack, 0x42, (char*)stack->handler - (char*)stack);
-#endif
-#ifdef USE_MMAP_MAP_STACK
-    munmap(stack, stack->size);
-#else
-    caml_stat_free(stack);
-#endif
+    caml_free_stack_memory(stack);
   }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/gc_ctrl.c 
new/ocaml-5.5.1/runtime/gc_ctrl.c
--- old/ocaml-5.5.0/runtime/gc_ctrl.c   2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/gc_ctrl.c   2026-09-04 13:16:34.000000000 +0200
@@ -51,6 +51,7 @@
 extern _Atomic uintnat caml_custom_minor_max_bsz; /* see custom.c */
 extern uintnat caml_minor_heap_max_wsz; /* see domain.c */
 extern atomic_uintnat caml_mark_stack_prune_factor; /* see major_gc.c */
+extern atomic_uintnat caml_cache_stacks_per_class; /* see fiber.c */
 
 CAMLprim value caml_gc_quick_stat(value v)
 {
@@ -514,6 +515,7 @@
 #define TWEAK(v) { #v, &caml_##v, 0 }
   TWEAK(mark_stack_prune_factor),
   TWEAK(small_heap_limit),
+  TWEAK(cache_stacks_per_class),
 #undef TWEAK
 };
 enum {N_GC_TWEAKS = sizeof(gc_tweaks)/sizeof(gc_tweaks[0])};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/intern.c 
new/ocaml-5.5.1/runtime/intern.c
--- old/ocaml-5.5.0/runtime/intern.c    2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/intern.c    2026-09-04 13:16:34.000000000 +0200
@@ -843,6 +843,7 @@
   int header_len;
   uintnat data_len;
   uintnat uncompressed_data_len;
+  uintnat total_len;  /* header_len + data_len */
   uintnat num_objects;
   uintnat whsize;
   int compressed;
@@ -902,6 +903,10 @@
   default:
     intern_failwith2(fun_name, "bad object");
   }
+  if (caml_uadd_overflow(h->header_len, h->data_len, &h->total_len)) {
+    intern_failwith2
+      (fun_name, "object too large to be read back on this platform");
+  }
 }
 
 /* Decompress the input if needed.
@@ -1035,7 +1040,8 @@
   /* Initialize global state */
   intern_init(s, &Byte_u(str, ofs), caml_string_length(str) - ofs, NULL);
   caml_parse_header(s, "input_val_from_string", &h);
-  if (ofs + h.header_len + h.data_len > caml_string_length(str))
+  if (ofs < 0 || ofs + h.total_len < h.total_len ||
+      ofs + h.total_len > caml_string_length(str))
     caml_failwith("input_val_from_string: bad length");
   /* Allocate result */
   intern_alloc_storage(s, h.whsize, h.num_objects);
@@ -1077,7 +1083,7 @@
 
   intern_init(s, src, len, input);
   caml_parse_header(s, fun_name, &h);
-  if (h.header_len + h.data_len > len)
+  if (h.total_len > len)
     intern_failwith2(fun_name, "bad length");
   s->intern_src_end = s->intern_src + h.data_len;
   return input_val_from_block(s, &h);
@@ -1117,7 +1123,7 @@
 {
   uint32_t magic;
   int header_len;
-  uintnat data_len;
+  uintnat data_len, total_len;
   struct caml_intern_state *s = init_intern_state ();
 
   s->intern_src = &Byte_u(buff, Long_val(ofs));
@@ -1147,7 +1153,12 @@
   default:
     caml_failwith("Marshal.data_size: bad object");
   }
-  return Val_long((header_len - 16) + data_len);
+  if (caml_uadd_overflow(header_len, data_len, &total_len)
+      || total_len > Max_long + 20) {
+    caml_failwith("Marshal.data_size: "
+                  "object too large to be read back on this platform");
+  }
+  return Val_long(total_len - 16);
 }
 
 /* Resolution of code pointers */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/memory.c 
new/ocaml-5.5.1/runtime/memory.c
--- old/ocaml-5.5.0/runtime/memory.c    2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/memory.c    2026-09-04 13:16:34.000000000 +0200
@@ -705,6 +705,16 @@
   }
 }
 
+/* [sz] is a number of bytes */
+CAMLexport caml_stat_block caml_stat_calloc(asize_t num, asize_t sz)
+{
+  void *result = caml_stat_calloc_noexc(num, sz);
+  /* calloc() may return NULL if size is 0 or number of elements is 0 */
+  if ((result == NULL) && (sz != 0) && (num != 0))
+    caml_raise_out_of_memory();
+  return result;
+}
+
 CAMLexport caml_stat_string caml_stat_strdup_noexc(const char *s)
 {
   size_t slen = strlen(s);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/minor_gc.c 
new/ocaml-5.5.1/runtime/minor_gc.c
--- old/ocaml-5.5.0/runtime/minor_gc.c  2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/minor_gc.c  2026-09-04 13:16:34.000000000 +0200
@@ -737,7 +737,7 @@
 
   CAML_EV_COUNTER(EV_C_MINOR_ALLOCATED, minor_allocated_bytes);
   CAML_EV_COUNTER(EV_C_MINOR_ALLOCATED_WORDS,
-                  Whsize_wosize(minor_allocated_bytes));
+                  Wsize_bsize(minor_allocated_bytes));
 
   CAML_EV_END(EV_MINOR);
   if (minor_allocated_bytes == 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/signals.c 
new/ocaml-5.5.1/runtime/signals.c
--- old/ocaml-5.5.0/runtime/signals.c   2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/runtime/signals.c   2026-09-04 13:16:34.000000000 +0200
@@ -21,6 +21,9 @@
 #include <errno.h>
 #include <stdbool.h>
 #include "caml/config.h"
+#ifndef _WIN32
+#include <unistd.h>
+#endif
 #ifdef USE_MMAP_MAP_STACK
 #include <sys/mman.h>
 #endif
@@ -544,12 +547,40 @@
   return Val_int(caml_rev_convert_signal_number(Int_val(signo)));
 }
 
+#ifdef POSIX_SIGNALS
+/* On Linux, the minimum signal stack size is architecture-dependent, whereas
+ * SIGSTKSZ can be a build-time constant and may be smaller than the run-time
+ * minimum (e.g. on musl with certain Intel CPUs). Thus, we call sysconf for 
the
+ * run-time value ourselves. */
+Caml_inline size_t caml_sigstksz(void)
+{
+  /* Compute the recommended signal stack size only once. Atomic due to benign
+   * concurrent reads during domain init. */
+  static _Atomic size_t cache = 0;
+  size_t size = atomic_load_relaxed(&cache);
+  if (size == 0) {
+    long sz;
+#ifdef _SC_SIGSTKSZ
+    /* glibc/musl only */
+    sz = sysconf(_SC_SIGSTKSZ);
+    if (sz <= 0)
+      sz = SIGSTKSZ;
+#else
+    sz = SIGSTKSZ;
+#endif
+    size = (size_t) sz;
+    atomic_store_relaxed(&cache, size);
+  }
+  return size;
+}
+#endif /* POSIX_SIGNALS */
+
 void * caml_init_signal_stack(void)
 {
 #ifdef POSIX_SIGNALS
   stack_t stk;
   stk.ss_flags = 0;
-  stk.ss_size = SIGSTKSZ;
+  stk.ss_size = caml_sigstksz();
   /* The memory used for the alternate signal stack must not free'd before
      calling sigaltstack with SS_DISABLE. malloc/mmap is therefore used rather
      than caml_stat_alloc_noexc so that if a shutdown path erroneously fails
@@ -562,7 +593,7 @@
   if (stk.ss_sp == MAP_FAILED)
     return NULL;
   if (sigaltstack(&stk, NULL) < 0) {
-    munmap(stk.ss_sp, SIGSTKSZ);
+    munmap(stk.ss_sp, stk.ss_size);
     return NULL;
   }
 #else
@@ -586,7 +617,7 @@
   stack_t stk, disable;
   disable.ss_flags = SS_DISABLE;
   disable.ss_sp = NULL;  /* not required but avoids a valgrind false alarm */
-  disable.ss_size = SIGSTKSZ; /* macOS wants a valid size here */
+  disable.ss_size = caml_sigstksz(); /* macOS wants a valid size here */
   if (sigaltstack(&disable, &stk) < 0) {
     caml_fatal_error("Failed to reset signal stack (err %d)", errno);
   }
@@ -598,7 +629,7 @@
   /* Memory was allocated with malloc/mmap directly (see
      caml_init_signal_stack) */
 #ifdef USE_MMAP_MAP_STACK
-  munmap(signal_stack, SIGSTKSZ);
+  munmap(signal_stack, caml_sigstksz());
 #else
   free(signal_stack);
 #endif /* USE_MMAP_MAP_STACK */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/runtime/startup_byt.c 
new/ocaml-5.5.1/runtime/startup_byt.c
--- old/ocaml-5.5.0/runtime/startup_byt.c       2026-06-19 13:32:53.000000000 
+0200
+++ new/ocaml-5.5.1/runtime/startup_byt.c       2026-09-04 13:16:34.000000000 
+0200
@@ -159,15 +159,14 @@
 
 void caml_read_section_descriptors(int fd, struct exec_trailer *trail)
 {
-  int toc_size;
-
-  toc_size = trail->num_sections * 8;
-  trail->section = caml_stat_alloc(toc_size);
-  lseek(fd, - (long) (TRAILER_SIZE + toc_size), SEEK_END);
+  size_t toc_size;
+  trail->section = caml_stat_calloc(trail->num_sections, 8);
+  toc_size = (size_t) trail->num_sections * 8;
+  lseek(fd, - (file_offset) (TRAILER_SIZE + toc_size), SEEK_END);
   if (read(fd, (char *) trail->section, toc_size) != toc_size)
     caml_fatal_error("cannot read section table");
   /* Fixup endianness of lengths */
-  for (int i = 0; i < trail->num_sections; i++)
+  for (uint32_t i = 0; i < trail->num_sections; i++)
     fixup_endianness_trailer(&(trail->section[i].len));
 }
 
@@ -178,13 +177,13 @@
 int32_t caml_seek_optional_section(int fd, struct exec_trailer *trail,
                                    const char *name)
 {
-  long ofs;
-
-  ofs = TRAILER_SIZE + trail->num_sections * 8;
-  for (int i = trail->num_sections - 1; i >= 0; i--) {
+  size_t ofs = TRAILER_SIZE + (size_t) trail->num_sections * 8;
+  uint32_t i = trail->num_sections;
+  while (i > 0) {
+    i -= 1;
     ofs += trail->section[i].len;
     if (strncmp(trail->section[i].name, name, 4) == 0) {
-      lseek(fd, -ofs, SEEK_END);
+      lseek(fd, - (file_offset) ofs, SEEK_END);
       return trail->section[i].len;
     }
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/testsuite/tests/lib-marshal/fuzzy.ml 
new/ocaml-5.5.1/testsuite/tests/lib-marshal/fuzzy.ml
--- old/ocaml-5.5.0/testsuite/tests/lib-marshal/fuzzy.ml        2026-06-19 
13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/testsuite/tests/lib-marshal/fuzzy.ml        2026-09-04 
13:16:34.000000000 +0200
@@ -79,6 +79,17 @@
   end;
   Gc.full_major()
 
+(* Same, but use Marshal.from_string instead *)
+
+let test_string ic =
+  In_channel.set_binary_mode ic true;
+  let s = In_channel.input_all ic in
+  begin try
+    ignore (Marshal.from_string s 0)
+  with Failure _ | Invalid_argument _ | Out_of_memory -> ()
+  end;
+  Gc.full_major()
+
 (* Internal fuzzing.  Rather naive. *)
 
 let random_offset b =
@@ -123,7 +134,7 @@
       end;
       Gc.full_major()
     done;
-    Bytes.set_uint8 b i (Bytes.get_uint8 b i)
+    Bytes.set_uint8 b i (String.get_uint8 d i)
   done
 
 let () =
@@ -135,7 +146,9 @@
     "-x", Arg.Unit fuzz1,
       "<num iter>  Perform internal fuzzing test (exhaustive 1-byte)";
     "-r", Arg.Unit (fun () -> test stdin),
-      "  Read marshaled data from standard input"
+      "  Read marshaled data from standard input";
+    "-s", Arg.Unit (fun () -> test_string stdin),
+      "  Read marshaled data from standard input via a string"
   ]
   (fun s -> raise (Arg.Bad ("don't know what to do with " ^ s)))
   "Usage: fuzzy [option].\nOptions are:"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/testsuite/tests/lib-systhreads/testpreempt.ml 
new/ocaml-5.5.1/testsuite/tests/lib-systhreads/testpreempt.ml
--- old/ocaml-5.5.0/testsuite/tests/lib-systhreads/testpreempt.ml       
2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/testsuite/tests/lib-systhreads/testpreempt.ml       
2026-09-04 13:16:34.000000000 +0200
@@ -1,12 +1,6 @@
 (* TEST
  include systhreads;
  hassysthreads;
-   (*
-     On Windows, we use Sleep(0) for triggering preemption of threads.
-     However, this does not seem very reliable, so that this test fails
-     on some Windows configurations. See GPR #1533.
-   *)
- not-target-windows;
  {
    bytecode;
  }{
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/testsuite/tests/parallel/fiber_migration.ml 
new/ocaml-5.5.1/testsuite/tests/parallel/fiber_migration.ml
--- old/ocaml-5.5.0/testsuite/tests/parallel/fiber_migration.ml 1970-01-01 
01:00:00.000000000 +0100
+++ new/ocaml-5.5.1/testsuite/tests/parallel/fiber_migration.ml 2026-09-04 
13:16:34.000000000 +0200
@@ -0,0 +1,72 @@
+(* TEST
+ multicore;
+ {
+   bytecode;
+ }{
+   native;
+ }
+*)
+
+(** Test fiber migration. We test that sending fibers from one domain
+    to another do not increase the size of the fiber cache of the
+    receiving domain in an unbounded way *)
+
+(** Migration effect *)
+type _ Effect.t += Migrate : unit Effect.t
+
+(** Transfer of continuation to a shared stack *)
+let shared_fiber_stack: (unit->unit) list Atomic.t = Atomic.make []
+let rec push item =
+  (* Update to Atomic.update once the function is less fresh *)
+   let before = Atomic.get shared_fiber_stack in
+   let after = item :: before in
+   if not (Atomic.compare_and_set shared_fiber_stack before after) then
+     push item
+let get_fibers () = Atomic.get shared_fiber_stack
+let take_fibers () = List.rev (Atomic.exchange shared_fiber_stack [])
+
+(** Produce fibers by performing the Migrate effect, then store
+    them in the shared stack *)
+let producer_loop () =
+  let max_live_fiber = 10 in
+  for _ = 1 to max_live_fiber do
+    match Effect.perform Migrate with
+    | () -> ()
+    | effect Migrate, k -> push (Effect.Deep.continue k)
+  done;
+  (* Wait for the consumer to cache all fibers in order to bound the
+     number of live fibers *)
+  while get_fibers () <> [] do Domain.cpu_relax () done
+
+(** Receiver loop: pick fibers in the shared stack, resume them and
+    store them in the cache of the receiver domain. *)
+let rec receiver_loop = function
+  | [] ->
+      (* wait for the producer to send more fibers *)
+      while get_fibers () = [] do
+        Domain.cpu_relax ()
+      done;
+      receiver_loop (take_fibers ())
+  | fiber :: fibers ->
+      (* we resume the fiber in the shared stack, and store it in the
+         current domain cache *)
+      match fiber () with
+      | () -> receiver_loop fibers
+      | exception Exit -> ()
+
+let main () =
+  let receiving_domain = Domain.spawn (fun () -> receiver_loop []) in
+  let finally () =
+    push (fun () -> raise Exit);
+    Domain.join receiving_domain
+  in
+  Fun.protect ~finally begin fun () ->
+    for _ = 1 to 50 do producer_loop () done;
+    (* Check that the size of fiber caches did not grow unboundedly during the 
loop *)
+    let cache_size = (Gc.quick_stat()).live_stacks_words in
+    if (cache_size < 25000) then
+      Printf.printf "OK\n%!"
+    else Printf.printf "Bad %d\n%!" cache_size
+  end
+
+let () = main ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/testsuite/tests/parallel/fiber_migration.reference 
new/ocaml-5.5.1/testsuite/tests/parallel/fiber_migration.reference
--- old/ocaml-5.5.0/testsuite/tests/parallel/fiber_migration.reference  
1970-01-01 01:00:00.000000000 +0100
+++ new/ocaml-5.5.1/testsuite/tests/parallel/fiber_migration.reference  
2026-09-04 13:16:34.000000000 +0200
@@ -0,0 +1 @@
+OK
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/testsuite/tests/typing-misc/type_external.ml 
new/ocaml-5.5.1/testsuite/tests/typing-misc/type_external.ml
--- old/ocaml-5.5.0/testsuite/tests/typing-misc/type_external.ml        
2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/testsuite/tests/typing-misc/type_external.ml        
2026-09-04 13:16:34.000000000 +0200
@@ -283,3 +283,76 @@
 [%%expect{|
 type t = external "\\\\\\"
 |}]
+
+(* manifest *)
+module type P = sig
+  type t = external "p"
+end
+module Q(P : P) : P with type t = P.t = struct
+  type t = P.t
+end;;
+[%%expect{|
+module type P = sig type t = external "p" end
+Lines 4-6, characters 40-3:
+4 | ........................................struct
+5 |   type t = P.t
+6 | end..
+Error: Signature mismatch:
+       Modules do not match:
+         sig type t = P.t end
+       is not included in
+         sig type t = external "p" end
+       Type declarations do not match:
+         type t = P.t
+       is not included in
+         type t = external "p"
+       The first is abstract, but the second is external "p".
+|}]
+
+module type P1 = sig
+  type !'b t = external "p"
+end
+module Q(P1 : P1) : P1 with type 'a t = 'a P1.t = struct
+  type 'a t = 'a P1.t
+end;;
+[%%expect{|
+module type P1 = sig type !'b t = external "p" end
+Lines 4-6, characters 50-3:
+4 | ..................................................struct
+5 |   type 'a t = 'a P1.t
+6 | end..
+Error: Signature mismatch:
+       Modules do not match:
+         sig type !'a t = 'a P1.t end
+       is not included in
+         sig type !'a t = external "p" end
+       Type declarations do not match:
+         type !'a t = 'a P1.t
+       is not included in
+         type !'a t = external "p"
+       The first is abstract, but the second is external "p".
+|}]
+
+module type P1 = sig
+  type +'b t = external "p"
+end
+module Q(P1 : P1) : P1 with type 'a t = 'a P1.t = struct
+  type 'a t = 'a P1.t
+end;;
+[%%expect{|
+module type P1 = sig type +!'b t = external "p" end
+Lines 4-6, characters 50-3:
+4 | ..................................................struct
+5 |   type 'a t = 'a P1.t
+6 | end..
+Error: Signature mismatch:
+       Modules do not match:
+         sig type +!'a t = 'a P1.t end
+       is not included in
+         sig type +!'a t = external "p" end
+       Type declarations do not match:
+         type +!'a t = 'a P1.t
+       is not included in
+         type +!'a t = external "p"
+       The first is abstract, but the second is external "p".
+|}]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ocaml-5.5.0/testsuite/tests/typing-modular-explicits/general.ml 
new/ocaml-5.5.1/testsuite/tests/typing-modular-explicits/general.ml
--- old/ocaml-5.5.0/testsuite/tests/typing-modular-explicits/general.ml 
2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/testsuite/tests/typing-modular-explicits/general.ml 
2026-09-04 13:16:34.000000000 +0200
@@ -1495,3 +1495,30 @@
                                                                   ^^
   This extra argument is not expected.
 |}]
+
+module type S = sig type t type e val v : e -> t end
+let helper (type a) (module M : S with type t = a) _ : a = assert false
+let outer (type a) (type b) (module M : S with type e = a and type t = b) e =
+  helper (module M) (M.v e)
+[%%expect {|
+module type S = sig type t type e val v : e -> t end
+val helper : (module S with type t = 'a) -> 'b -> 'a = <fun>
+val outer : (module M : S with type e = 'a and type t = 'b) -> M.e -> M.t =
+  <fun>
+|}]
+
+
+(* Bug #14891: nondep package type *)
+
+module type N = sig module type T end
+module type S = sig type 'a t end
+let f (module M:N) (x:(module M.T)) = x
+let app = f (module struct module type T = S end)
+let ok = f (module struct module type T = S end) (module List:S)
+[%%expect {|
+module type N = sig module type T end
+module type S = sig type 'a t end
+val f : (module M : N) -> (module M.T) -> (module M.T) = <fun>
+val app : (module S) -> (module S) = <fun>
+val ok : (module S) = <module>
+|}]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/typing/ctype.ml 
new/ocaml-5.5.1/typing/ctype.ml
--- old/ocaml-5.5.0/typing/ctype.ml     2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/typing/ctype.ml     2026-09-04 13:16:34.000000000 +0200
@@ -2321,7 +2321,7 @@
       | Tpackage {pack_path = p; pack_constraints} ->
           begin match Path.check_for_unbound_unscoped_idents bound_id p with
           | Some i ->
-            occur_normalize_modtype_path env bound_uv bound_id i p
+            occur_normalize_modtype_path env bound_uv bound_id i p ty
               (fun pack_path -> Tpackage {pack_path; pack_constraints})
           | None ->
               List.iter (fun (_, t) -> occur_rec env bound_uv bound_id t)
@@ -2334,6 +2334,7 @@
           match id_escape with
           | Some i ->
             occur_normalize_modtype_path env bound_uv bound_id i pack.pack_path
+              ty
               (fun pack_path -> Tfunctor (l, id, {pack with pack_path}, ty))
           | None ->
               List.iter (fun (_, t) -> occur_rec env bound_uv bound_id t)
@@ -2358,7 +2359,7 @@
         occur_desc env bound_uv bound_id ty
       end else
         iter_type_expr (occur_rec env bound_uv bound_id) ty
-    and occur_normalize_modtype_path env bound_uv bound_id us p f =
+    and occur_normalize_modtype_path env bound_uv bound_id us p ty f =
       match Env.try_normalize_modtype_path env p with
       | None -> raise_escape_exn (Module (Ident.of_unscoped us))
       | Some p' ->
@@ -2459,7 +2460,7 @@
     Similar to [nondep_type], however we remove the dependency in place,
     while [nondep] does a copy of the type.
 *)
-let identifier_escape env idl ty =
+let identifier_escape env idl initial_ty =
   with_type_mark begin fun mark ->
   let rec occur ?(ignore_mark=false) idl ty =
     if try_mark_node mark ty || ignore_mark then begin
@@ -2473,7 +2474,7 @@
           begin match Path.find_free_opt idl pack.pack_path with
           | None -> iter_type_expr (occur idl) ty
           | Some i ->
-            occur_normalize_modtype_path env idl pack.pack_path i
+            occur_normalize_modtype_path env idl pack.pack_path i ty
               (fun pack_path -> Tpackage {pack with pack_path})
           end
       | Tobject (_, ({contents = Some (p, _)} as nm)) ->
@@ -2489,7 +2490,7 @@
       | Tfunctor (l, id, pack, t) ->
           begin match Path.find_free_opt idl pack.pack_path with
           | Some i ->
-              occur_normalize_modtype_path env idl pack.pack_path i
+              occur_normalize_modtype_path env idl pack.pack_path i ty
                 (fun pack_path -> Tfunctor (l, id, {pack with pack_path}, ty))
           | None ->
               List.iter (fun (_, t) -> occur idl t) pack.pack_constraints;
@@ -2514,14 +2515,14 @@
       occur ~ignore_mark:true idl ty
     end else
       iter_type_expr (occur idl) ty
-  and occur_normalize_modtype_path env idl p id f =
+  and occur_normalize_modtype_path env idl p id ty f =
     match Env.try_normalize_modtype_path env p with
     | None -> raise_escape_exn (Module id)
     | Some p' ->
       set_type_desc ty (f p');
       occur ~ignore_mark:true idl ty
   in
-  occur (List.map Ident.of_unscoped idl) ty
+  occur (List.map Ident.of_unscoped idl) initial_ty
   end
 
 let identifier_escape_for tr_exn env idl t =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocaml-5.5.0/typing/out_type.ml 
new/ocaml-5.5.1/typing/out_type.ml
--- old/ocaml-5.5.0/typing/out_type.ml  2026-06-19 13:32:53.000000000 +0200
+++ new/ocaml-5.5.1/typing/out_type.ml  2026-09-04 13:16:34.000000000 +0200
@@ -1453,7 +1453,7 @@
     | _ -> {ot_non_gen=false; ot_name="?"; ot_variance}
   in
   let type_defined decl =
-    let abstr =
+    let non_inferable_variance =
       match decl.type_kind with
         Type_abstract _ ->
           decl.type_manifest = None || decl.type_private = Private
@@ -1465,16 +1465,18 @@
       | Type_open ->
           decl.type_manifest = None
       | Type_external _ ->
-          assert (decl.type_manifest = None); true
+          true
     in
     let vari =
       List.map2
         (fun ty v ->
           let is_var = is_Tvar ty in
-          let with_variance = !Clflags.print_variance || abstr || not is_var in
+          let with_variance =
+            !Clflags.print_variance || non_inferable_variance || not is_var
+          in
           let with_injectivity =
             !Clflags.print_variance ||
-            (abstr || not is_var) &&
+            (non_inferable_variance || not is_var) &&
             type_kind_is_abstract decl &&
             match decl.type_manifest with
             | None -> true

Reply via email to