A differential run can carry a killed outcome onto a surviving mutant and exit 0

Aperta
#21 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 3 giorni

@andrewmolyuk ci sta già lavorando.

Dal 30/10/2026.

  • #23 di @andrewmolyuk — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
35/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Ferma
Stack tecnologico
go, python
Ambito
devtools, testing

Direzione di ricerca

Read functions.mutation_id, _select, and _carry_forward, then trace how mutation IDs and form digests are built and reused. Reproduce the reported Go case with the 7-byte comment and compare it with --mutate-all and the 8-byte comment case. Done means the differential run preserves the surviving mutant’s outcome correctly and avoids rerunning unaffected functions; pull request #23 is already open.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

A mutation id holds the site's byte offsets in the file. When text above an unchanged function moves it by exactly the distance between two identical sites in it, a site takes the id its neighbour had in the last run. It inherits that outcome without being run.

Repro (mutator a5a0cb8, crapper 6fd92c4, go 1.27.3, macOS 27)

go.mod: module example.com/shop

calc/calc.go:

package calc

func F(a, b, c, d int) (bool, bool) {
	return a > b, c > d
}

calc/calc_test.go (it checks only the second result, so a > b → a >= b survives):

package calc

import "testing"

func TestF(t *testing.T) {
	if _, y := F(0, 0, 1, 1); y {
		t.Fatal("c > d")
	}
}
$ ../mutator/mutator --no-coverage calc/calc.go
SURVIVED  calc/calc.go:4 > -> >=
KILLED    calc/calc.go:4 > -> >=
$ echo $?
3

The snapshot has […,"defn/F",62,63,">",">="] :survived and […,"defn/F",69,70,">",">="] :killed. Now add a 7-byte comment above F, the distance between the two >:

package calc

// ab

func F(a, b, c, d int) (bool, bool) {
	return a > b, c > d
}
$ ../mutator/mutator --no-coverage calc/calc.go
KILLED    calc/calc.go:6 > -> >=
KILLED    calc/calc.go:6 > -> >=
$ echo $?
0

With --verbose, only one mutant runs. The first > is now at 69..70: it takes the killed id and is carried forward. --mutate-all on the same file reports the survivor again and exits 3, as does an 8-byte comment instead of 7.

Cause, as far as I can tell

functions.mutation_id uses site.start and site.end, which are offsets in the file. _select and _carry_forward reuse an outcome when the form's digest is unchanged and the id matches. The digest covers only the function's text, so it does not change when the function moves, while the offsets do.

Why it matters

Used as a gate, the run reports 100% and exits 0 with a surviving mutant. In Go a function often repeats a site, such as err != nil, so an edit above it can line up with a gap between two of them. The same offsets also make every function below an edit rerun all its mutants, which loses most of the gain of a differential run.

Possible fix

Key the id by offsets relative to the start of its form, or by the site's ordinal among identical sites in the form, rather than by offsets in the file.

Lingua principale
Python
Stelle
97
Fork
45
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di unclebob/mutator

Tutte le issue di unclebob/mutator

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.