Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reproducible builds: filesystem readdir order #9794

Closed
bmwiedemann opened this issue Jan 22, 2024 · 5 comments · Fixed by #9861 or ocaml/opam-repository#25186
Closed

reproducible builds: filesystem readdir order #9794

bmwiedemann opened this issue Jan 22, 2024 · 5 comments · Fixed by #9861 or ocaml/opam-repository#25186

Comments

@bmwiedemann
Copy link

While working on reproducible builds for openSUSE, I found that our ocaml-dune package varies through non-determinism from filesystem readdir order.

Expected Behavior

dune build should be reproducible

Actual Behavior

--- strings RPMS.1/usr/bin/dune
+++ strings RPMS.2/usr/bin/dune
[...]
 padding.0
-sha1_do_chunk
 sha512_do_chunk
+sha1_do_chunk
 scanmult
 shutdown_happened

Maybe related: ocaml-dune-3.12.2/_boot/source_files produced by ./.duneboot.exe --verbose also has order variations.

Reproduction

build on two different filesystems or use disorderfs or randomize readdir order

Specifications

  • Version of dune (output of dune --version): ocaml-dune-3.12.2 with boot: remove single-command bootstrap #9735
  • Version of ocaml (output of ocamlc --version) ocaml-4.14.1
  • Operating system (distribution and version): openSUSE Tumbleweed
@emillon
Copy link
Collaborator

emillon commented Jan 22, 2024

Hi,
Thanks for the report.
I'll have a look at this, but to clarify, can you tell me how you are creating /usr/bin/dune?

@emillon
Copy link
Collaborator

emillon commented Jan 24, 2024

I had a look at the build instructions. This part does not look right:

ocaml boot/bootstrap.ml --verbose ${jobs}
./_boot/dune.exe build \
	dune.install \
	--release \
	--profile dune-bootstrap \
	--verbose \
	${jobs} \
	%nil
mkdir .bin
ln -sv ../_boot/dune.exe .bin/dune

The first command will create _boot/dune.exe. This binary is then used to build a new binary (in _build/install/default/bin/dune).

If I understand correctly, you're installing _boot/dune instead of installing _build/install/default/bin/dune. They both should act similarly, but only the latter has been built by dune and is expected to be reproducible. So that's the one you should be installing in the rpm package. _boot/dune.exe is just and intermediate build artifact that's not expected to be reproducible.

(in the light of that, #9507 didn't really have to be fixed in terms of reproducibility, but it's still valuable to remove this code path)

@bmwiedemann
Copy link
Author

I saw

/home/abuild/rpmbuild/BUILDROOT/ocaml-dune-3.13.0-0.x86_64/usr/bin/dune from /home/abuild/rpmbuild/BUILDROOT/ocaml-dune-3.13.0-0.x86_64/usr/bin/.#dune.dune-temp written per rename
    by exec="/home/abuild/rpmbuild/BUILD/ocaml-dune-3.13.0/.bin/dune", ["dune", "install", "--verbose", "--for-release-of-packages=dune", "-j16", "--prefix=/usr", "--libdir=/usr/lib64/ocaml", "--destdir=/home/abuild/rpmbuild/BUILDROOT/ocaml-dune-3.13.0-0.x86_64", "dune"] - started

so the final binary gets written there by dune install, but don't know where dune install reads the installed binary.

I also tried

-ln -sv ../_boot/dune.exe .bin/dune
+ln -sv ../_build/default/bin/dune.exe .bin/dune

and it did not help with the original issue.
Plus these dune.exe files had the same content after the build.

md5sum ./_build/default/bin/dune.exe ./_build/default/_boot/dune.exe _boot/dune.exe 
be020387f3b524d2c1105a4a26d7281c  ./_build/default/bin/dune.exe
be020387f3b524d2c1105a4a26d7281c  ./_build/default/_boot/dune.exe
be020387f3b524d2c1105a4a26d7281c  _boot/dune.exe

emillon added a commit to emillon/dune that referenced this issue Jan 30, 2024
Fixes ocaml#9794

`_boot/dune.exe` is installed, so it needs to be reproducible. This
change ensures that the source files are scanned in an order that is
independent from the underlying directory entries.

This has been tested with `disorderfs --shuffle-dirents=yes`: two runs
of `make bootstrap` create the same binary.

Signed-off-by: Etienne Millon <me@emillon.org>
emillon added a commit to emillon/dune that referenced this issue Jan 30, 2024
Fixes ocaml#9794

`_boot/dune.exe` is installed, so it needs to be reproducible. This
change ensures that the source files are scanned in an order that is
independent from the underlying directory entries.

This has been tested with `disorderfs --shuffle-dirents=yes`: two runs
of `make bootstrap` create the same binary.

Signed-off-by: Etienne Millon <me@emillon.org>
@emillon
Copy link
Collaborator

emillon commented Jan 30, 2024

Sorry, I was confused about our bootstrap process. It's indeed intended that _boot/dune.exe is installed. I created #9861 to solve the issue, and tested it with disorderfs.

emillon added a commit that referenced this issue Jan 30, 2024
Fixes #9794

`_boot/dune.exe` is installed, so it needs to be reproducible. This
change ensures that the source files are scanned in an order that is
independent from the underlying directory entries.

This has been tested with `disorderfs --shuffle-dirents=yes`: two runs
of `make bootstrap` create the same binary.

Signed-off-by: Etienne Millon <me@emillon.org>
emillon added a commit to emillon/dune that referenced this issue Feb 5, 2024
Fixes ocaml#9794

`_boot/dune.exe` is installed, so it needs to be reproducible. This
change ensures that the source files are scanned in an order that is
independent from the underlying directory entries.

This has been tested with `disorderfs --shuffle-dirents=yes`: two runs
of `make bootstrap` create the same binary.

Signed-off-by: Etienne Millon <me@emillon.org>
emillon added a commit that referenced this issue Feb 5, 2024
Fixes #9794

`_boot/dune.exe` is installed, so it needs to be reproducible. This
change ensures that the source files are scanned in an order that is
independent from the underlying directory entries.

This has been tested with `disorderfs --shuffle-dirents=yes`: two runs
of `make bootstrap` create the same binary.

Signed-off-by: Etienne Millon <me@emillon.org>
emillon added a commit to emillon/opam-repository that referenced this issue Feb 5, 2024
CHANGES:

- Fix performance regression for incremental builds (ocaml/dune#9769, fixes ocaml/dune#9738,
  @rgrinberg)

- Fix `dune ocaml top-module` to correctly handle absolute paths. (ocaml/dune#8249, fixes
  ocaml/dune#7370, @Alizter)

- subst: ignore broken symlinks when looking at source files (ocaml/dune#9810, fixes
  ocaml/dune#9593, @emillon)

- subst: do not fail on 32-bit systems when large files are encountered. Just
  log a warning in this case. (ocaml/dune#9811, fixes ocaml/dune#9538, @emillon)

- boot: sort directory entries in readdir. This makes the dune binary
  reproducible in terms of filesystem order. (ocaml/dune#9861, fixes ocaml/dune#9794, @emillon)
nberth pushed a commit to nberth/opam-repository that referenced this issue Jun 18, 2024
CHANGES:

- Fix performance regression for incremental builds (ocaml/dune#9769, fixes ocaml/dune#9738,
  @rgrinberg)

- Fix `dune ocaml top-module` to correctly handle absolute paths. (ocaml/dune#8249, fixes
  ocaml/dune#7370, @Alizter)

- subst: ignore broken symlinks when looking at source files (ocaml/dune#9810, fixes
  ocaml/dune#9593, @emillon)

- subst: do not fail on 32-bit systems when large files are encountered. Just
  log a warning in this case. (ocaml/dune#9811, fixes ocaml/dune#9538, @emillon)

- boot: sort directory entries in readdir. This makes the dune binary
  reproducible in terms of filesystem order. (ocaml/dune#9861, fixes ocaml/dune#9794, @emillon)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants