Attach mtimes to individual deps, not files. Fixes a miscompile (!!)
Fix bug:
- Assume X and Y depend on Z
- X and Y both compile clean.
- A change is made to Z
- X and Y are now "out-of-date," and marked to compile.
- The change causes a failure in X, but Y still compiles clean.
- Because X compiles clean, the database will be updated and store the new mtime of Z!
- Attempting to compile again, the mtime of Z will not be considered "changed" since the last compile.
- X depends on Z, but Z is not marked "changed," and X will not be recompiled, even though it is still in a dirty state!
- Linking of X and Y produces wild results. UB. ORD NDR. Badness.
The fix is to have the edges in the graph between inputs and outputs
store the mtime of the input, rather than to store that mtime on the
file itself. Thus, each individual relationship between inputs and
outputs will track the "outdated-ness" of themselves.
This also adds a test which can correctly reproduce the issue in absense of the fix.
5 anos atrás Attach mtimes to individual deps, not files. Fixes a miscompile (!!)
Fix bug:
- Assume X and Y depend on Z
- X and Y both compile clean.
- A change is made to Z
- X and Y are now "out-of-date," and marked to compile.
- The change causes a failure in X, but Y still compiles clean.
- Because X compiles clean, the database will be updated and store the new mtime of Z!
- Attempting to compile again, the mtime of Z will not be considered "changed" since the last compile.
- X depends on Z, but Z is not marked "changed," and X will not be recompiled, even though it is still in a dirty state!
- Linking of X and Y produces wild results. UB. ORD NDR. Badness.
The fix is to have the edges in the graph between inputs and outputs
store the mtime of the input, rather than to store that mtime on the
file itself. Thus, each individual relationship between inputs and
outputs will track the "outdated-ness" of themselves.
This also adds a test which can correctly reproduce the issue in absense of the fix.
5 anos atrás Attach mtimes to individual deps, not files. Fixes a miscompile (!!)
Fix bug:
- Assume X and Y depend on Z
- X and Y both compile clean.
- A change is made to Z
- X and Y are now "out-of-date," and marked to compile.
- The change causes a failure in X, but Y still compiles clean.
- Because X compiles clean, the database will be updated and store the new mtime of Z!
- Attempting to compile again, the mtime of Z will not be considered "changed" since the last compile.
- X depends on Z, but Z is not marked "changed," and X will not be recompiled, even though it is still in a dirty state!
- Linking of X and Y produces wild results. UB. ORD NDR. Badness.
The fix is to have the edges in the graph between inputs and outputs
store the mtime of the input, rather than to store that mtime on the
file itself. Thus, each individual relationship between inputs and
outputs will track the "outdated-ness" of themselves.
This also adds a test which can correctly reproduce the issue in absense of the fix.
5 anos atrás Attach mtimes to individual deps, not files. Fixes a miscompile (!!)
Fix bug:
- Assume X and Y depend on Z
- X and Y both compile clean.
- A change is made to Z
- X and Y are now "out-of-date," and marked to compile.
- The change causes a failure in X, but Y still compiles clean.
- Because X compiles clean, the database will be updated and store the new mtime of Z!
- Attempting to compile again, the mtime of Z will not be considered "changed" since the last compile.
- X depends on Z, but Z is not marked "changed," and X will not be recompiled, even though it is still in a dirty state!
- Linking of X and Y produces wild results. UB. ORD NDR. Badness.
The fix is to have the edges in the graph between inputs and outputs
store the mtime of the input, rather than to store that mtime on the
file itself. Thus, each individual relationship between inputs and
outputs will track the "outdated-ness" of themselves.
This also adds a test which can correctly reproduce the issue in absense of the fix.
5 anos atrás Attach mtimes to individual deps, not files. Fixes a miscompile (!!)
Fix bug:
- Assume X and Y depend on Z
- X and Y both compile clean.
- A change is made to Z
- X and Y are now "out-of-date," and marked to compile.
- The change causes a failure in X, but Y still compiles clean.
- Because X compiles clean, the database will be updated and store the new mtime of Z!
- Attempting to compile again, the mtime of Z will not be considered "changed" since the last compile.
- X depends on Z, but Z is not marked "changed," and X will not be recompiled, even though it is still in a dirty state!
- Linking of X and Y produces wild results. UB. ORD NDR. Badness.
The fix is to have the edges in the graph between inputs and outputs
store the mtime of the input, rather than to store that mtime on the
file itself. Thus, each individual relationship between inputs and
outputs will track the "outdated-ness" of themselves.
This also adds a test which can correctly reproduce the issue in absense of the fix.
5 anos atrás Attach mtimes to individual deps, not files. Fixes a miscompile (!!)
Fix bug:
- Assume X and Y depend on Z
- X and Y both compile clean.
- A change is made to Z
- X and Y are now "out-of-date," and marked to compile.
- The change causes a failure in X, but Y still compiles clean.
- Because X compiles clean, the database will be updated and store the new mtime of Z!
- Attempting to compile again, the mtime of Z will not be considered "changed" since the last compile.
- X depends on Z, but Z is not marked "changed," and X will not be recompiled, even though it is still in a dirty state!
- Linking of X and Y produces wild results. UB. ORD NDR. Badness.
The fix is to have the edges in the graph between inputs and outputs
store the mtime of the input, rather than to store that mtime on the
file itself. Thus, each individual relationship between inputs and
outputs will track the "outdated-ness" of themselves.
This also adds a test which can correctly reproduce the issue in absense of the fix.
5 anos atrás |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- import subprocess
-
- import pytest
-
- from tests import DDS
- from dds_ci import proc, paths
-
- ## #############################################################################
- ## #############################################################################
- ## The test project in this directory contains a single application and two
- ## functions, each defined in a separate file. The two functions each return
- ## an integer, and the application exit code will be the difference between
- ## the two integers. (They are passed through std::abs(), so it is always a
- ## positive integer). The default value is 32 in both functions.
- ## #############################################################################
- ## The purpose of these tests is to ensure the reliability of the compilation
- ## dependency database. Having a miscompile because there was a failure to
- ## detect file changes is a catastrophic bug!
-
-
- def build_and_get_rc(dds: DDS) -> int:
- dds.build()
- app = dds.build_dir / ('app' + paths.EXE_SUFFIX)
- return proc.run([app]).returncode
-
-
- def test_simple_rebuild(dds: DDS) -> None:
- """
- Check that changing a source file will update the resulting application.
- """
- assert build_and_get_rc(dds) == 0
- dds.scope.enter_context(
- dds.set_contents(
- 'src/1.cpp',
- b'''
- int value_1() { return 33; }
- ''',
- ))
- # 33 - 32 = 1
- assert build_and_get_rc(dds) == 1
-
-
- def test_rebuild_header_change(dds: DDS) -> None:
- """Change the content of the header which defines the values"""
- assert build_and_get_rc(dds) == 0
- dds.scope.enter_context(
- dds.set_contents(
- 'src/values.hpp',
- b'''
- const int first_value = 63;
- const int second_value = 88;
- ''',
- ))
- assert build_and_get_rc(dds) == (88 - 63)
-
-
- def test_partial_build_rebuild(dds: DDS) -> None:
- """
- Change the content of a header, but cause one user of that header to fail
- compilation. The fact that compilation fails means it is still `out-of-date`,
- and will need to be compiled after we have fixed it up.
- """
- assert build_and_get_rc(dds) == 0
- dds.scope.enter_context(
- dds.set_contents(
- 'src/values.hpp',
- b'''
- const int first_value_q = 6;
- const int second_value_q = 99;
- ''',
- ))
- # Header now causes errors in 1.cpp and 2.cpp
- with pytest.raises(subprocess.CalledProcessError):
- dds.build()
- # Fix 1.cpp
- dds.scope.enter_context(
- dds.set_contents(
- 'src/1.cpp',
- b'''
- #include "./values.hpp"
-
- int value_1() { return first_value_q; }
- ''',
- ))
- # We will still see a failure, but now the DB will record the updated values.hpp
- with pytest.raises(subprocess.CalledProcessError):
- dds.build()
-
- # Should should raise _again_, even though we've successfully compiled one
- # of the two files with the changed `values.hpp`, because `2.cpp` still
- # has a pending update
- with pytest.raises(subprocess.CalledProcessError):
- dds.build()
-
- dds.scope.enter_context(
- dds.set_contents(
- 'src/2.cpp',
- b'''
- #include "./values.hpp"
-
- int value_2() { return second_value_q; }
- ''',
- ))
- # We should now compile and link to get the updated value
- assert build_and_get_rc(dds) == (99 - 6)
|