[SV 63047] Fix shuffle of SECONDEXPANSION prerequisites

Commit 07eea3aa4 `make --shuffle` prevented shuffling prerequisites
that use .SECONDEXPANSION, since shuffle happens before expansion.
This has two problems:
1. No shuffling happens for such prerequisites.
2. Use-after-free when outdated '->shuf' links are used.

Add a reshuffle into expansion phase right after dependency changes.

* src/file.c (expand_deps): Add reshuffle if dependencies change.
* src/shuffle.c (identity_shuffle_array): Fix comment typo.
* tests/scripts/options/shuffle: Add new SECONDEXPANSION test.
This commit is contained in:
Sergei Trofimovich 2022-09-11 21:28:59 +01:00 committed by Paul Smith
parent 257b82ac1f
commit ca4234c4b5
3 changed files with 20 additions and 1 deletions

View File

@ -25,6 +25,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "variable.h" #include "variable.h"
#include "debug.h" #include "debug.h"
#include "hash.h" #include "hash.h"
#include "shuffle.h"
/* Remember whether snap_deps has been invoked: we need this to be sure we /* Remember whether snap_deps has been invoked: we need this to be sure we
@ -576,6 +577,7 @@ expand_deps (struct file *f)
struct dep **dp; struct dep **dp;
const char *fstem; const char *fstem;
int initialized = 0; int initialized = 0;
int changed_dep = 0;
if (f->snapped) if (f->snapped)
return; return;
@ -664,6 +666,7 @@ expand_deps (struct file *f)
if (new == 0) if (new == 0)
{ {
*dp = d->next; *dp = d->next;
changed_dep = 1;
free_dep (d); free_dep (d);
d = *dp; d = *dp;
continue; continue;
@ -672,6 +675,7 @@ expand_deps (struct file *f)
/* Add newly parsed prerequisites. */ /* Add newly parsed prerequisites. */
fstem = d->stem; fstem = d->stem;
next = d->next; next = d->next;
changed_dep = 1;
free_dep (d); free_dep (d);
*dp = new; *dp = new;
for (dp = &new, d = new; d != 0; dp = &d->next, d = d->next) for (dp = &new, d = new; d != 0; dp = &d->next, d = d->next)
@ -688,6 +692,12 @@ expand_deps (struct file *f)
*dp = next; *dp = next;
d = *dp; d = *dp;
} }
/* Shuffle mode assumes '->next' and '->shuf' links both traverse the same
dependencies (in different sequences). Regenerate '->shuf' so we don't
refer to stale data. */
if (changed_dep)
shuffle_deps_recursive (f->deps);
} }
/* Add extra prereqs to the file in question. */ /* Add extra prereqs to the file in question. */

View File

@ -146,7 +146,7 @@ identity_shuffle_array (void **a UNUSED, size_t len UNUSED)
/* No-op! */ /* No-op! */
} }
/* Shuffle list of dependencies by populating '->next' /* Shuffle list of dependencies by populating '->shuf'
field in each 'struct dep'. */ field in each 'struct dep'. */
static void static void
shuffle_deps (struct dep *deps) shuffle_deps (struct dep *deps)

View File

@ -116,4 +116,13 @@ run_make_test('
', ',
'--shuffle=reverse a_ b_ c_', "a_\nb_\nc_"); '--shuffle=reverse a_ b_ c_', "a_\nb_\nc_");
# Check if SECONDEXPANSION targets also get reshuffled.
run_make_test('
.SECONDEXPANSION:
all: $$(var)
%_: ; @echo $@
var = a_ b_ c_
',
'--shuffle=reverse', "c_\nb_\na_");
1; 1;