C/C++: Maximale Größe von errno-assoziierten Strings (zur Kompilierzeit)

Lesezeit: 9 Minuten

Benutzer-Avatar
mtraceur

Frage

Gibt es eine Möglichkeit, die maximale Größe einer Zeichenfolge zu ermitteln, mit der korreliert wird? errno zur Kompilierzeit (zur Präprozessorzeit wäre noch besser)? ZB eine Obergrenze an strlen(strerror(errno))?

Meine Gedanken

Das Beste, was ich mir vorstellen kann, ist, ein Programm auszuführen, um eine Brute-Force-Suche über den Bereich eines int, über jedes Gebietsschema durchzuführen, um die mit jedem {errno, locale}-Paar verknüpfte Zeichenfolge zu erhalten, ihre Größe zu erhalten und einen Header zu generieren auf diesem System, dann das Einhängen in zB ein Makefile oder Autoconf oder was auch immer. Ich kann mir keinen besseren Weg vorstellen, aber es scheint lächerlich, dass es so wäre: Die Standardbibliothek für ein System hat diese Informationen eingebaut, wenn auch nur implizit. Gibt es wirklich keine gute Möglichkeit, diese Informationen zu erhalten?

Okay, ich gebe zu, dass die C- und/oder C++-Standards möglicherweise Fehlerzeichenfolgen zulassen, die zur Laufzeit generiert werden, z. B. mit umstandsspezifischen Meldungen (z strerror(EINVAL) Geben Sie eine Zeichenfolge an, die von einem anderen Laufzeit-Metadatensatz abgeleitet wurde, wenn errno wurde zuletzt eingestellt oder so) – nicht sicher, ob das so ist ist erlaubt, und ich würde eine solche Implementierung eigentlich begrüßen, aber ich habe noch nie von einer gehört, die dies tat oder mehr als eine Zeichenfolge für eine bestimmte {errnolocale}-Paar.

Motivation

Was ich speziell wollte (aber ich denke, diese Frage ist allgemeiner wertvoll, wie in den Kommentaren besprochen wurde), was zu dieser Frage geführt hat, war, die zugehörige Fehlerzeichenfolge verwenden zu können errno im Systemaufruf/Funktion writev. In meinem speziellen Anwendungsfall habe ich Zeichenfolgen aus verwendet argv und errno-verknüpfte Saiten. Dies stellte meine “Worst-Case” -Länge auf ein ARG_MAX + some max errno string length + size of a few other small strings).

Jedes *nix-Dokument, das ich konsultiert habe, scheint darauf hinzudeuten writev wird (oder “darf”, für den geringen Nutzen, den dieser Unterschied in diesem Fall ausmacht) einen Fehler machen errno einstellen EINVAL wenn die Summe der iov_len Werte überlaufen SSIZE_MAX. Intuitiv kenne ich jeden errno Saite, die ich gesehen habe, ist sehr kurz, und in der Praxis ist dies kein Problem. Aber ich möchte nicht, dass mein Code auf irgendeinem System auf mysteriöse Weise überhaupt keinen Fehler ausgibt, wenn es möglich ist, dass diese Annahme falsch ist. Also habe ich Code geschrieben, um einen solchen Fall zu handhaben – aber gleichzeitig möchte ich nicht, dass dieser zusätzliche Code für die Plattformen einkompiliert wird, die ihn im Allgemeinen eindeutig nicht benötigen.

Die kombinierte Eingabe der bisherigen Antworten und Kommentare lässt mich zu der Annahme neigen, dass in meinem speziellen Anwendungsfall die “richtige” Lösung darin besteht, obszön lange Nachrichten einfach abzuschneiden – aber deshalb habe ich die Frage gestellt, wie ich es ursprünglich gemacht habe: solche Informationen würden auch bei der Auswahl einer Größe für einen Puffer helfen strerror_r/strerror_s (jeweils *nix/Windows) und sogar eine negative Antwort (zB “das kannst du wirklich nicht”) ist meiner Meinung nach nützlich für die Aufklärung anderer.

Verwandt

Diese Frage enthält Antworten für die von angegebenen Strings strerror_r auf VxWorks, aber ich fühle mich nicht wohl dabei, das auf alle Systeme zu verallgemeinern.

  • C und C++ sind verschiedene Sprachen!

    – zu ehrlich für diese Seite

    30. März 2016 um 20:20 Uhr

  • @Olaf Obwohl ich Ihre Bemühungen, diese Unterscheidung deutlich zu machen, im Allgemeinen schätze, glaube ich, dass es in diesem Fall legitim ist, von C und C++ zusammen zu sprechen errno Konzept wird von beiden gleichermaßen verwendet. Es wäre willkürlich, eines der Tags dem anderen vorzuziehen.

    – 5gon12eder

    30. März 2016 um 20:25 Uhr


  • Können Sie Ihr eigenes Maximum wählen und die Fehlermeldungen zur Laufzeit abschneiden?

    – xrgb

    30. März 2016 um 20:30 Uhr

  • Mir fehlt vielleicht etwas, aber eine Fehlermeldung, die größer als ssize_t ist, scheint auf jeder Plattform, auf der ssize_t größer als int8_t ist, völlig verrückt zu sein.

    – zneak

    30. März 2016 um 20:35 Uhr

  • Der C-Standard (und ich vermute der C++-Standard) wird diesbezüglich nicht weiterhelfen SSIZE_MAX wie es nicht definiert SSIZE_MAX. Wenn SSIZE_MAX für Ihren Code wichtig ist, schlagen Sie vor, die Umgebung von Interesse zu markieren, die sie definiert.

    – chux – Wiedereinsetzung von Monica

    30. März 2016 um 21:01 Uhr

Die C-Bibliothek, mit der Sie bauen, ist möglicherweise nicht dieselbe (ABI-kompatible C-Bibliothek wird möglicherweise verwendet) oder sogar die exakte Version der C-Bibliothek (unter GNU/Linux betrachten Sie glibc 2.2.5 vs. glibc 2.23), mit der Sie arbeiten, daher Computing die maximale Größe der vom Gebietsschema abhängigen Zeichenfolge, die zurückgegeben wird strerror kann nur zur Laufzeit während der Prozessausführung durchgeführt werden. Darüber hinaus können die Locale-Übersetzungen jederzeit auf dem Zielsystem aktualisiert werden, was wiederum jede Vorabberechnung dieser Obergrenze ungültig macht.

Leider gibt es keine Garantie, dass die zurückgegebenen Werte von strerror für die Lebensdauer des Prozesses konstant sind, und sich daher auch zu einem späteren Zeitpunkt ändern können, wodurch eine frühe Berechnung der Schranke hinfällig wird.

Ich empfehle die Verwendung strerror_r um die Fehlerzeichenfolge zu speichern und Probleme mit nicht Multi-Thread-fähigen Bibliotheken zu vermeiden, die möglicherweise sterror aufrufen und möglicherweise das Ergebnis der Zeichenfolge ändern, während Sie sie kopieren. Anstatt die Zeichenfolge spontan zu übersetzen, würden Sie dann das gespeicherte Ergebnis verwenden und möglicherweise abschneiden SSIZE_MAX (wird in der Realität nie passieren).

  • +1, beachten Sie jedoch, dass es großartig wäre, eine Obergrenze zu haben, um eine Größe für den übergebenen Puffer auszuwählen strerror_r Außerdem wird der Bedarf an Laufzeitlogik reduziert. Außerdem hatte ich die Maxima-könnte-aus-unter-Ihrem-Programm-Situation berücksichtigt und war mir dessen bewusst – aber ich hatte gehofft, dass es eine Standardbeschränkung oder zumindest plattformspezifische Makros gibt, die wir überprüfen könnten zumindest einige Systeme, die dies möglicherweise für zumindest einige Systeme zu einem Nicht-Problem gemacht haben könnten, daher die Frage.

    – mtraceur

    30. März 2016 um 21:40 Uhr

  • Insbesondere ist es bemerkenswert, dass POSIX (gemäß Ihrem Link) dies zulässt strerror_r mit einem scheitern ERANGE Wenn der Puffer nicht groß genug ist: Meine Lektüre legt nahe, dass eine Implementierung, die zuerst die Länge überprüft und Fehler ausgibt, ohne etwas zu schreiben, standardkonform wäre. Ich möchte glauben, dass keine Implementierung dies tut, oder ich lese falsch, aber wenn ja, dann scheint es, als müssten wir uns, ohne eine Obergrenze zu kennen, entweder auf der Seite eines mäßig großzügigen Puffers irren, um ihn zu halten, oder einer Schleife, um ihn neu zuzuweisen bis es Erfolg bringt?

    – mtraceur

    31. März 2016 um 6:22 Uhr

  • Es gibt keine Garantie dafür, dass die strerrorbuf wurde durch einen Aufruf an geändert strerror_r die zurückkam ERANGE. Sie müssen also darauf vorbereitet sein, die verschiedenen Kombinationen von Rücksendungen zu handhaben, wie sie im normativen Text der Norm angegeben sind.

    – Carlos O’Donell

    1. April 2016 um 15:46 Uhr

  • Nach ein paar Tagen des Nachdenkens akzeptiere ich diese Antwort (vorläufig), weil sie sowohl 1) allgemein ist als auch 2) die gründlichsten Erklärungen dafür liefert, warum solche Informationen zur Kompilierzeit nicht verfügbar sein könnten (und vielleicht nicht sollten). viele Implementierungen.

    – mtraceur

    1. April 2016 um 17:35 Uhr


Mir ist nicht bekannt, dass die C- oder C++-Standards Aussagen zur Länge dieser Nachrichten machen. Die Plattformen, an denen Sie interessiert sind, bieten jedoch möglicherweise stärkere implementierungsdefinierte Garantien.

Für POSIX-Systeme habe ich beispielsweise Folgendes gefunden in limits.h.

Die folgenden Konstanten müssen in allen Implementierungen definiert werden <limits.h>:

  • […]
  • {NL_TEXTMAX}

    Maximale Anzahl von Bytes in einer Nachrichtenzeichenfolge.
    Akzeptabler Mindestwert: {_POSIX2_LINE_MAX}

Ich glaube, dass Fehlermeldungen von erzeugt werden strerror würden in diese Kategorie fallen.

Das heißt, ich kann dieses Makro nicht auf mein System bekommen. Allerdings habe ich _POSIX2_LINE_MAX (aus <unistd.h>). es ist #defined bis 2048. Da die Norm nur sagt, dass dies eine Untergrenze ist, ist das vielleicht nicht sehr hilfreich.

  • konnte ich bekommen NL_TEXTMAX definiert durch Definieren _GNU_SOURCE. Ich vermute daher, dass ein ausreichend “hoher” Wert für definiert ist _POSIX_C_SOURCE würde es inklusive bekommen. Jedenfalls war der Wert 0x7fffffffoder 2147483647. Nicht zu inspirierend für sich allein – obwohl SSIZE_MAX war doppelt so breit (8 weitere nachlaufende f Ziffern).

    – mtraceur

    31. März 2016 um 5:06 Uhr


  • Fürs Protokoll, ich habe auch diesem +1 gegeben, und ich schätze die Informationen, die in Bezug auf meinen spezifischen Anwendungsfall gegeben wurden. Obwohl ich derzeit eine andere Antwort akzeptiert habe, denke ich, dass dies die nächstbeste Antwort ist, da sie Informationen abdeckt, die nicht in der Hauptantwort enthalten sind, und (wenn auch nicht schlüssig) darauf hindeutet, dass einige Implementierungen oder andere Standards auf den Sprachspezifikationen aufbauen , könnte tatsächlich eine Art Obergrenze definieren.

    – mtraceur

    1. April 2016 um 17:41 Uhr


Benutzer-Avatar
Colin Basnett

Die Standards geben keine Garantien über die Größenbeschränkungen der nullterminierten Zeichenfolge, die von zurückgegeben wird strerror.

In der Praxis wird dies nie ein Problem sein. Wenn Sie jedoch so paranoid sind, würde ich vorschlagen, dass Sie einfach die Zeichenfolge kopieren, von der zurückgegeben wird strerr und klemmen Sie seine Länge an SSIZE_MAX bevor Sie es weitergeben writev.

  • Ich bin geneigt zuzustimmen, dass der Standard in diesem Bereich keine Garantie gibt, aber ich glaube nicht, dass cppreference.com eine maßgebliche Referenz dafür ist.

    – Johannes Bollinger

    30. März 2016 um 20:43 Uhr

Davon kann man getrost ausgehen SSIZE_MAX ist größer als die längste Zeichenfolge (Zeichen-Array), die strerror in einem normalen C- oder C++-System zurückgibt. Dies liegt daran, dass der nutzbare Systemspeicher (der direkt von Ihrem C-Programm genutzt werden kann) nicht größer sein darf als SIZE_MAX (ein vorzeichenloser ganzzahliger Wert) und SSIZE_MAX wird mindestens die gleiche Anzahl von Bits haben, so dass SSIZE_MAX mindestens die Hälfte der Größe des Systemspeichers haben wird, wenn man die 2er-Komplement-Mathematik verwendet, um die vorzeichenbehaftete Natur von SSIZE_MAX (und ssize_t) zu berücksichtigen.

1062760cookie-checkC/C++: Maximale Größe von errno-assoziierten Strings (zur Kompilierzeit)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy