HermitCrab: unhandled NullReferenceException in Morpher.ParallelSynthesize on an empty InsertSegments PhoneticShape
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 68/100
Direzione di ricerca
Inizia da Morpher.cs intorno alla riga 305 e riproduci il crash con la grammatica fornita e il comando hc -i grammar.xml -s script.txt -o out.txt -c. Traccia il percorso con cui un InsertSegments PhoneticShape vuoto raggiunge ParallelSynthesize, quindi aggiungi la coverage per il caso di parse e verifica che produca un errore di validazione gestito oppure un no-op riuscito, invece di un’eccezione non gestita.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Unhandled NullReferenceException in Morpher.ParallelSynthesize when a MorphologicalRule's InsertSegments has an empty PhoneticShape
Component: SIL.Machine.Morphology.HermitCrab (HermitCrab morphological parser) — used via the hc CLI (SIL.Machine.HCParser).
Severity: Medium. A grammar-authoring mistake (an empty insertion shape) crashes the whole process with an unhandled exception instead of being reported as a grammar/validation error. The grammar compiles and loads cleanly ("Compiling rules... done", " loaded"); the crash happens at parse time, so it is easy to mistake for a parser bug in otherwise-valid grammars.
Environment
sil.machine.hcparser2.2.3 (thehc.NET global tool), .NET (DOTNET_ROLL_FORWARD=LatestMajor).- OS: Windows 11.
- Build paths in the stack trace:
C:\projects\machine\src\SIL.Machine.Morphology.HermitCrab\Morpher.cs.
Summary
A MorphologicalRule (affix process) whose MorphologicalOutput contains
<InsertSegments><PhoneticShape></PhoneticShape></InsertSegments> (an empty phonetic shape) causes
hc.exe to throw an unhandled System.NullReferenceException during synthesis when any word is parsed.
The configuration compiles without error; the exception is only raised at parse time, inside
Morpher.ParallelSynthesize (HC verifies each analysis by re-synthesizing it).
Minimal reproduction
Self-contained grammar (one root tu, one affix rule that inserts an empty shape before the stem):
<?xml version="1.0" encoding="utf-8"?>
<HermitCrabInput><Language><Name>x</Name>
<PartsOfSpeech><PartOfSpeech id="root"><Name>root</Name></PartOfSpeech></PartsOfSpeech>
<PhonologicalFeatureSystem><SymbolicFeature id="seg" defaultSymbol="g0"><Name>seg</Name>
<Symbols><Symbol id="g0">g0</Symbol><Symbol id="g1">g1</Symbol></Symbols></SymbolicFeature>
</PhonologicalFeatureSystem>
<CharacterDefinitionTable id="t1"><Name>m</Name><SegmentDefinitions>
<SegmentDefinition id="s_t"><Representations><Representation>t</Representation></Representations>
<FeatureValue feature="seg" symbolValues="g0"/></SegmentDefinition>
<SegmentDefinition id="s_u"><Representations><Representation>u</Representation></Representations>
<FeatureValue feature="seg" symbolValues="g1"/></SegmentDefinition>
</SegmentDefinitions></CharacterDefinitionTable>
<NaturalClasses><SegmentNaturalClass id="any"><Name>any</Name>
<Segment segment="s_t"/><Segment segment="s_u"/></SegmentNaturalClass></NaturalClasses>
<Strata><Stratum characterDefinitionTable="t1" morphologicalRuleOrder="unordered"
morphologicalRules="afx"><Name>main</Name><MorphologicalRuleDefinitions>
<MorphologicalRule id="afx" requiredPartsOfSpeech="root" outputPartOfSpeech="root"><Name>afx</Name>
<MorphologicalSubrules><MorphologicalSubrule id="afxs"><MorphologicalInput>
<PhoneticSequence id="st"><OptionalSegmentSequence min="1" max="-1"><SimpleContext naturalClass="any"/>
</OptionalSegmentSequence></PhoneticSequence></MorphologicalInput><MorphologicalOutput>
<InsertSegments><PhoneticShape></PhoneticShape></InsertSegments> <!-- EMPTY shape -->
<CopyFromInput index="st"/></MorphologicalOutput></MorphologicalSubrule></MorphologicalSubrules>
<Gloss>afx</Gloss></MorphologicalRule></MorphologicalRuleDefinitions>
<LexicalEntries><LexicalEntry id="e0" partOfSpeech="root"><Allomorphs>
<Allomorph id="e0a"><PhoneticShape>tu</PhoneticShape></Allomorph></Allomorphs><Gloss>tu</Gloss>
</LexicalEntry></LexicalEntries></Stratum></Strata></Language></HermitCrabInput>
Run:
hc -i grammar.xml -s script.txt -o out.txt -c # script.txt contains: parse tu
Actual result
Reading configuration file "grammar.xml"... done.
Compiling rules... done.
x loaded.
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at SIL.Machine.Morphology.HermitCrab.Morpher.ParallelSynthesize(IEnumerable`1 analyses) in C:\projects\machine\src\SIL.Machine.Morphology.HermitCrab\Morpher.cs:line 305
at SIL.Machine.Morphology.HermitCrab.Morpher.ParseWord(String word, Object& trace) in C:\projects\machine\src\SIL.Machine.Morphology.HermitCrab\Morpher.cs:line 114
at SIL.Machine.Morphology.HermitCrab.ParseCommand.Run(String[] remainingArguments) in C:\projects\machine\src\SIL.Machine.HCParser\ParseCommand.cs:line 30
at ManyConsole.ConsoleCommandDispatcher.DispatchCommand(...)
at SIL.Machine.Morphology.HermitCrab.Program.Main(String[] args) in C:\projects\machine\src\SIL.Machine.HCParser\Program.cs:line 95
The process exits abnormally and writes no output file.
Expected result
Either:
- Validation error at load/compile time — e.g. "MorphologicalRule 'afx': InsertSegments has an empty PhoneticShape", with a non-zero but handled exit; or
- The empty insertion is treated as a no-op (insert nothing) and parsing proceeds normally.
Crashing with an unhandled NullReferenceException at parse time is the problem regardless of which is chosen.
Notes on how it arises in practice
We hit this when programmatically generating affix-process rules: the inserted PhoneticShape was built from characters that were not all present in the grammar's CharacterDefinitionTable, so the shape encoded to an empty string. The grammar still compiled, then every parse crashed. A clear validation message (or a tolerant no-op) would have turned a hard-to-localize crash into an obvious authoring error. (A related hardening: reject/validate an InsertSegments PhoneticShape containing representations not defined in the character table.)
Suggested fix
Guard Morpher.ParallelSynthesize (Morpher.cs:~305) against an affix process that inserts an empty/!null segment shape, and/or validate non-empty InsertSegments PhoneticShape (with all representations defined in the CharacterDefinitionTable) at rule-compile time.
- Lingua principale
- C#
- Stelle
- 29
- Fork
- 17
- Merge medio
- 3g 2h
- PR unite (30g)
- 8
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di sillsdev/machine
-
Environment matchers pay for captures they never read; key the traversal on what the caller consumes Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 45/100
-
enhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
-
HermitCrab: Word.ExpandAlternatives discards Unify's success flag and can null the realizational FS Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 38/100
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 42/100
Tutte le issue di sillsdev/machine
Issue simili
-
type/automation type/tech-debt
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
t/bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
ci-failure-cause test-failure
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
area:auth FE mvp P3
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
klasolsson81/jobbliggaren#1788 ·