11 Punkte von GN⁺ 2026-01-01 | 5 Kommentare | Auf WhatsApp teilen
  • Das cURL-Projekt hat nach der früheren Entfernung von strncpy() nun auch strcpy() vollständig in der Codebasis verboten
  • Die API von strcpy() ist zwar einfach, birgt aber das Risiko, dass die Prüfung der Puffergröße vom Kopiervorgang getrennt wird, was bei langfristiger Wartung unsicher ist
  • Als Ersatz wurde die neue Funktion curlx_strcopy() eingeführt, die sowohl die Größe des Zielpuffers als auch die Länge der Zeichenkette als Argumente erhält und vor dem Kopieren prüft, ob der Vorgang möglich ist
  • Intern verwendet die Funktion memcpy() und garantiert auch die Behandlung des Null-Terminators
  • Durch diese Änderung sollen Sicherheit und Konsistenz des Codes verbessert und zugleich Probleme reduziert werden, bei denen KI fälschlich Schwachstellenmeldungen erzeugt

Hintergrund zur Entfernung von strcpy

  • cURL hat in der Vergangenheit bereits alle Aufrufe von strncpy() entfernt und auf die Probleme dieser Funktion hingewiesen: eine unintuitive API, keine garantierte Null-Terminierung und unnötiges Auffüllen mit 0-Werten
    • Wenn Teilstrings kopiert werden müssen, wurde auf memcpy() umgestellt und die Null-Terminierung direkt behandelt
  • Die API von strcpy() ist zwar simpel, nennt aber keine Puffergröße ausdrücklich, wodurch bei der Wartung das Risiko entsteht, dass Prüfcode und Kopieraufruf voneinander getrennt werden
    • Wenn Code über Jahrzehnte von verschiedenen Entwicklern geändert wird, besteht die Möglichkeit, dass die Prüfung der Puffergröße ausgehebelt wird

Einführung einer neuen String-Kopierfunktion

  • Um dieses Risiko zu vermeiden, wurde die Ersatzfunktion curlx_strcopy() eingeführt
    • Sie nimmt als Argumente Zielpuffer, Puffergröße, Quellpuffer und Länge der Quellzeichenkette entgegen
    • Sie führt den Kopiervorgang nur dann mit memcpy() aus, wenn sowohl das Kopieren als auch die Null-Terminierung möglich sind
    • Im Fehlerfall wird der Zielpuffer als leerer String initialisiert
  • Diese Funktion benötigt im Vergleich zu strcpy() mehr Argumente und mehr Code, stellt die Sicherheit jedoch dadurch sicher, dass die Pufferprüfung eng an den Kopiervorgang gekoppelt ist
  • Die Verwendung von strcpy() wurde in der cURL-Codebasis vollständig verboten und damit ebenso entfernt wie strncpy()

Implementierungsdetails

  • Ein Beispiel für die Funktionsdefinition sieht wie folgt aus
    void curlx_strcopy(char *dest, size_t dsize, const char *src, size_t slen)
    {
      DEBUGASSERT(slen < dsize);
      if(slen < dsize) {
        memcpy(dest, src, slen);
        dest[slen] = 0;
      }
      else if(dsize)
        dest[0] = 0;
    }
    
  • Mit DEBUGASSERT werden Fehler während der Entwicklung früh erkannt, während die Funktion für echte Deployment-Umgebungen so ausgelegt ist, dass sie immer erfolgreich arbeitet
  • Wie strcpy gibt sie keinen Rückgabewert zurück; stattdessen setzt man darauf, Fehler in Test- und Fuzzing-Phasen zu finden

Reaktionen aus der Community

  • Einige Entwickler merkten an, dass dies strcpy_s() (C11 Annex K) ähnele, cURL verwende jedoch weiterhin den C89-Standard
  • Andere Stimmen schlugen vor, einen Rückgabewert hinzuzufügen oder die Behandlung bei Pufferfehlern zu verbessern
  • Darauf erklärte cURL, ein Rückgabewert sei unnötig, weil die Funktion „so entworfen wurde, dass sie immer erfolgreich ist“

Zusätzlicher Effekt im Zusammenhang mit KI

  • Durch diese Änderung lässt sich verhindern, dass KI-Chatbots die Verwendung von strcpy im cURL-Code fälschlich erkennen und als „verwundbar“ bezeichnen
  • Der Autor merkte jedoch an, dass KI weiterhin andere falsche Meldungen erzeugen könnte, und verwies damit auf die Grenzen KI-basierter Codeanalyse

5 Kommentare

 
ahwjdekf 2026-01-02

Statt strcpy sollte man besser snprintf verwenden. Wenn im Code strcpy vorkommt, sollte man die Adresse des Entwicklers herausfinden, der das eingebaut hat.

 
winmain 2026-01-02

Das war eine Arbeitsweise, die ich vor 25 Jahren, als ich bei einer Spielefirma arbeitete, mit Debug-Code umgesetzt habe – und es war sicher nicht nur strcpy. Im Release wurde das für mehr Geschwindigkeit wieder gelockert und so in den Service übernommen. Tatsächlich ist man gerade im Games-Bereich bei Speicherkonflikten am empfindlichsten, deshalb arbeitet man auch extrem sorgfältig und aufmerksam, und wir haben sogar eigene Memory-Debugger gebaut und verwendet. Aber wenn ich heute darüber nachdenke, merke ich: Das war im Grunde schon dabei, eine Garbage Collection zu bauen. Eine wehmütige Erinnerung.

 
secwind 2026-01-02

Fehler C4996: 'strcpy': Diese Funktion oder Variable ist möglicherweise unsicher. Erwägen Sie stattdessen die Verwendung von strcpy_s. Um die Veraltungsmeldung zu deaktivieren, verwenden Sie _CRT_SECURE_NO_WARNINGS. Weitere Details finden Sie in der Onlinehilfe.

 
GN⁺ 2026-01-01
Hacker-News-Kommentare
  • strcpy() ist nicht nur in puncto Sicherheit problematisch, sondern auch leistungstechnisch schlecht
    Früher dachte man, strcpy() sei effizient, wenn man die Stringlänge nicht kennt, aber tatsächlich kopiert es Byte für Byte, sodass die CPU Branch Prediction betreiben muss, was ineffizient ist

    • Ich denke, man sollte inzwischen den null-terminierten String selbst möglichst aufgeben
    • In letzter Zeit habe ich nicht gesehen, dass strcpy eine skalare Schleife verwendet. Ich frage mich, ob das nur auf der ARM-Architektur so ist
  • Die String-Routinen in C haben alle große Einschränkungen, sodass sie sich kaum sinnvoll verwenden lassen
    Deshalb halte ich eine Bibliothek für nötig, die zusammen mit dem String-Pointer auch die Größe des allokierten Speichers festhält
    Als Beispiel kann man die bstring-Bibliothek ansehen

    • strncpy wurde eingeführt, um Dateinamen mit fester Länge zu kopieren. Siehe dazu diese StackOverflow-Antwort
    • Dass Strings keine Längeninformation enthalten, lag früher an der Speicherersparnis. Damals war selbst ein einzelnes Byte wertvoll
    • Dass die String-Funktionen in C Probleme verursacht haben, liegt daran, dass die Entwickler sie hinzugefügt haben, ohne die Folgen vollständig vorherzusehen. Dass Arrays in Funktionsargumenten zwangsweise zu Zeigern umgewandelt werden, ist ebenfalls ein grundlegender Designfehler
    • Solches zusätzliches Book-keeping war früher eine Belastung, heute ist es aber gut tragbar
    • strncpy war ursprünglich für Strings mit fester Feldbreite gedacht. Zum Beispiel, um ein Feld wie char username[20] mit NUL-Zeichen aufzufüllen. Siehe dazu das Manual string_copying.7
  • Es ist seltsam, dass curlx_strcopy keinen Erfolgsstatus zurückgibt
    Man könnte zwar dest[0] prüfen, aber das ist fehleranfällig und unintuiv

    • Frühere Versionen gaben einen Fehler zurück, jetzt schlägt es stillschweigend fehl und setzt einen leeren String. Das ist merkwürdig
    • Vermutlich gilt es als Erfolg, wenn DEBUGASSERT(slen < dsize); durchläuft, aber in Release-Builds kann assert entfernt sein. Ein expliziter Fehlercode wäre besser
    • Bei so einem Design halte ich es für wahrscheinlich, dass später noch eine CVE auftaucht
  • strncpy() war ursprünglich nicht für null-terminierte Strings gedacht, sondern für Felder fester Länge
    Das Problem begann, als statische Analysewerkzeuge empfahlen, statt strcpy einfach strncpy zu verwenden. Die tatsächlichen Alternativen waren snprintf oder strlcpy

    • strlcpy ist eine BSD-Funktion und nicht Teil von POSIX. Offiziell empfohlen wird stpecpy, aber real existierende Implementierungen gibt es kaum. Siehe die zugehörige Dokumentation
    • Dass strncpy nach dem NUL-Zeichen auffüllt, diente effizienten Vergleichen bei Namensfeldern fester Länge wie Verzeichniseinträgen. So steht es auch in den Begründungsdokumenten zum ANSI-C-Standard
  • Diese API fühlt sich ein wenig wie Annex-K an. Im Zielpuffer ist der Platz für NUL in der Größenangabe enthalten, bei der Quellgröße jedoch nicht
    Ich denke, es wäre besser, einfach direkt memcpy zu verwenden

  • Im Artikel blieb mir die Formulierung in Erinnerung, dass „strcpy ein Köder für von AI erzeugte falsche Schwachstellenberichte“ sei

    • Tatsächlich weist AI nicht bloß schlicht auf strcpy als Problem hin, sondern erzeugt komplexe Begründungen mit logischen Fehlern, die Maintainer dann mühsam überprüfen müssen
    • Die Leute, die solche falschen Reports einreichen, wissen entweder nicht, dass AI irren kann, oder es ist ihnen egal. Schließlich kostet selbst eine falsche Meldung nichts
    • Am Ende liegt das Problem bei den Menschen, die AI für ungeeignete Zwecke einsetzen
  • Das Prinzip „in der Nähe des Codes prüfen“ ist gut, aber es wird unklar, wenn man früh im Lebenszyklus der Daten prüfen muss
    Es wäre gut, wenn man wie beim Result-Typ in Rust per Typ ausdrücken könnte, dass es sich um „validierte Daten“ handelt

    • Result enthält nur Erfolg oder Fehler, garantiert aber keinen validierten Zustand. Besser wäre ein eigener Typ, der nur nach einem Validierungsschritt erzeugt werden kann. Das ist die Philosophie „parse, don’t validate
    • Idealerweise sollte die Validierung nicht nahe am konsumierenden Code stattfinden, sondern so früh wie möglich an der Systemgrenze. Dafür braucht man allerdings ein ausdrucksstarkes Typsystem
    • In solchen Fällen kann man Typen auch wie bei String und CharSequence in Java voneinander trennen
  • Der Off-by-one-Unterschied zwischen Puffergröße und Stringlänge ist ein schreckliches Usability-Problem. Er wird wahrscheinlich auch künftig Fehler verursachen

  • Die neu vorgeschlagene String-Kopierfunktion leert den Zielpuffer, wenn das Kopieren nicht möglich ist, und gibt void zurück
    In so einem Fall wäre es meiner Meinung nach besser, dies als Fehler zu behandeln und den Puffer unberührt zu lassen. Sich nur auf DEBUGASSERT zu verlassen, wirkt unsicher

  • Glückwunsch zum Abschluss des Projekts. Auch in C/C++ kann man sich mit genügend Aufwand Speichersicherheit erarbeiten
    Allerdings ist in der mobilen Ansicht die Schriftgröße der Grafiken zu klein, was die Lesbarkeit verschlechtert

    • Dass strcpy entfernt wurde, bedeutet nicht, dass der Code damit automatisch speichersicher ist
    • Die Schrift in den Grafiken wirkt, als sei sie für den Druck entworfen worden. Für einen Blog ist sie zu klein
 
hiongun 2026-01-04

Es ist auch eine gute Idee, komplett auf die Sprache C3 umzusteigen. Es ist ein Projekt, das die C-Syntax nur minimal verändert und moderne Funktionen hinzufügt, sodass die Umstellung leichtfällt.