HermitCrab: unhandled NullReferenceException in Morpher.ParallelSynthesize on an empty InsertSegments PhoneticShape

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

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
68/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Tranquilla
Stack tecnologico
csharp
Ambito
backend

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.hcparser 2.2.3 (the hc .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:

  1. Validation error at load/compile time — e.g. "MorphologicalRule 'afx': InsertSegments has an empty PhoneticShape", with a non-zero but handled exit; or
  2. 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

  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 sillsdev/machine

Tutte le issue di sillsdev/machine

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.