37Limits für fremde Eingaben & Thread-Sicherheit
Etiketten aus Uploads, Webdiensten, ERP-Schnittstellen oder von Coding-Agents sind fremde Eingaben. zplCore begrenzt, was solche Eingaben kosten dürfen – Etiketten, Punkte, Grafiken, Felddaten, Druckerspeicher, Bilddateien – und legt fest, welche Klassen zwischen Threads geteilt werden dürfen.
ZplLimits: ein Bereich für alles
Für fremde Eingaben (Uploads, Webdienste, Agents) setzt ZplLimits.Enforce harte Grenzen für jeden Renderer im Bereich – auch für die, die Compliance-Check, Scan-Proof, Import, Extraktion, GS1-Migration, Printer Twin, Cut-Plan und Vector-Lift intern anlegen, über Tasks und Parallel hinweg. Einstellungen werden auf den strengeren Wert gekappt, Schriftquellen, Systemschriften und Hintergrundbilder abgeschaltet; optional eine feste Uhr. Der MCP-Server führt jeden Aufruf in diesem Bereich aus.
// using ZplCore.Compliance;
using (ZplLimits.Enforce(new ZplLimits { MaxLabels = 10, MaxGraphicBytes = 4 << 20, FixedClock = DateTime.UnixEpoch }))
{
// gilt für jeden Renderer in diesem Bereich – auch die, die Compliance, Scan-Proof,
// Import, Extraktion, Printer Twin und Vector-Lift intern anlegen (auch über Tasks/Parallel)
var report = ZplCompliance.Check(untrusted, CompliancePacks.Gs1LogisticLabel);
}
Bilder und Dateien: Im Bereich lesen Bild-Elemente (sourceFile oder ein Pfad in gebundenen Daten) keine lokalen Dateien, außer sie liegen unter einem der AllowedImageRoots (Standard: keiner; keine Links unterhalb des Ordners) – eine abgewiesene, fehlende oder unlesbare Datei ergibt immer dieselbe Antwort, Pfade lassen sich so nicht abtasten. Bilder werden vor dem Dekodieren gegen MaxImageBytes, MaxSvgBytes und MaxImagePixels geprüft (Größe aus dem Header, SVG-Raster und skaliertes Zielraster; Überschreitung wirft ZplLimitExceededException). Ein CancellationToken beendet Rendern und Etikett-Erzeugung beim nächsten Befehl bzw. Etikett, so kann ein Host die Arbeit an seinem Zeitlimit abbrechen. Außerhalb eines Bereichs ändert sich nichts: das SDK liest Bilddateien wie bisher.
using (ZplLimits.Enforce(new ZplLimits { AllowedImageRoots = ["/srv/label-images"], MaxImagePixels = 16_000_000,
MaxImageBytes = 4 << 20, CancellationToken = requestTimeout.Token }))
zpl = label.ToZpl(records);
Weitere Mitglieder: MaxQuantity, MaxLabelDots, MaxLabelSide, MaxFieldDataLength, MaxStoreBytes (Druckerspeicher) und Isolated (Standard true: kein FontProvider, keine Systemschriften, kein Hintergrund- oder Wasserzeichenbild, kein Cache dekodierter Grafiken – Schriften kommen dann nur aus Downloads in derselben Eingabe, ~DY/~DU). Eine nicht gesetzte Grenze ist unbegrenzt; verschachtelte Bereiche gelten zusammen mit den strengsten Werten (Bildordner: nur was jeder Bereich erlaubt; jedes Token bricht ab). ZplLimits.Current liefert die geltenden Grenzen, ZplLimitExceededException.Limit nennt die überschrittene Eigenschaft, z. B. "MaxImagePixels".
Limits für fremde Eingaben & Thread-Sicherheit
Standardwerte: MaxLabelSide 32000, MaxLabelDots 64 Mio., MaxQuantity 10000, MaxLabels 100000, MaxGraphicBytes 32 MB (auch Z64-Entpackgrenze gegen Zip-Bomben), MaxFieldDataLength 1 Mio., ZplResourceStore.MaxTotalBytes 256 MB. ZplRenderer/EplRenderer halten Druckerzustand und sind nicht thread-sicher – ein Renderer pro Thread; ZplResourceStore, FontManager, ZplCaches, PropertyPath und konfigurierte LabelBindings sind es. ConcurrencyTests vergleicht SHA-256 aller Ausgaben von 16 Threads mit dem Einzel-Thread-Lauf; samples/FuzzRunner füttert den Parser mit Zufalls- und mutierten Eingaben, samples/LeakTest rendert 1 Mio. Etiketten und protokolliert Heap und RSS. Details: THREADING.md, DIAGNOSTICS.md.
var shared = new ZplResourceStore(); // thread-safe, von vielen Renderern teilbar
var safe = new ZplRenderSettings
{
MaxLabelSide = 8000, MaxLabelDots = 16_000_000, MaxQuantity = 100,
MaxLabels = 1000, MaxGraphicBytes = 4 * 1024 * 1024, MaxFieldDataLength = 10_000,
};
Parallel.For(0, 8, _ =>
{
var r = new ZplRenderer(safe) { Store = shared }; // ein Renderer pro Thread
r.ProcessCommands(untrusted);
});

