Discussion:
extern char **environ;
(zu alt für eine Antwort)
Helmut Schellong
2016-09-09 09:38:06 UTC
Permalink
E n v i r o n m e n t
PATH=ppppppp etc.

Unter Windows das Kommando 'set' und unter Unix 'env'
liefern den Inhalt des sogenannten Environments.

Stets das aktuelle Environment liefert 'extern char **environ'.
Das ist ein Pointer auf 'extern char *env[n]'.
In env[] sind Zeichenketten "name=inhalt" eingehängt.
Der Name env[] ist ausgedacht, der reale Name ist unbekannt.

int main(int argc, char **argv, char **envp);
Hier das Environment per envp zum Startzeitpunkt.

execve(..., envp);
Ein eigenes Environment für den neuen Prozeß.

Ich frage mich nur, was ich - ganz genau - von
Any application that directly modifies the pointers to which
the environ variable points has undefined behavior.
zu halten habe.
Ich modifiziere environ nämlich direkt, seit 1995, ohne Probleme.
environ modifiziere ich nicht, aber *environ.

Zum Löschen einer Env-Variablen mache ich:
vorher:
A=aaaaaaaaa
B=bbbbbbbbb
C=ccccccccc
NULL

nachher:
A=aaaaaaaaa
C=bbbbbbbbb
NULL
NULL

Funktioniert makellos.
Muß es IMO auch.

Zum Setzen verwende ich allerding putenv(), setenv().
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
G.B.
2016-09-09 09:52:15 UTC
Permalink
Post by Helmut Schellong
Funktioniert makellos.
Muß es IMO auch.
I.S.v. enthalten in: "es muss undefiniertes Verhalten zeigen"?
Claus Reibenstein
2016-09-09 10:40:19 UTC
Permalink
Post by Helmut Schellong
int main(int argc, char **argv, char **envp);
Diese Form ist "implementation-defined". Hier verlässt Du also bereits
den Standard.
Post by Helmut Schellong
Ich frage mich nur, was ich - ganz genau - von
Any application that directly modifies the pointers to which
the environ variable points has undefined behavior.
zu halten habe.
Was genau ist Dir daran unklar?
Post by Helmut Schellong
[...]
Funktioniert makellos.
Definiere "Funktioniert". Da das Verhalten undefiniert ist, ist
"Funktioniert" eine ziemlich inhaltsleere Aussage.

Ich interpretiere es mal als "macht, was ich erwarte". Wobei wir
natürlich nicht wissen können, was genau Du erwartest.
Post by Helmut Schellong
Muß es IMO auch.
Muss es natürlich nicht. Kann es aber. Steht in keinem Widerspruch zu
"undefined behavior".

Gruß
Claus
Thomas Jahns
2016-09-09 11:13:33 UTC
Permalink
Post by Helmut Schellong
Ich frage mich nur, was ich - ganz genau - von
Any application that directly modifies the pointers to which
the environ variable points has undefined behavior.
zu halten habe.
Ich modifiziere environ nämlich direkt, seit 1995, ohne Probleme.
environ modifiziere ich nicht, aber *environ.
Und das ist ja auch genau, das, was als undefiniert beschrieben ist. Im
wesentlichen bedeutet das "ohne Probleme" wohl, dass Du nicht auf IRIX
gearbeitet hast, WIMRE dort wird man mit SIGSEGV belohnt, wenn man händisch
environ manipuliert, ohne vorher mindestens einmal putenv o.ä. aufgerufen zu haben.
Post by Helmut Schellong
Zum Setzen verwende ich allerding putenv(), setenv().
Und Du benutzt unsetenv(3) jetzt warum nicht?

Thomas
Helmut Schellong
2016-09-09 14:13:49 UTC
Permalink
Post by Thomas Jahns
Post by Helmut Schellong
Ich frage mich nur, was ich - ganz genau - von
Any application that directly modifies the pointers to which
the environ variable points has undefined behavior.
zu halten habe.
Ich modifiziere environ nämlich direkt, seit 1995, ohne Probleme.
environ modifiziere ich nicht, aber *environ.
Und das ist ja auch genau, das, was als undefiniert beschrieben ist. Im
wesentlichen bedeutet das "ohne Probleme" wohl, dass Du nicht auf IRIX
gearbeitet hast, WIMRE dort wird man mit SIGSEGV belohnt, wenn man händisch
environ manipuliert, ohne vorher mindestens einmal putenv o.ä. aufgerufen zu haben.
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.

Die Deklaration von 'environ' enthält kein 'const', und
auch kein 'volatile'. Das ist in POSIX genormt.

Ich lösche dort Einträge, durch Überschreiben von Einträgen
mit anderen gültigen Einträgen (Pointer), von oben nach unten.
Wenn ein Eintrag nicht gefunden wird, findet auch keine
Schreibaktion statt.
Es muß folglich putenv o.ä. zuvor gegeben worden sein.

Es handelt sich um ein normales C-Objekt: char *array[n];
Wenn 'const' fehlt und wenn ich nur bis n-1 zugreife, kann
IMO niemals irgendwas Undefiniertes passieren.
Ich wüßte nicht, daß der C-Standard hierbei UB als möglich beschreibt.
Post by Thomas Jahns
Post by Helmut Schellong
Zum Setzen verwende ich allerding putenv(), setenv().
Und Du benutzt unsetenv(3) jetzt warum nicht?
Die gab es 1995 nicht.
Im Moment sehe ich keinen dringenden Grund, den funktionierenden
C-Code zu ändern.
Wenn es die auf allen relevanten Plattformen gibt, habe ich kein
Problem, das irgendwann zu ändern.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
G.B.
2016-09-09 15:03:19 UTC
Permalink
Post by Helmut Schellong
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.
#include <unistd.h>

int
execve(const char *path, char *const argv[], char *const envp[]);

Wäre es im allg. Falls zulässig, wenn ein compiler envp als
Fassade implementiert, wohinter bspw. eine verkettete Liste oder
eine Tabelle lebt, deren Manipulation nur über setenv, putenv,
unsetenv, erfolgen darf? Z.B. weil die Verwaltung von Prozessvariablen
auf dem Zielsystem das erbittet? Oder weil die Prozesssteuerung
dann richtig Buch führen kann?
Helmut Schellong
2016-09-09 16:17:46 UTC
Permalink
Post by G.B.
Post by Helmut Schellong
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.
#include <unistd.h>
int
execve(const char *path, char *const argv[], char *const envp[]);
Wäre es im allg. Falls zulässig, wenn ein compiler envp als
Fassade implementiert, wohinter bspw. eine verkettete Liste oder
eine Tabelle lebt, deren Manipulation nur über setenv, putenv,
unsetenv, erfolgen darf?
Das darf ein Compiler sicherlich nicht:
char *env[20]; //Statisch!
//...
execve(..., env);
Was soll der Compiler denn da auch speziell dürfen?

char *const*envp;
ist unterschiedlich zu
char * *environ;
Das ist auf den ersten Blick inkonsistent.
Allerdings dürfen Objekte ja beliebig kopiert werden.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-09 15:50:26 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Jahns
Post by Helmut Schellong
Ich frage mich nur, was ich - ganz genau - von
Any application that directly modifies the pointers to which
the environ variable points has undefined behavior.
zu halten habe.
Ich modifiziere environ nämlich direkt, seit 1995, ohne Probleme.
environ modifiziere ich nicht, aber *environ.
Und das ist ja auch genau, das, was als undefiniert beschrieben
ist. Im wesentlichen bedeutet das "ohne Probleme" wohl, dass Du
nicht auf IRIX gearbeitet hast, WIMRE dort wird man mit SIGSEGV
belohnt, wenn man händisch environ manipuliert, ohne vorher
mindestens einmal putenv o.ä. aufgerufen zu haben.
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.
Die Single Unix Specification ist sich ziemlich sicher, dass genau diese
Manipulationen undefiniertes Verhalten darstellen.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html

"Any application that directly modifies the pointers to which the
environ variable points has undefined behavior."

Aus Sicht von ISO C ist es erst recht undefiniert (wie in: "kommt im
Standard nicht vor").
Post by Helmut Schellong
Die Deklaration von 'environ' enthält kein 'const', und
auch kein 'volatile'. Das ist in POSIX genormt.
Die Deklaration von 'argv' enthält auch kein 'const', dennoch ist eine
Manipulation der Pointer unzulässig (die Strings darfst du dagegen
modifizieren).
Post by Helmut Schellong
Ich lösche dort Einträge, durch Überschreiben von Einträgen
mit anderen gültigen Einträgen (Pointer), von oben nach unten.
[...]
Post by Helmut Schellong
Es handelt sich um ein normales C-Objekt: char *array[n];
Wenn 'const' fehlt und wenn ich nur bis n-1 zugreife, kann
IMO niemals irgendwas Undefiniertes passieren.
Ich wüßte nicht, daß der C-Standard hierbei UB als möglich beschreibt.
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.

Ein anderes Verhalten, das durch die in SUS und ISO C spezifizierten
Einschränkungen legitimiert wird ist, dass die Laufzeitumgebung gewisse
Annahmen treffen möchte, welche der Strings per 'malloc' allokiert sind.
Die stürzen hochkant ab, wenn du ihnen einen anderen String unterjubelst.


Stefan
Helmut Schellong
2016-09-09 21:48:16 UTC
Permalink
[...]
Post by Stefan Reuther
Post by Helmut Schellong
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.
Die Single Unix Specification ist sich ziemlich sicher, dass genau diese
Manipulationen undefiniertes Verhalten darstellen.
"Any application that directly modifies the pointers to which the
environ variable points has undefined behavior."
Ich hatte das ja gepostet.
Man weiß aber nicht GANZ GENAU, was der Satz aussagen soll.
Man kann einhängen
o fremde Pointer
o ungültige Pointer
o Pointer, die auf falschen Inhalt zeigen
o Pointer, die auf gleiche Namen= zeigen
o Pointer auf die terminierende NULL setzen...
o etc.
Alles das mache ich nicht und sollte man auch nicht machen.
Es stellt sich doch die Frage, ob absolut jede denkbare Modifikation
des Arrays UB zur Folge haben soll?
Ausdrücklich steht das nicht da.
Post by Stefan Reuther
Post by Helmut Schellong
Die Deklaration von 'environ' enthält kein 'const', und
auch kein 'volatile'. Das ist in POSIX genormt.
Die Deklaration von 'argv' enthält auch kein 'const', dennoch ist eine
Manipulation der Pointer unzulässig (die Strings darfst du dagegen
modifizieren).
Die Formulierung im Standard ist nicht glasklar.
Wenn der Standard etwas ausdrücklich fordert, heißt das nicht, daß
alles denkbare, was nicht ausdrücklich gefordert wurde, verboten ist
bzw. UB verursacht.
Denn der Standard schreibt an vielen Stellen ausdrücklich von UB.
An der Stelle jedoch nicht.

Ich vermute, POSIX schreibt pauschal von UB, um Implementatoren
von vornherein alles zu erlauben.
Aus meiner Sicht ist UB hier nur möglich, wenn *vorsätzlich* UB
herbeigeführt wird.
Also, wenn eine Funktion NULL retourniert, liegt ja kein UB vor, denn
NULL zu retournieren ist ja eine definierte Aktion.
Post by Stefan Reuther
Post by Helmut Schellong
Ich lösche dort Einträge, durch Überschreiben von Einträgen
mit anderen gültigen Einträgen (Pointer), von oben nach unten.
[...]
Post by Helmut Schellong
Es handelt sich um ein normales C-Objekt: char *array[n];
Wenn 'const' fehlt und wenn ich nur bis n-1 zugreife, kann
IMO niemals irgendwas Undefiniertes passieren.
Ich wüßte nicht, daß der C-Standard hierbei UB als möglich beschreibt.
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Post by Stefan Reuther
Ein anderes Verhalten, das durch die in SUS und ISO C spezifizierten
Einschränkungen legitimiert wird ist, dass die Laufzeitumgebung gewisse
Annahmen treffen möchte, welche der Strings per 'malloc' allokiert sind.
Die stürzen hochkant ab, wenn du ihnen einen anderen String unterjubelst.
Was passiert denn dann? SIGSEGV? Oder vorsätzlicher Absturz.
Es könnte sein, daß free() dann nicht mehr freigeben kann.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2016-09-09 23:19:23 UTC
Permalink
Hallo,
Post by Helmut Schellong
Die Formulierung im Standard ist nicht glasklar.
Wenn der Standard etwas ausdrücklich fordert, heißt das nicht, daß
alles denkbare, was nicht ausdrücklich gefordert wurde, verboten ist
bzw. UB verursacht.
Der POSIX Standard sagt da eindeutig "undefined", und da spielt es keine
Rolle, ob du fragst "warum" oder es zufaellig in den von dir getesteten
Faellen tat was du erwartet hast. "undefined" ist und bleibt es trotzdem.
Post by Helmut Schellong
Post by Stefan Reuther
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Der libc code kann bei putenv, unsetenv etc. eine kopie anlegen und fortan
mit der Kopie arbeiten. Die libc darf/kann mehr ueber das System wissen als
du ...
Post by Helmut Schellong
Post by Stefan Reuther
Ein anderes Verhalten, das durch die in SUS und ISO C spezifizierten
Einschränkungen legitimiert wird ist, dass die Laufzeitumgebung gewisse
Annahmen treffen möchte, welche der Strings per 'malloc' allokiert sind.
Die stürzen hochkant ab, wenn du ihnen einen anderen String unterjubelst.
Was passiert denn dann? SIGSEGV? Oder vorsätzlicher Absturz.
Es könnte sein, daß free() dann nicht mehr freigeben kann.
Ein free() auf einen nicht per malloc allozierten Speicherbereich ist
ebenfalls undefined. Von "gar nichts" ueber Fehlermeldungen, Programm-
absturz bis zum kompletten Systemabsturz (oder auch jedes andere Ver-
halten) ist da alles moeglich und von der Formulierung "undefined" abgedeckt.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Helmut Schellong
2016-09-10 10:42:06 UTC
Permalink
Post by Juergen Ilse
Hallo,
Post by Helmut Schellong
Die Formulierung im Standard ist nicht glasklar.
Wenn der Standard etwas ausdrücklich fordert, heißt das nicht, daß
alles denkbare, was nicht ausdrücklich gefordert wurde, verboten ist
bzw. UB verursacht.
Der POSIX Standard sagt da eindeutig "undefined", und da spielt es keine
Rolle, ob du fragst "warum" oder es zufaellig in den von dir getesteten
Faellen tat was du erwartet hast. "undefined" ist und bleibt es trotzdem.
Ich sprach vom C-Standard: **argv
Der C-Standard fordert hier explizit:
=============================================================
The parameters argc and argv and the strings pointed to by
the argv array shall be modifiable by the program, and retain
their last-stored values between program startup
and program termination.
=============================================================
argv und argv[][] sollen ausdrücklich änderbar sein.
Von argv[] wird nichts geschrieben.
Ist nun ein Ändern von argv[] deshalb unzulässig?

Ich halte es für äußerst unwahrscheinlich, daß bei solchen
Manipulationen etwas Negatives passiert, wobei ich ein
Sortieren der Pointer meine, also nicht beliebige Änderungen.

Theoretisch gilt natürlich 'undefined'.
In der Realität sind solche Dinge aber (fast immer) definiert.

'Undefined' wird aus meiner Praktikersicht immer gegeben, wenn man
etwas im Standard nicht definieren will und einfach offen läßt
für die Freiheit der Implementatoren.
Diese definieren jedoch und schreiben wohl keinen absurden Code.
Post by Juergen Ilse
Post by Helmut Schellong
Post by Stefan Reuther
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Der libc code kann bei putenv, unsetenv etc. eine kopie anlegen und fortan
mit der Kopie arbeiten. Die libc darf/kann mehr ueber das System wissen als
du ...
Als Praktiker sehe ich diese Argumente als wackelig an.
Ein const Pointerarray[]={...}; ist im Zusammenhang Unfug.
Es wird mit seinen einmaligen Initialisierungen zur Kompilierzeit
readonly gelegt. Und was sind das für Initialisierungsinhalte?
Post by Juergen Ilse
Post by Helmut Schellong
Post by Stefan Reuther
Ein anderes Verhalten, das durch die in SUS und ISO C spezifizierten
Einschränkungen legitimiert wird ist, dass die Laufzeitumgebung gewisse
Annahmen treffen möchte, welche der Strings per 'malloc' allokiert sind.
Die stürzen hochkant ab, wenn du ihnen einen anderen String unterjubelst.
Was passiert denn dann? SIGSEGV? Oder vorsätzlicher Absturz.
Es könnte sein, daß free() dann nicht mehr freigeben kann.
Ein free() auf einen nicht per malloc allozierten Speicherbereich ist
ebenfalls undefined. Von "gar nichts" ueber Fehlermeldungen, Programm-
absturz bis zum kompletten Systemabsturz (oder auch jedes andere Ver-
halten) ist da alles moeglich und von der Formulierung "undefined" abgedeckt.
Das ist richtig.
Allerdings meinte ich nicht, daß fremde Pointer übergeben werden, sondern
daß ich free() eventuell Pointer 'wegnehme', weil ich die in der Tabelle
überschrieb.

Auch dieses UB nennt der Standard, weil er dasjenige Verhalten nicht
definieren will, sondern den Implementatoren überläßt.
Denen bleibt jedoch nichts anderes übrig als definierenden Code zu schreiben.
Z.B. daß bei übergebenen Fremdpointern einfach - nichts gemacht wird.
Was soll man denn auch machen mit einem Pointer, der in der Tabelle
keine Zuordnung ermöglicht?
Die werden schon nicht vorsätzlich absurden, schädigenden Code fabrizieren.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-10 11:36:57 UTC
Permalink
Post by Helmut Schellong
Post by Juergen Ilse
Der POSIX Standard sagt da eindeutig "undefined", und da spielt es keine
Rolle, ob du fragst "warum" oder es zufaellig in den von dir getesteten
Faellen tat was du erwartet hast. "undefined" ist und bleibt es trotzdem.
Ich sprach vom C-Standard: **argv
=============================================================
The parameters argc and argv and the strings pointed to by
the argv array shall be modifiable by the program, and retain
their last-stored values between program startup
and program termination.
=============================================================
argv und argv[][] sollen ausdrücklich änderbar sein.
Von argv[] wird nichts geschrieben.
Ist nun ein Ändern von argv[] deshalb unzulässig?
ja.
Post by Helmut Schellong
Ich halte es für äußerst unwahrscheinlich, daß bei solchen
Manipulationen etwas Negatives passiert, wobei ich ein
Sortieren der Pointer meine, also nicht beliebige Änderungen.
Der Standard versucht halt nicht, ein paar "das geht trotzdem"
Operationen aufzuzählen, sondern sagt: das ist halt undefiniert.
Post by Helmut Schellong
'Undefined' wird aus meiner Praktikersicht immer gegeben, wenn man
etwas im Standard nicht definieren will und einfach offen läßt
für die Freiheit der Implementatoren.
Diese definieren jedoch und schreiben wohl keinen absurden Code.
Des einen "offensichtlich" ist des anderen "absurd".

Ein Implementierer darf z.B. die Pointer in eine read-only-Speicherseite
packen, dann crasht es beim Umsortieren. Er darf alle Parameter in einen
großen String packen, den er am Ende mit 'free(argv[1])' freigibt. Dann
crasht das umsortierte eben dann.
Post by Helmut Schellong
Post by Juergen Ilse
Post by Helmut Schellong
Post by Stefan Reuther
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Der libc code kann bei putenv, unsetenv etc. eine kopie anlegen
und fortan mit der Kopie arbeiten. Die libc darf/kann mehr ueber
das System wissen als du ...
Fun fact: glibc tut unter bestimmten Bedingungen genau das.
Post by Helmut Schellong
Als Praktiker sehe ich diese Argumente als wackelig an.
Ein const Pointerarray[]={...}; ist im Zusammenhang Unfug.
Es wird mit seinen einmaligen Initialisierungen zur Kompilierzeit
readonly gelegt. Und was sind das für Initialisierungsinhalte?
Du scheinst davon auszugehen, dass 'const Pointerarray' die einzige
Möglichkeit sei, eine read-only-Speicherseite zu erzeugen. Mit
C-Sprachmitteln stimmt das sogar. Typische Betriebssysteme haben aber
Funktionen wie 'mprotect' oder 'VirtualProtect'.


Stefan
Helmut Schellong
2016-09-10 16:25:42 UTC
Permalink
On 09/10/16 13:36, Stefan Reuther wrote:
[...]
Post by Stefan Reuther
Du scheinst davon auszugehen, dass 'const Pointerarray' die einzige
Möglichkeit sei, eine read-only-Speicherseite zu erzeugen. Mit
C-Sprachmitteln stimmt das sogar. Typische Betriebssysteme haben aber
Funktionen wie 'mprotect' oder 'VirtualProtect'.
Ich gehe von der C-Ebene aus.
Ich sprach von 'const' und 'volatile'.
Ein 'const Pointerarray[]= {...};' ist hier definitiv Unsinn.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2016-09-10 13:03:44 UTC
Permalink
Hallo,
Post by Helmut Schellong
Post by Juergen Ilse
Post by Helmut Schellong
Die Formulierung im Standard ist nicht glasklar.
Wenn der Standard etwas ausdrücklich fordert, heißt das nicht, daß
alles denkbare, was nicht ausdrücklich gefordert wurde, verboten ist
bzw. UB verursacht.
Der POSIX Standard sagt da eindeutig "undefined", und da spielt es keine
Rolle, ob du fragst "warum" oder es zufaellig in den von dir getesteten
Faellen tat was du erwartet hast. "undefined" ist und bleibt es trotzdem.
Ich sprach vom C-Standard: **argv
=============================================================
The parameters argc and argv and the strings pointed to by
the argv array shall be modifiable by the program, and retain
their last-stored values between program startup
and program termination.
=============================================================
argv und argv[][] sollen ausdrücklich änderbar sein.
... und nichts von beiden hat auch nur das geringste mit dem Environment
zu tun ...
Post by Helmut Schellong
Von argv[] wird nichts geschrieben.
Ist nun ein Ändern von argv[] deshalb unzulässig?
Zumindest kann man sich nicht darauf verlassen, dass es modifiable ist,
mit anderen Worten: wenn du da dran rumfummelst, ist das unportabel und
im schlimmsten fall kann es boese scheppern ...
Post by Helmut Schellong
Ich halte es für äußerst unwahrscheinlich, daß bei solchen
Manipulationen etwas Negatives passiert, wobei ich ein
Sortieren der Pointer meine, also nicht beliebige Änderungen.
Zumindest ist das nicht portabel, denn niemand (auch nicht der Standard)
garantiert dir, dass das wie du es erwartest funktioniert.
Post by Helmut Schellong
Theoretisch gilt natürlich 'undefined'.
Auch praktisch "undefined", denn es ist kein Verhalten dafuer vorge-
schrieben oder definiert.
Post by Helmut Schellong
In der Realität sind solche Dinge aber (fast immer) definiert.
Nein, sie koennen aber gelegentlich auch wie von dir erwártet
"funktionieren".
Post by Helmut Schellong
'Undefined' wird aus meiner Praktikersicht immer gegeben, wenn man
etwas im Standard nicht definieren will und einfach offen läßt
für die Freiheit der Implementatoren.
Eben, und man kann sich nicht auf eine bestimmte Implementierung
verlassen. Jede noch so krude und hirnrissige Implementierung ist
moeglich, auch wenn sie deine Erwartungen in jeglicher Hinsicht
zunichte macht.
Post by Helmut Schellong
Diese definieren jedoch und schreiben wohl keinen absurden Code.
Eben das kannst du nicht wissen, da "undefined" eben genau das heisst:
Es ist kein spezifisches Verhalten garantiert, und es kann je nach
umgebenden Programmcode ggfs. manchmal auch anders aussehen (vom
Verhalten einer evt. nachfolgenden Compilerversion ganz zu schweigen).
Solchen "es wird schon funktionieren" Erwartungen war der Crash von
Linux-Kerneln 2.0.x mit x<=34 zu verdankewn, wenn man den Kernel mit
gcc2.8 bzw. egcs uebersetzt hat.
Post by Helmut Schellong
Post by Juergen Ilse
Post by Helmut Schellong
Post by Stefan Reuther
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Der libc code kann bei putenv, unsetenv etc. eine kopie anlegen und fortan
mit der Kopie arbeiten. Die libc darf/kann mehr ueber das System wissen als
du ...
Als Praktiker sehe ich diese Argumente als wackelig an.
Was du dir zu sehen einbildet, spielt keine Rolle. Es *ist* einfach so.
Post by Helmut Schellong
Post by Juergen Ilse
Ein free() auf einen nicht per malloc allozierten Speicherbereich ist
ebenfalls undefined. Von "gar nichts" ueber Fehlermeldungen, Programm-
absturz bis zum kompletten Systemabsturz (oder auch jedes andere Ver-
halten) ist da alles moeglich und von der Formulierung "undefined" abgedeckt.
Das ist richtig.
Allerdings meinte ich nicht, daß fremde Pointer übergeben werden, sondern
daß ich free() eventuell Pointer 'wegnehme', weil ich die in der Tabelle
überschrieb.
Auch dieses UB nennt der Standard, weil er dasjenige Verhalten nicht
definieren will, sondern den Implementatoren überläßt.
Denen bleibt jedoch nichts anderes übrig als definierenden Code zu schreiben.
... und dafuer gilt exakt das selbe: von "tut gar nichts" bis zum System-
absturz ist dabei *jedes* Verhalten moeglich. Verlaesslich ist das, was
der Sprachstandard, evt. zusaetzlich auf die Umgebung zutreffende Standards
und die Dokumentation des Herstellers definiert, *nicht* *mehr*.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Peter J. Holzer
2016-09-10 15:03:07 UTC
Permalink
Post by Juergen Ilse
Post by Helmut Schellong
Ich halte es für äußerst unwahrscheinlich, daß bei solchen
Manipulationen etwas Negatives passiert, wobei ich ein
Sortieren der Pointer meine, also nicht beliebige Änderungen.
Zumindest ist das nicht portabel, denn niemand (auch nicht der Standard)
garantiert dir, dass das wie du es erwartest funktioniert.
Hier ist meiner Meinung nach die Implikation verkehrt herum. Aus
"niemand garantiert" folgt "der Standard garantiert nicht" (da der
Standard "jemand" ist). Umgekehrt folgt aber aus "der Standard
garantiert nicht" nicht "niemand garantiert". Denn eine solche Garantie
könnte z.B. von einem Betriebssystem- oder Compiler-Hersteller abgegeben
werden.

Das schränkt natürlich die Portabilität ein (statt auf "alle
POSIX-Systeme" ist das Programm nur mehr auf "alle Foo-OS-Systeme" oder
"alle Systeme mit barcc" portabel), aber auf diesen Systemen
funktioniert es garantiert.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Stefan Reuther
2016-09-10 09:53:22 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Stefan Reuther
Post by Helmut Schellong
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.
Die Single Unix Specification ist sich ziemlich sicher, dass genau diese
Manipulationen undefiniertes Verhalten darstellen.
"Any application that directly modifies the pointers to which the
environ variable points has undefined behavior."
Ich hatte das ja gepostet.
Man weiß aber nicht GANZ GENAU, was der Satz aussagen soll.
Schließ nicht von dir auf andere. Ich weiß genau, was der Satz aussagen
soll. Nämlich dass man die Zeiger, auf die 'environ' zeigt, nicht
modifizieren darf.
Post by Helmut Schellong
Man kann einhängen
o fremde Pointer
o ungültige Pointer
o Pointer, die auf falschen Inhalt zeigen
o Pointer, die auf gleiche Namen= zeigen
o Pointer auf die terminierende NULL setzen...
o etc.
Alles das mache ich nicht und sollte man auch nicht machen.
Es stellt sich doch die Frage, ob absolut jede denkbare Modifikation
des Arrays UB zur Folge haben soll?
Ausdrücklich steht das nicht da.
Doch, genau das steht da.

Du darfst den 'environ'-Zeiger selbst ändern, und du darfst die Texte
ändern. Nicht jedoch die Pointer. Wie bei 'argv'.
Post by Helmut Schellong
Post by Stefan Reuther
Post by Helmut Schellong
Die Deklaration von 'environ' enthält kein 'const', und
auch kein 'volatile'. Das ist in POSIX genormt.
Die Deklaration von 'argv' enthält auch kein 'const', dennoch ist eine
Manipulation der Pointer unzulässig (die Strings darfst du dagegen
modifizieren).
Die Formulierung im Standard ist nicht glasklar.
Wenn der Standard etwas ausdrücklich fordert, heißt das nicht, daß
alles denkbare, was nicht ausdrücklich gefordert wurde, verboten ist
bzw. UB verursacht.
Doch, genau das heißt das. Wenn der Standard kein Verhalten definiert,
ist das - Überraschung - undefiniertes Verhalten.
Post by Helmut Schellong
Ich vermute, POSIX schreibt pauschal von UB, um Implementatoren
von vornherein alles zu erlauben.
Aus meiner Sicht ist UB hier nur möglich, wenn *vorsätzlich* UB
herbeigeführt wird.
Natürlich ist das Verhalten auf einer konkreten Version einer konkreten
Implementierung immer definiert.

Es kann sich halt beim nächsten Patchlevel ändern, und dann fangen die
Pfuscher an zu weinen. Und es kann natürlich auf anderen Versionen, die
du nicht getestet hast, sich völlig anders verhalten.
Post by Helmut Schellong
Post by Stefan Reuther
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Doch. Der kann und darf das wissen und entsprechend damit arbeiten.

Das erste, was z.B. die glibc bei 'putenv' tut, wenn sie detektiert,
dass du 'environ' geändert hast, ist, eine Kopie davon anzulegen und mit
der Kopie weiterzuarbeiten, da sie bei deiner Änderung nicht mehr weiß,
wem welche Strings gehören.


Stefan
Peter J. Holzer
2016-09-10 14:51:41 UTC
Permalink
Post by Stefan Reuther
Du darfst den 'environ'-Zeiger selbst ändern, und du darfst die Texte
ändern.
Selbst das halte ich für eine etwas mutige Interpretation des Standards.

Der Standard definiert, was passiert, wenn man den environ-Pointer
ändert. Der Standard definiert auch, was passiert, wenn man einen String
ändert, den man zuvor an putenv übergeben hat. Aber darüber, was
passiert, wenn man andere Strings im Environment ändert, finde ich im
Standard keine Aussage. Ich halte das daher für undefiniert, und die
Rationale von getenv[1] stützt meine Annahme. Bei einer Implementation,
wie sie dort skizziert wird, würde das direkte Ändern der Texte nicht
(zuverlässig) funktionieren.
[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/getenv.html#tag_16_194_08

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Claus Reibenstein
2016-09-10 15:48:30 UTC
Permalink
Post by Peter J. Holzer
Post by Stefan Reuther
Du darfst den 'environ'-Zeiger selbst ändern, und du darfst die Texte
ändern.
Selbst das halte ich für eine etwas mutige Interpretation des Standards.
Der Standard definiert, was passiert, wenn man den environ-Pointer
ändert.
Von welchem Standard redest Du? Die Standards, die ich kenne, erwähnen
keinen solchen Pointer.

Gruß
Claus
Peter J. Holzer
2016-09-14 07:15:51 UTC
Permalink
Post by Claus Reibenstein
Post by Peter J. Holzer
Post by Stefan Reuther
Du darfst den 'environ'-Zeiger selbst ändern, und du darfst die Texte
ändern.
Selbst das halte ich für eine etwas mutige Interpretation des Standards.
Der Standard definiert, was passiert, wenn man den environ-Pointer
ändert.
Von welchem Standard redest Du? Die Standards, die ich kenne, erwähnen
keinen solchen Pointer.
POSIX, genauer gesagt die Ausgabe von 2013:
http://pubs.opengroup.org/onlinepubs/9699919799/

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Stefan Reuther
2016-09-11 09:29:17 UTC
Permalink
Post by Peter J. Holzer
Post by Stefan Reuther
Du darfst den 'environ'-Zeiger selbst ändern, und du darfst die Texte
ändern.
Selbst das halte ich für eine etwas mutige Interpretation des Standards.
Der Standard definiert, was passiert, wenn man den environ-Pointer
ändert. Der Standard definiert auch, was passiert, wenn man einen String
ändert, den man zuvor an putenv übergeben hat. Aber darüber, was
passiert, wenn man andere Strings im Environment ändert, finde ich im
Standard keine Aussage. Ich halte das daher für undefiniert, und die
Rationale von getenv[1] stützt meine Annahme. Bei einer Implementation,
wie sie dort skizziert wird, würde das direkte Ändern der Texte nicht
(zuverlässig) funktionieren.
[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/getenv.html#tag_16_194_08
OK, dann ist das eine zusätzliche Einschränkung, die für mich aus der
Beschreibung bei 'exec' nicht hervorging. Auch gut.


Stefan
Peter J. Holzer
2016-09-10 13:32:27 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Stefan Reuther
Post by Helmut Schellong
Ich bin recht sicher, daß genau diejenigen Manipulationen, die ich
vornehme und postete, auf keinen Fall Probleme bereiten können, also
kein undefiniertes Verhalten darstellen können.
Die Single Unix Specification ist sich ziemlich sicher, dass genau diese
Manipulationen undefiniertes Verhalten darstellen.
Das ist etwas flapsig formuliert. Die SUS ist keine Untersuchung
existierender Systeme, sondern eine Norm. Sie stellt nicht fest, ob
etwas definiert ist, sondern sie legt es fest, indem sie es definiert.
Alles, was sie nicht definiert, ist undefiniert.
Post by Helmut Schellong
Post by Stefan Reuther
"Any application that directly modifies the pointers to which the
environ variable points has undefined behavior."
Ich hatte das ja gepostet.
Man weiß aber nicht GANZ GENAU, was der Satz aussagen soll.
Man kann einhängen
o fremde Pointer
o ungültige Pointer
o Pointer, die auf falschen Inhalt zeigen
o Pointer, die auf gleiche Namen= zeigen
o Pointer auf die terminierende NULL setzen...
o etc.
Alles das mache ich nicht und sollte man auch nicht machen.
Es stellt sich doch die Frage, ob absolut jede denkbare Modifikation
des Arrays UB zur Folge haben soll?
Die Frage ist unsinnig. "Undefined" heißt, der Standard definiert nicht,
was passiert. Da der Standard für alle diese Fälle nicht definiert, was
passiert, sind alle undefined. Wenn einige dieser Fälle doch definiert
sein sollten, müsste sie der Standard explizit definieren. Tut er aber
nicht.

(Anmerkung: Theoretisch könnten einige dieser Operationen durch die
Definition von getenv(), setenv() und putenv() indirekt definiert sein.
Das muss aber durch die Definiton begründet sein, nicht durch mögliche
Implementationen. Denn die Funktionen müssen nicht in C implementiert
sein.)

Die Rationale zu getenv() gibt ein Beispiel für eine Implementation, in
der das Löschen einzelner Pointer nicht den von Dir erwähnten Effekt
haben könnte:

| In fact, for higher performance of getenv(), implementations that do not
| provide putenv() could also maintain a separate copy of the environment
| in a data structure that could be searched much more quickly (such as an
| indexed hash table, or a binary tree), and update both it and the linear
| list at environ when setenv() or unsetenv() is invoked.

Wenn Du da die Pointer in environ änderst, sind die beiden
Datenstrukturen nicht mehr synchronisiert. Getenv() würde also z.B. das
von Dir vermeintlich gelöschte Element weiterhin finden.

Ich könnte mir z.B. auch eine Datenstruktur vorstellen, bei der die
Position eines bestimmten Environment-Strings in environ durch eine
Hash-Funktion bestimmt wird. Wenn Du da Elemente verschiebst, werden sie
nicht mehr gefunden. (Und wenn Du Pech hast, führt der Zugriff auf das
Element, das nicht mehr da ist, wo es erwartet wird, zu einem falschen
Ergebnis oder zu einem SEGV.)
Post by Helmut Schellong
Ausdrücklich steht das nicht da.
Alles, was nicht ausdrücklich da steht, ist undefiniert.
Post by Helmut Schellong
Post by Stefan Reuther
Post by Helmut Schellong
Die Deklaration von 'environ' enthält kein 'const', und
auch kein 'volatile'. Das ist in POSIX genormt.
[Ab hier geht es um argv, nicht mehr um environ]
Post by Helmut Schellong
Post by Stefan Reuther
Die Deklaration von 'argv' enthält auch kein 'const', dennoch ist eine
Manipulation der Pointer unzulässig (die Strings darfst du dagegen
modifizieren).
Die Formulierung im Standard ist nicht glasklar.
Wenn der Standard etwas ausdrücklich fordert, heißt das nicht, daß
alles denkbare, was nicht ausdrücklich gefordert wurde, verboten ist
bzw. UB verursacht.
Alles was nicht ausdrücklich definiert ist, ist undefiniert:

| Undefined behavior is otherwise indicated in this International Standard
| by the words ‘‘undefined behavior’’ or by the omission of any explicit
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| definition of behavior. There is no difference in emphasis among these
^^^^^^^^^^^^^^^^^^^^^^
| three; they all describe ‘‘behavior that is undefined’’.
Post by Helmut Schellong
Denn der Standard schreibt an vielen Stellen ausdrücklich von UB.
An der Stelle jedoch nicht.
Ich vermute, POSIX schreibt pauschal von UB, um Implementatoren
von vornherein alles zu erlauben.
Aus meiner Sicht ist UB hier nur möglich, wenn *vorsätzlich* UB
herbeigeführt wird.
Jeder Verhalten ist hier "undefined behavior", denn der Standard
definiert ja nicht, was passieren soll.
Post by Helmut Schellong
Post by Stefan Reuther
Post by Helmut Schellong
Es handelt sich um ein normales C-Objekt: char *array[n];
Wenn 'const' fehlt und wenn ich nur bis n-1 zugreife, kann
IMO niemals irgendwas Undefiniertes passieren.
Ich wüßte nicht, daß der C-Standard hierbei UB als möglich beschreibt.
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Der libc-Code muss den Bereich, auf den argv zeigt, ja nicht ändern.
Also ist das kein Argument (mal ganz abgesehen davon, dass die libc
natürlich auch Permissions auf Speicherbereiche manipulieren könnte).

Eine Implementation, die die eigentlichen Argumente in rw-Memory hält
(muss sie), aber die Pointer in ro-Memory (darf sie), wäre
zugegebenermaßen etwas seltsam. Mir fällt kein plausibler Grund für eine
solche Konstruktion ein. Aber das heißt nicht, dass sie nicht erlaubt
wäre.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Helmut Schellong
2016-09-10 15:42:21 UTC
Permalink
Post by Peter J. Holzer
Post by Helmut Schellong
Post by Stefan Reuther
Die Single Unix Specification ist sich ziemlich sicher, dass genau diese
Manipulationen undefiniertes Verhalten darstellen.
Das ist etwas flapsig formuliert. Die SUS ist keine Untersuchung
existierender Systeme, sondern eine Norm. Sie stellt nicht fest, ob
etwas definiert ist, sondern sie legt es fest, indem sie es definiert.
Alles, was sie nicht definiert, ist undefiniert.
[...]
Post by Peter J. Holzer
Die Frage ist unsinnig. "Undefined" heißt, der Standard definiert nicht,
was passiert. Da der Standard für alle diese Fälle nicht definiert, was
passiert, sind alle undefined. Wenn einige dieser Fälle doch definiert
sein sollten, müsste sie der Standard explizit definieren. Tut er aber
nicht.
Da hast Du grundlegend schon Recht, mit dem gesamten Posting.

Ich stelle allerdings oft fest, daß viele bei geschriebenem UB
denken, es würde tatsächlich prompt etwas crash-artiges passieren.
Jedoch das _kann_ mit sehr geringer Wahrscheinlichkeit passieren.
Die konkrete Wirkung in dem Falle ist auch unbekannt.
(Ich ereifere mich dann hin und wieder.)
Post by Peter J. Holzer
Die Rationale zu getenv() gibt ein Beispiel für eine Implementation, in
der das Löschen einzelner Pointer nicht den von Dir erwähnten Effekt
| In fact, for higher performance of getenv(), implementations that do not
| provide putenv() could also maintain a separate copy of the environment
| in a data structure that could be searched much more quickly (such as an
| indexed hash table, or a binary tree), and update both it and the linear
| list at environ when setenv() or unsetenv() is invoked.
Wenn Du da die Pointer in environ änderst, sind die beiden
Datenstrukturen nicht mehr synchronisiert. Getenv() würde also z.B. das
von Dir vermeintlich gelöschte Element weiterhin finden.
Ich habe schon genau überlegt, bevor ich die Pointer mangels unsetenv
manipulierte:
Ich benutze _nur_ putenv(); für alles andere environ.
Damals hielt ich das für konsistent, auch heute noch.
Post by Peter J. Holzer
Ich könnte mir z.B. auch eine Datenstruktur vorstellen, bei der die
Position eines bestimmten Environment-Strings in environ durch eine
Hash-Funktion bestimmt wird. Wenn Du da Elemente verschiebst, werden sie
nicht mehr gefunden. (Und wenn Du Pech hast, führt der Zugriff auf das
Element, das nicht mehr da ist, wo es erwartet wird, zu einem falschen
Ergebnis oder zu einem SEGV.)
Rainer W. hat hier die FreeBSD-Implementation dazu eingeführt.
Die hat ein getrenntes internes Struktur-Array.

Es ist dort erkennbar, daß fast jede denkbare Manipulation von environ,
die keine vorsätzliche Sabotage ist, erlaubt ist.
Für die ist 'environ' quasi ein User-Objekt.

Wenn ich z.B. einen Pointer überschreibe und damit vernichte, so ist
der z.B. für free() in der internen Struktur weiterhin vorhanden.

Die suchen _getrennt_ in beiden Arrays.
Im internen bis n, im environ bis NULL (wenn die interne NULL ist).
Das unterstützt meine Konsistenzüberlegungen.
Standard ist die interne Liste, die ja gehasht werden könnte.

Beispiel:
/*
* If the program attempts to replace the array of environment variables
* (environ) environ or sets the first varible to NULL, then deactivate all
* variables and merge in the new list from environ.
*/
Post by Peter J. Holzer
Post by Helmut Schellong
Post by Stefan Reuther
Die Laufzeitumgebung darf die Pointer in eine schreibgeschützte
Speicherseite legen, auch, wenn der Datentyp das nicht aussagt.
Tja, dann kann aber niemand damit arbeiten.
Auch nicht der libc-Code.
Der libc-Code muss den Bereich, auf den argv zeigt, ja nicht ändern.
Also ist das kein Argument (mal ganz abgesehen davon, dass die libc
natürlich auch Permissions auf Speicherbereiche manipulieren könnte).
Vorstehend ist allerdings wieder *environ[] gemeint.
Post by Peter J. Holzer
Eine Implementation, die die eigentlichen Argumente in rw-Memory hält
(muss sie), aber die Pointer in ro-Memory (darf sie), wäre
zugegebenermaßen etwas seltsam. Mir fällt kein plausibler Grund für eine
solche Konstruktion ein. Aber das heißt nicht, dass sie nicht erlaubt
wäre.
So schätze ich das auch ein.
In aller Regel wird so etwas robust implementiert.

Es kommt ja darauf an, ob mein Code auf 'meinen' Plattformen funktioniert!
Ich habe z.B. keinen Zugang (mehr) auf irgendwelche Plattformen != iX86,
bzw. dort will ich gar nicht kompilieren.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2016-09-10 16:24:44 UTC
Permalink
Hallo,
Post by Helmut Schellong
Ich stelle allerdings oft fest, daß viele bei geschriebenem UB
denken, es würde tatsächlich prompt etwas crash-artiges passieren.
Jedoch das _kann_ mit sehr geringer Wahrscheinlichkeit passieren.
Die konkrete Wirkung in dem Falle ist auch unbekannt.
(Ich ereifere mich dann hin und wieder.)
Wer Code benutzt, der laut Standards "undefined" ist, handelt fahrlaessig,
und ich kann niemandem ernsthaft empfehlen, entsprechende Programme produktiv
einzusetzen.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Helmut Schellong
2016-09-10 16:54:19 UTC
Permalink
Post by Juergen Ilse
Post by Helmut Schellong
Ich stelle allerdings oft fest, daß viele bei geschriebenem UB
denken, es würde tatsächlich prompt etwas crash-artiges passieren.
Jedoch das _kann_ mit sehr geringer Wahrscheinlichkeit passieren.
Die konkrete Wirkung in dem Falle ist auch unbekannt.
Wer Code benutzt, der laut Standards "undefined" ist, handelt fahrlaessig,
und ich kann niemandem ernsthaft empfehlen, entsprechende Programme produktiv
einzusetzen.
Wenn solcher Code *auf den relevanten Plattformen* vollkommen definiert
funktioniert, ist diese Situation sicher - 100% sicher.
Darauf kommt es an!

Mögliche algorithmische Fehler sind da eher anzusprechen.
Beispiel:
vv
else if (lv=va_arg(ap,int)+1, t0&(V_4|V_8|V_f))
if (t&V_q) t|= lv==4 ?V_4:V_8;

if (t&V_q) t|= lv==4+1?V_4:V_8; //korrigiert
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-10 20:09:30 UTC
Permalink
Post by Helmut Schellong
Wenn solcher Code *auf den relevanten Plattformen* vollkommen definiert
funktioniert, ist diese Situation sicher
Undefiniertes Verhalten hat eine blöde Angewohnheit: Es kann
bei bestimmten Plattformen funktionieren. Das nächste Upgrade
oder der nächste Wechsel der Plattform kann das schon wieder ändern.

Nur: Die Sache läuft dann auf FooOS Version 3.14159265 mit libc
2.7182818. Leider funktionieret es mit dem nächste Major Update
auf 4.0, was du installieren musst, weil die Sicherheitsupgrades
ausbleiben, nicht mehr.

Dann hat der, der sich auf deinen Code verlässt, leider verloren.
Post by Helmut Schellong
- 100% sicher.
Wohl kaum.
Helmut Schellong
2016-09-11 09:46:52 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Wenn solcher Code *auf den relevanten Plattformen* vollkommen definiert
funktioniert, ist diese Situation sicher
Undefiniertes Verhalten hat eine blöde Angewohnheit: Es kann
bei bestimmten Plattformen funktionieren. Das nächste Upgrade
oder der nächste Wechsel der Plattform kann das schon wieder ändern.
Nur: Die Sache läuft dann auf FooOS Version 3.14159265 mit libc
2.7182818. Leider funktionieret es mit dem nächste Major Update
auf 4.0, was du installieren musst, weil die Sicherheitsupgrades
ausbleiben, nicht mehr.
Dann hat der, der sich auf deinen Code verlässt, leider verloren.
Post by Helmut Schellong
- 100% sicher.
Wohl kaum.
Ist das denn so schwer zu verstehen?!

Wenn ich kompiliere, und dann funktioniert die Exe einwandfrei, dann
funktioniert die nun mal einwandfrei!
Eine fehlerhafte Exe liegt dann nicht vor; ist doch logisch - oder?
(Ich habe keine Open-Source.)

Wenn ich einen Compilerwechsel vornehme, prüfe ich daraufhin.

Zum Beispiel habe ich unter Windows einen 32-Bit-Compiler und einen
64-Bit-Compiler.
Beide haben nur getenv() und putenv().
Und nun?

Ich habe unter Windows, Linux und FreeBSD meine Exe getestet.
Soeben nochmals, nach vielen Tests zuvor, ab 1995.

Natürlich funktionieren die alle.
Also doch - 100% sicher.

Auf allen Plattformen wird 'TEST=ttttt' zu 'TEST' im Environment
'environ', wenn ich in 'environ' direkt lösche.
Nur auf Linux verschwindet 'TEST=ttttt' zu '' in 'environ',
wenn ich per unsetenv() lösche.

Anmerkung: Man beachte oben, daß 'TEST' ungleich 'TEST=' ist.
ifenv TEST liefert false, wenn 'TEST' im Env liegt.

Unter Windows wird das aktuelle (erweiterte) Environment _nicht_
an Folgeprozesse übergeben.
Eventuell hilft da eine Verwendung von execve(..., environ);
der Sinn solch einer Übergabe ist allerdings ein anderer.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-11 10:22:57 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Dann hat der, der sich auf deinen Code verlässt, leider verloren.
Post by Helmut Schellong
- 100% sicher.
Wohl kaum.
Ist das denn so schwer zu verstehen?!
Wenn ich kompiliere, und dann funktioniert die Exe einwandfrei, dann
funktioniert die nun mal einwandfrei!
Du verwendest shared libraries?
Helmut Schellong
2016-09-11 18:17:56 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Dann hat der, der sich auf deinen Code verlässt, leider verloren.
Post by Helmut Schellong
- 100% sicher.
Wohl kaum.
Ist das denn so schwer zu verstehen?!
Wenn ich kompiliere, und dann funktioniert die Exe einwandfrei, dann
funktioniert die nun mal einwandfrei!
Du verwendest shared libraries?
Nein, -static.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-11 18:55:04 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Dann hat der, der sich auf deinen Code verl??sst, leider verloren.
Post by Helmut Schellong
- 100% sicher.
Wohl kaum.
Ist das denn so schwer zu verstehen?!
Wenn ich kompiliere, und dann funktioniert die Exe einwandfrei, dann
funktioniert die nun mal einwandfrei!
Du verwendest shared libraries?
Nein, -static.
Also keine Updates, wenn im glibc-Code Sicherheitsl�cken entdeckt
werden?
Helmut Schellong
2016-09-11 21:01:37 UTC
Permalink
[...]
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Wenn ich kompiliere, und dann funktioniert die Exe einwandfrei, dann
funktioniert die nun mal einwandfrei!
Du verwendest shared libraries?
Nein, -static.
Also keine Updates, wenn im glibc-Code Sicherheitsl�cken entdeckt
werden?
Richtig.
bsh verwendet fast nur elementare Kerneleinsprungfunktionen.
Gib doch mal ein Beispiel - zu write(), zu read(), ...

Auf meinem Webspace arbeitet seit 1998 bsh als CGI-Interpreter,
auch mit -static.

Wenn ich nicht -static angegeben h�tte, h�ttest Du sehr wahrscheinlich
gesagt, da� oft neue shared Libs meinem Programm hinzugebunden werden
und es somit dadurch pl�tzlich zu Fehlern kommen kann.
--
Mit freundlichen Gr��en
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-11 22:15:53 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Wenn ich kompiliere, und dann funktioniert die Exe einwandfrei, dann
funktioniert die nun mal einwandfrei!
Du verwendest shared libraries?
Nein, -static.
Also keine Updates, wenn im glibc-Code Sicherheitsl�cken entdeckt
werden?
Richtig.
bsh verwendet fast nur elementare Kerneleinsprungfunktionen.
Redest du jetzt nur �ber deine Shell, bei der du solche Sachen machst?
Ich dachte, nach den Prinzipien programmierst du immer.
Post by Helmut Schellong
Gib doch mal ein Beispiel - zu write(), zu read(), ...
Naja, wenn eins deiner Programme direkt mit dem Internet kommuniziert,
dann gibt es da z.B. CVE 2015-7547. Eine Liste findest du unter

https://www.cvedetails.com/vulnerability-list/vendor_id-72/product_id-767/GNU-Glibc.html
Post by Helmut Schellong
Wenn ich nicht -static angegeben h�tte, h�ttest Du sehr wahrscheinlich
gesagt, da� oft neue shared Libs meinem Programm hinzugebunden werden
und es somit dadurch pl�tzlich zu Fehlern kommen kann.
Korrekt, das ist die Konsequenz, wenn man sich auf undefiniertes
Verhalten verl�sst - Programme h�ren pl�tzlich auf zu funktionieren.
Das gleiche kann auch genauso f�r Updates von Compilern gelten.

Undefiniertes Verhalten mit Absicht in Programme einzubauen,
ist mindestens grob fahrl�ssig.
Juergen Ilse
2016-09-11 22:42:53 UTC
Permalink
Hallo,
Post by Thomas Koenig
Undefiniertes Verhalten mit Absicht in Programme einzubauen,
ist mindestens grob fahrl?ssig.
Auf dem Ohr ist er taub ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Helmut Schellong
2016-09-11 22:43:32 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Gib doch mal ein Beispiel - zu write(), zu read(), ...
Naja, wenn eins deiner Programme direkt mit dem Internet kommuniziert,
dann gibt es da z.B. CVE 2015-7547. Eine Liste findest du unter
Es steht also fest, daß Programme wie z.B. bsh keine libc-Updates
wegen Sicherheitsmängeln brauchen.
Post by Thomas Koenig
Korrekt, das ist die Konsequenz, wenn man sich auf undefiniertes
Verhalten verl�sst - Programme h�ren pl�tzlich auf zu funktionieren.
Das gleiche kann auch genauso f�r Updates von Compilern gelten.
Ich verlasse mich nicht auf UB.
Ich schätze die Lage so ein, daß ein UB extrem unwahrscheinlich ist.
Meine Prüfungen zeigen, daß meine Einschätzung richtig ist.
Post by Thomas Koenig
Undefiniertes Verhalten mit Absicht in Programme einzubauen,
ist mindestens grob fahrl�ssig.
Das tue ich ja nicht.
Wenn die Exe kein UB zeigt, ist sie ohne UB.
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Ich prüfe, ob meine Exe UB zeigen.

Ich sagte in anderen Postings, daß ich unter Windows die
Funktionen setenv und unsetenv nicht zur Verfügung habe.
Unter Unix hatte ich unsetenv lange Zeit nicht zur
Verfügung.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
G.B.
2016-09-12 08:26:45 UTC
Permalink
Post by Helmut Schellong
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Warum reden wir dann über C? Es scheint vielmehr um statisch
gebundenen Objektcode für ein passend eingerichtetes System
zu gehen, und sein Verhalten, gerade im nicht von C definierten Fall,
also in dem Fall, in dem sich von C aus nicht urteilen lässt,
wird mit dem Ergebnis "überprüft", dass die Ausführung
wahrscheinlich nicht die GAU-Schwelle überschreiten wird.

Dabei ist C nur eine zufällige Beigabe zu den Argumentationsinhalten;
so könnte man mit ziemlich jeder Sprache verfahren, sofern nur
das darin geschriebene Programm für die selben Systeme übersetzt
werden kann: "Überschreibe ich nur diesen env*-Zeiger in der Hoffnung,
dass ich in der Zukunft noch den Schraubendreher in der Hand halte
und weiß, dass ich da ggf. was dran drehen muss, oder verwende ich die
Programmier-Schnittstelle, die dafür in der Zielumgebung dringend
nahegelegt wird?"

Mir scheint hier kein C-spezifisches IT-Konstrukt erkennbar, wohl
ein System-Hack, der aus irgend welchen Gründen™ von der normalen
Verfahrensweise abweicht und trotzdem "Norm, Norm, Oh, Norm!" beten
möchte.

Für so etwas gibt es Software-Konfiguration:
- Zweig A: schneller Hack, hoffentlich dokumentiert.
- Zweig B: norm_en_konform und insoweit vorhersagbares Verhalten.
--
"HOTDOGS ARE NOT BOOKMARKS"
Springfield Elementary teaching staff
Helmut Schellong
2016-09-12 11:40:29 UTC
Permalink
Post by G.B.
Post by Helmut Schellong
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Warum reden wir dann über C? Es scheint vielmehr um statisch
gebundenen Objektcode für ein passend eingerichtetes System
zu gehen, und sein Verhalten, gerade im nicht von C definierten Fall,
also in dem Fall, in dem sich von C aus nicht urteilen lässt,
wird mit dem Ergebnis "überprüft", dass die Ausführung
wahrscheinlich nicht die GAU-Schwelle überschreiten wird.
Ich nahm vollständige funktionale Tests vor.
Die *Exe* waren/sind bezüglich des Themas *als Produkt fehlerfrei*!
Davon schrieb und schreibe ich.
Ich bestritt nie, daß die Software ein UB mit Auswirkungspotential
enthält.
Post by G.B.
Dabei ist C nur eine zufällige Beigabe zu den Argumentationsinhalten;
so könnte man mit ziemlich jeder Sprache verfahren, sofern nur
das darin geschriebene Programm für die selben Systeme übersetzt
werden kann: "Überschreibe ich nur diesen env*-Zeiger in der Hoffnung,
dass ich in der Zukunft noch den Schraubendreher in der Hand halte
und weiß, dass ich da ggf. was dran drehen muss, oder verwende ich die
Programmier-Schnittstelle, die dafür in der Zielumgebung dringend
nahegelegt wird?"
[...]
Da ist eine Menge Dramatik enthalten; ziemlich übertrieben.

Die benötigten Schnittstellen standen/stehen (teilweise) nicht
zur Verfügung.

Aus Sicht von C kann ich das, was ich (teilweise) tue, nämlich
'extern char **environ;' in der von mir beschriebenen Art und Weise
ändern, ohne Einwand tun.

Das von POSIX beschriebene UB bezieht sich auf ein mögliches
Verhalten von Implementierern, das bewirken kann, daß sich das
beschriebene UB schädlich auswirkt.

Das bedeutet dann aber nicht, daß ein Produkt (die Exe) mit der
schädlichen Auswirkung verbreitet wird.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
G.B.
2016-09-12 12:19:48 UTC
Permalink
Post by Helmut Schellong
Ich nahm vollständige funktionale Tests vor.
Die *Exe* waren/sind bezüglich des Themas *als Produkt fehlerfrei*!
Eine exe mit anforderungsgemäß funktionierenden Teilsystem
macht immer noch nicht klar, was C für die Nicht-Beachtung
von POSIX-Schnittstellen hergeben soll.

Es mag in diesem besonderen Fall auch nicht bedeutsam sein,
was WIMRE, auf GNU/Linux mit glibc in Sachen Netzwerk schon
der Fall war: dass statisches Einbinden von glibc für manche
Netzwerk-Funktionen nicht hinreichte, sondern dennoch die
Funktionen aufgerufen wurde, die gerade anders ein Teil des
Systems waren. Ich nehme an, dass der Herstellungsprozess
Deines Programms solche Eventualitäten vollständig überprüft,
damit weiterhin auf den Aufruf der POSIX-Schnittstellen
verzichtet werden kann.
Post by Helmut Schellong
Davon schrieb und schreibe ich.
Naja, und viel über C, welche Sprache in der Argumentation zu *env
eben dem (Nicht-)Gehalt nach nur aus politischen oder rhetorischen
Gründen Erwähnung finden kann, nach Art eines Strohmanns,
oder bestenfalls als Anlass.
Post by Helmut Schellong
["Du sollst die POSIX-Schittstelle für ENV verwenden!"]
Da ist eine Menge Dramatik enthalten; ziemlich übertrieben.
Woran gemessen?
Helmut Schellong
2016-09-12 15:30:33 UTC
Permalink
Post by G.B.
Post by Helmut Schellong
Ich nahm vollständige funktionale Tests vor.
Die *Exe* waren/sind bezüglich des Themas *als Produkt fehlerfrei*!
Eine exe mit anforderungsgemäß funktionierenden Teilsystem
macht immer noch nicht klar, was C für die Nicht-Beachtung
von POSIX-Schnittstellen hergeben soll.
getenv ist ja in C standardisiert, von POSIX ebenfalls, weil
der C-Standard in POSIX enthalten ist.
Die anderen Funktionen sind nur von POSIX standardisiert.

Der C-Standard nennt UB bei seinen Funktionen.
Der POSIX-Standard tut das auch.
Das hat die gleiche Bedeutung.
Post by G.B.
Es mag in diesem besonderen Fall auch nicht bedeutsam sein,
was WIMRE, auf GNU/Linux mit glibc in Sachen Netzwerk schon
[...] Ich nehme an, dass der Herstellungsprozess
Deines Programms solche Eventualitäten vollständig überprüft,
damit weiterhin auf den Aufruf der POSIX-Schnittstellen
verzichtet werden kann.
Ich sagte schon, es gibt nur write, read, lseek, open, close,
putenv, memset, memcpy und ähnlich in meinem Programm.

Ich verwende teilweise unsetenv, soweit verfügbar.
Post by G.B.
Post by Helmut Schellong
["Du sollst die POSIX-Schittstelle für ENV verwenden!"]
Da ist eine Menge Dramatik enthalten; ziemlich übertrieben.
Woran gemessen?
An den realen faktischen Zuständen.
Die sind fast völlig unproblematisch.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2016-09-12 13:56:01 UTC
Permalink
Hallo,
Post by Helmut Schellong
Ich nahm vollständige funktionale Tests vor.
Wenn "funktionale Tests" vollstaendig waeren, gaebe es viel weniger Fehler
und Sicherheitsluecken in existierender Software ...
Post by Helmut Schellong
Die *Exe* waren/sind bezüglich des Themas *als Produkt fehlerfrei*!
Nur weil keine Auswirkungen von Fehlern bekannt sind, heisst das noch nicht
zwingend, dass die Software fehlerfrei waere ...
Post by Helmut Schellong
Da ist eine Menge Dramatik enthalten; ziemlich übertrieben.
"undefined" heisst, es koennte alles passieren, im schlimmsten Fall sogar
vom aktuellen Systemzustand, dem Datum oder der Mondphase abhaengig ...
Das ist der Grund, weshalb man sich auch nach "funktionalen Tests" *niemals*
auf "undefined behaviour" verlassen sollte.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Helmut Schellong
2016-09-12 15:54:32 UTC
Permalink
Post by Juergen Ilse
Hallo,
Post by Helmut Schellong
Ich nahm vollständige funktionale Tests vor.
Wenn "funktionale Tests" vollstaendig waeren, gaebe es viel weniger Fehler
und Sicherheitsluecken in existierender Software ...
Das wird so sein.

Ich teste insbesondere während der Ursprungskreation von Quellcode
sehr intensiv.
Deshalb muß ich später fast nie etwas korrigieren.
Und falls doch, dann nur Winzigkeiten.

Wirklich gefährlich sind Umbauten von kompletten Quellen, z.B. wegen
Wechsels der Endianess (bei Embedded).
Man vergißt manche Anpassungen mit hoher Wahrscheinlichkeit.

Auch die Änderung von sizeof(long) von 4 -> 8 ist gefährlich.
Ebenso die von size_t -> 64 Bit.
Post by Juergen Ilse
Post by Helmut Schellong
Die *Exe* waren/sind bezüglich des Themas *als Produkt fehlerfrei*!
Nur weil keine Auswirkungen von Fehlern bekannt sind, heisst das noch nicht
zwingend, dass die Software fehlerfrei waere ...
Ja, allerdings unterscheide ich strikt a.out und quelle.c .

Das Produkt a.out kann fehlerfrei sein [1], obwohl die Quelle problematische
Teile enthält, die das Potential haben, schädlich zu wirken.

[1] Sogar mit sehr hoher Wahrscheinlichkeit.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-12 16:13:48 UTC
Permalink
Post by Helmut Schellong
Wirklich gefährlich sind Umbauten von kompletten Quellen, z.B. wegen
Wechsels der Endianess (bei Embedded).
Man vergißt manche Anpassungen mit hoher Wahrscheinlichkeit.
Auch die Änderung von sizeof(long) von 4 -> 8 ist gefährlich.
Ebenso die von size_t -> 64 Bit.
Ich finde es ja nun völlig trivial, Code so zu bauen, dass das überhaupt
nicht gefährlich ist.


Stefan
Rainer Weikusat
2016-09-12 15:47:55 UTC
Permalink
Post by G.B.
Post by Helmut Schellong
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Warum reden wir dann über C? Es scheint vielmehr um statisch
gebundenen Objektcode für ein passend eingerichtetes System
zu gehen, und sein Verhalten, gerade im nicht von C definierten Fall,
also in dem Fall, in dem sich von C aus nicht urteilen lässt,
wird mit dem Ergebnis "überprüft", dass die Ausführung
wahrscheinlich nicht die GAU-Schwelle überschreiten wird.
Anekdote die an dieser Stelle unbedingt erzaehlt werden muss: Vor ein
paar Jahren sass ich mal in einem Buero in China mit einen PCB auf das
ich - streng nach Gebrauchansweisung - ein OS flashen
wollte. Dummerweise fuehrte jeder Versuch nur zu einem
Systemabsturz. Das fand ich damals ziemlich gruseling weil mein Wissen
um diese Dinge sich auf den Inhalt der Gebrauchsanweisung
beschraenkte. Getreu dem alten Marine-Motto "Geht weil muss" habe ich
mal also in Flashprogrammierung sowohl allgemein als auch fuer den
konkreten Chip hineingelesen. Als ich davon genuegend verstanden hatte,
habe ich mir den (ARM9 Assembler)-Code angesehen, der das ROM zu
programmieren versuchte. Dort fand ich einen Algorithmus, der mit dem
dokumentierten Verfahren schlicht nichts zu tun hatte sowie einen
Kommentar "This is not the documented procedure. But we've tested it".

Nachdem ich den Code so geaendert hatte, dass er das Flash so zu
programmieren versuchte, wie das nach Ansicht des Herstellers getan
werden sollte, funktionierte das dann auch.

Ich bezweifle ernsthat, das ich dem Monatsgehalt der Knallcharge, die
diesen Bockmist fabriziert hatte, irgendwann in meinem Leben auch nur
nahekommen werden.
Helmut Schellong
2016-09-12 16:06:24 UTC
Permalink
Post by Rainer Weikusat
Ich bezweifle ernsthat, das ich dem Monatsgehalt der Knallcharge, die
diesen Bockmist fabriziert hatte, irgendwann in meinem Leben auch nur
nahekommen werden.
Das erinnert mich an Harry Sneed.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2016-09-12 15:57:14 UTC
Permalink
Post by G.B.
Post by Helmut Schellong
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Warum reden wir dann über C? Es scheint vielmehr um statisch
gebundenen Objektcode für ein passend eingerichtetes System
zu gehen, und sein Verhalten, gerade im nicht von C definierten Fall,
also in dem Fall, in dem sich von C aus nicht urteilen lässt,
wird mit dem Ergebnis "überprüft", dass die Ausführung
wahrscheinlich nicht die GAU-Schwelle überschreiten wird.
Anekdote die an dieser Stelle unbedingt erzaehlt werden muss: Vor ein
paar Jahren sass ich mal in einem Buero in China mit einen PCB auf das
ich - streng nach Gebrauchansweisung - ein OS flashen
wollte. Dummerweise fuehrte jeder Versuch nur zu einem
Systemabsturz. Das fand ich damals ziemlich gruseling weil mein Wissen
um diese Dinge sich auf den Inhalt der Gebrauchsanweisung
beschraenkte. Getreu dem alten Marine-Motto "Geht weil muss" habe ich
mich also in Flashprogrammierung sowohl allgemein als auch fuer den
konkreten Chip hineingelesen. Als ich davon genuegend verstanden hatte,
habe ich mir den (ARM9 Assembler)-Code angesehen, der das ROM zu
programmieren versuchte. Dort fand ich einen Algorithmus, der mit dem
dokumentierten Verfahren schlicht nichts zu tun hatte sowie einen
Kommentar "This is not the documented procedure. But we've tested it".

Nachdem ich den Code so geaendert hatte, dass er das Flash so zu
programmieren versuchte, wie das nach Ansicht des Herstellers getan
werden sollte, funktionierte das dann auch.

Ich bezweifle ernsthat, das ich dem Monatsgehalt der Knallcharge, die
diesen Bockmist fabriziert hatte, irgendwann in meinem Leben auch nur
nahekommen werde.
Thomas Jahns
2016-09-12 09:42:54 UTC
Permalink
Post by Helmut Schellong
Das tue ich ja nicht.
Wenn die Exe kein UB zeigt, ist sie ohne UB.
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Ich prüfe, ob meine Exe UB zeigen.
Du hast schlicht nicht verstanden, was UB meint: UB meint, dass das Verhalten
des Programms nicht von entsprechenden Normen diktiert wird. Dass ein Programm
trotzdem funktioniert, hat damit so wenig zu tun wie die Frage, ob
Feuerwehrfahrzeuge rot sein müssen, um Brände zu löschen.

Was Du beschreibst, ist die Abwesenheit von Laufzeitfehlern (fault).
Laufzeitfehler sind aber nicht deckungsgleich mit Programmierfehlern, zu denen
UB gehört. Es kann sowohl a) Programme geben, die ohne (eigene)
Programmierfehler nicht korrekt funktionieren, weil die Laufzeitumgebung oder
der Compiler fehlerhaft sind und es kann b) Programme mit massenhaft
Programmierfehlern geben, die ohne Laufzeitfehler funktionieren, weil zufällig
kein Fehler beobachtbar ist.

Was hier scheinbar alle außer Dich erstaunt ist, dass Du willens bist
absichtlich Programmierfehler einzubauen, nur weil Deine derzeitige
Entwicklungsumgebung das entsprechende Programm ohne beobachtbaren Fehler
ausführt. Sehenden Auges Zustand b) herbeizuführen halte ich ohne gewichtigen
Grund für sehr fragwürdig.
Post by Helmut Schellong
Ich sagte in anderen Postings, daß ich unter Windows die
Funktionen setenv und unsetenv nicht zur Verfügung habe.
Unter Unix hatte ich unsetenv lange Zeit nicht zur
Verfügung.
Das ist doch kein Grund: nichts hindert Dich, *environ zu kopieren und das zu
ändern. Nur *environ so, wie Du es von der C Laufzeitumgebung erhalten hast,
darfst Du nach den einschlägigen Regeln eben nicht ändern, wenn Du ein Programm
ohne Programmierfehler haben möchtest. Du darfst ja sowohl environ als auch
selbst angelegte Strings verändern.

Aber da Du offenbar nicht daran interessiert bist, fehlerarme Programme zu
schreiben, kannst Du natürlich auch alle Regeln ignorieren. Über rote Ampeln
kann man evtl. auch ohne Konsequenzen laufen, wenn weder kreuzender Verkehr noch
Verkehrspolizisten in der Nähe sind. Nur löst es halt bei den meisten Befremden
aus, wenn sich jemand hinterher beschwert, von so einem Verhalten negative
Konsequenzen zu erfahren, obwohl es bis dahin ja stets ohne funktioniert habe.

Thomas
Helmut Schellong
2016-09-12 11:19:30 UTC
Permalink
Post by Thomas Jahns
Post by Helmut Schellong
Das tue ich ja nicht.
Wenn die Exe kein UB zeigt, ist sie ohne UB.
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Ich prüfe, ob meine Exe UB zeigen.
Du hast schlicht nicht verstanden, was UB meint: UB meint, dass das Verhalten
des Programms nicht von entsprechenden Normen diktiert wird. Dass ein
Programm trotzdem funktioniert, hat damit so wenig zu tun wie die Frage, ob
Feuerwehrfahrzeuge rot sein müssen, um Brände zu löschen.
Doch, ich habe durchaus verstanden, schon vor langer Zeit.
Jedoch andere verstehen nicht die konkrete in der Praxis vorliegende
Komplexität zum Thema Software-Fehler.

Beispiel: Es ist bekannt, daß ein neues Windows zunächst Fehler im
Millionenbereich enthält.
Diese Zahl wird durch Tests reduziert.
Wenn 100000 .. 200000 restliche Fehler erreicht sind, wird das Produkt
als marktreif betrachtet - und so auf den Markt gebracht.

Wie wirkt das denn im Vergleich zu diesem Thread?
Post by Thomas Jahns
Was Du beschreibst, ist die Abwesenheit von Laufzeitfehlern (fault).
Laufzeitfehler sind aber nicht[...]
Ich nehme an der konkreten Exe funktionale Tests vor.
Und zwar 100%-Tests.
Es werden alle existierenden Funktionen (zum Thema) getestet.
Mehr kann nicht getan werden.
Wenn alles korrekt arbeitet, ist die Exe als Produkt in Ordnung!

Man beachte, daß ich schrieb: die *Exe* ist in Ordnung.
Das sollte doch mal beachtet werden!
Post by Thomas Jahns
Was hier scheinbar alle außer Dich erstaunt ist, dass Du willens bist
absichtlich Programmierfehler einzubauen, nur weil Deine derzeitige
Entwicklungsumgebung das entsprechende Programm ohne beobachtbaren Fehler
ausführt. Sehenden Auges Zustand b) herbeizuführen halte ich ohne gewichtigen
Grund für sehr fragwürdig.
Ich weiß (schon immer), daß niemand nachweisen kann, daß in einer Software
keinerlei Fehler (mehr) enthalten sind.
Es können stets Fehler schlummern, mit dem Potential, schädlich
zur Wirkung kommen zu können.
Das ist eine klar theoretische Angelegenheit.
(Die Praxis sprach ich zuvor an.)
Post by Thomas Jahns
Post by Helmut Schellong
Ich sagte in anderen Postings, daß ich unter Windows die
Funktionen setenv und unsetenv nicht zur Verfügung habe.
Unter Unix hatte ich unsetenv lange Zeit nicht zur
Verfügung.
Das ist doch kein Grund: nichts hindert Dich, *environ zu kopieren und das zu
ändern. Nur *environ so, wie Du es von der C Laufzeitumgebung erhalten hast,
darfst Du nach den einschlägigen Regeln eben nicht ändern,[...]
Die Historie dazu muß als Gesamtbild bekannt sein:
Das Programm war zu Anfang für *DOS*, Windows und Unix.
An ein Kopieren war nicht zu denken, wegen Speichermangels unter DOS.
Dann hätte ich das eigene environ auch an eine exec() anderen Typs
übergeben müssen.
Ich wollte (1995) nicht aufwendige Extrawürste für die verschiedenen
Systeme, zumal meine Methode ja funktionierte, auch heute noch.
Post by Thomas Jahns
Aber da Du offenbar nicht daran interessiert bist, fehlerarme Programme zu
schreiben, kannst Du natürlich auch alle Regeln ignorieren. Über rote Ampeln
[...]
Hier muß differenziert werden.
Die Exe als Produkt ist bezüglich Env fehlerfrei.
Die Software enthält in einem Bereich UB mit einem unbekannten
Auswirkungspotential.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-12 16:13:07 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Gib doch mal ein Beispiel - zu write(), zu read(), ...
Naja, wenn eins deiner Programme direkt mit dem Internet kommuniziert,
dann gibt es da z.B. CVE 2015-7547. Eine Liste findest du unter
Es steht also fest, daß Programme wie z.B. bsh keine libc-Updates
wegen Sicherheitsmängeln brauchen.
Nein, das steht nicht fest.
Post by Helmut Schellong
Post by Thomas Koenig
Korrekt, das ist die Konsequenz, wenn man sich auf undefiniertes
Verhalten verl�sst - Programme h�ren pl�tzlich auf zu funktionieren.
Das gleiche kann auch genauso f�r Updates von Compilern gelten.
Ich verlasse mich nicht auf UB.
Ich schätze die Lage so ein, daß ein UB extrem unwahrscheinlich ist.
Meine Prüfungen zeigen, daß meine Einschätzung richtig ist.
Meine Einschätzung sagt, dass es Pfusch ist, sowas ohne Not zu tun.
Post by Helmut Schellong
Post by Thomas Koenig
Undefiniertes Verhalten mit Absicht in Programme einzubauen,
ist mindestens grob fahrl�ssig.
Das tue ich ja nicht.
Wenn die Exe kein UB zeigt, ist sie ohne UB.
Ich habe in einem anderen Posting bewiesen, daß meine
Exe für alle Plattformen kein UB aufweisen.
Ich prüfe, ob meine Exe UB zeigen.
Das kannst du nicht prüfen, da du nicht in der Lage bist, alle möglichen
Umgebungsbedingungen zu enumerieren.

Funktioniert deine exe in chinesischer Locale? In arabischer? Hast du
mit Cyrix-Prozessoren getestet? Hast du auf Rechnern, wo getaddrinfo nur
IPX-Adressen bringt (keine Ahnung, ob es sowas gibt) getestet? Hast du
im Linux-Emulator von FreeBSD getestet? Im "Ubuntu-Subsystem" von
Microsoft? Auf case-sensitiven, case-preserving und case-insensitiven
Filesystemen? Mit allen Pfadlängen von 1 bis 100k? Mit allen
Environment-Größen von 1 bis 1000k?


Stefan
Helmut Schellong
2016-09-12 21:03:19 UTC
Permalink
Post by Stefan Reuther
Post by Helmut Schellong
Ich prüfe, ob meine Exe UB zeigen.
Das kannst du nicht prüfen, da du nicht in der Lage bist, alle möglichen
Umgebungsbedingungen zu enumerieren.
Funktioniert deine exe in chinesischer Locale? In arabischer? Hast du
mit Cyrix-Prozessoren getestet? Hast du auf Rechnern, wo getaddrinfo nur
IPX-Adressen bringt (keine Ahnung, ob es sowas gibt) getestet? Hast du
im Linux-Emulator von FreeBSD getestet? Im "Ubuntu-Subsystem" von
Microsoft? Auf case-sensitiven, case-preserving und case-insensitiven
Filesystemen? Mit allen Pfadlängen von 1 bis 100k? Mit allen
Environment-Größen von 1 bis 1000k?
Ich kompiliere zurzeit für Windows, Linux, FreeBSD.
iX86 LC_ALL=C
Das ist sehr übersichtlich.

Ich werde nicht wieder für DOS, SCO-Unix, SCO-Openserver,
SCO-Openunix, Unixware, Solaris kompilieren.

FreeBSD kann ab 10.3 auch Linux-Exe64 direkt ausführen.
(Exe32 schon ewig.)

bsh enthält keinerlei Netzwerkkram.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-13 14:27:41 UTC
Permalink
Post by Helmut Schellong
Post by Stefan Reuther
Funktioniert deine exe in chinesischer Locale? In arabischer? Hast du
mit Cyrix-Prozessoren getestet? Hast du auf Rechnern, wo getaddrinfo nur
IPX-Adressen bringt (keine Ahnung, ob es sowas gibt) getestet? Hast du
im Linux-Emulator von FreeBSD getestet? Im "Ubuntu-Subsystem" von
Microsoft? Auf case-sensitiven, case-preserving und case-insensitiven
Filesystemen? Mit allen Pfadlängen von 1 bis 100k? Mit allen
Environment-Größen von 1 bis 1000k?
Ich kompiliere zurzeit für Windows, Linux, FreeBSD.
iX86 LC_ALL=C
Das ist sehr übersichtlich.
Wie du compilierst, ist zweitrangig. Interessant ist, wie der User (den
du nicht kennst) ausführt.
Post by Helmut Schellong
FreeBSD kann ab 10.3 auch Linux-Exe64 direkt ausführen.
(Exe32 schon ewig.)
Und du hast nachgewiesen, dass deren Linux-Emulator sich an allen
Stellen genau so benimmt wie das Original? Du hast einen automatischen
Test mit messbar 100% Zweigabdeckung? Respekt.


Stefan
Rainer Weikusat
2016-09-13 16:17:13 UTC
Permalink
Post by Stefan Reuther
Post by Helmut Schellong
Post by Stefan Reuther
Funktioniert deine exe in chinesischer Locale? In arabischer? Hast du
mit Cyrix-Prozessoren getestet? Hast du auf Rechnern, wo getaddrinfo nur
IPX-Adressen bringt (keine Ahnung, ob es sowas gibt) getestet? Hast du
im Linux-Emulator von FreeBSD getestet? Im "Ubuntu-Subsystem" von
Microsoft? Auf case-sensitiven, case-preserving und case-insensitiven
Filesystemen? Mit allen Pfadlängen von 1 bis 100k? Mit allen
Environment-Größen von 1 bis 1000k?
[...]
Post by Stefan Reuther
Post by Helmut Schellong
FreeBSD kann ab 10.3 auch Linux-Exe64 direkt ausführen.
(Exe32 schon ewig.)
Und du hast nachgewiesen, dass deren Linux-Emulator sich an allen
Stellen genau so benimmt wie das Original?
Das duerfte fuer den konkreten Fall (direkte Manipulation des Feldes,
auf das environ bei Programmstart zeigte) keine Rolle spielen. Da ist
man nur zu Eiertaenzen um C-Librayfunktion herum, die sich einbilden,
die Umgebung manipulieren zu duerfen, gezwungen.

ZB wird ein manuelles 'Loeschen' von Umgebungsvariable gefolgt von einem
putenv auf FreeBSD die vermeintlich geloeschten Variablen auch wieder
herbeizaubern.
Thomas Koenig
2016-09-12 17:42:08 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Gib doch mal ein Beispiel - zu write(), zu read(), ...
Naja, wenn eins deiner Programme direkt mit dem Internet kommuniziert,
dann gibt es da z.B. CVE 2015-7547. Eine Liste findest du unter
Es steht also fest, daß Programme wie z.B. bsh keine libc-Updates
wegen Sicherheitsmängeln brauchen.
Hast du die ganze Liste durchgesehen (71 Einträge)? Ich hatte nur
einen einzigen genannt.

Hast du auch die Liste mit den _zukünftig entdeckten_ Bugs
durchgeschaut, um sicher zu sein, dass Du von keinem davon
betroffen bist? Wenn du das gemacht hast, hast du noch ganz andere
Verdienstmöglichkeiten; zero-day exploits kann man für eine ganze
Menge Geld verkaufen. :-)
Post by Helmut Schellong
Ich verlasse mich nicht auf UB.
Ich schätze die Lage so ein, daß ein UB extrem unwahrscheinlich ist.
Undefined behavior ist in diesem Fall sicher. In deinen eigenen
Worten: 100% sicher!

Dass du das als "extrem unwahrscheinlich" bezeichnest, ist
ziemlich amüsant.
Helmut Schellong
2016-09-12 21:14:35 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Gib doch mal ein Beispiel - zu write(), zu read(), ...
Naja, wenn eins deiner Programme direkt mit dem Internet kommuniziert,
dann gibt es da z.B. CVE 2015-7547. Eine Liste findest du unter
Es steht also fest, daß Programme wie z.B. bsh keine libc-Updates
wegen Sicherheitsmängeln brauchen.
Hast du die ganze Liste durchgesehen (71 Einträge)? Ich hatte nur
einen einzigen genannt.
Das scheint alles Internetkram zu sein.
Damit hat bsh nun überhaupt keine Berührung.

pop.bsh + pop.bin sind die einzigen Programme, die mit Internet
was machen, wobei pop.bin Sockets programmiert.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-12 21:34:07 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Gib doch mal ein Beispiel - zu write(), zu read(), ...
Naja, wenn eins deiner Programme direkt mit dem Internet kommuniziert,
dann gibt es da z.B. CVE 2015-7547. Eine Liste findest du unter
Es steht also fest, daß Programme wie z.B. bsh keine libc-Updates
wegen Sicherheitsmängeln brauchen.
Hast du die ganze Liste durchgesehen (71 Einträge)? Ich hatte nur
einen einzigen genannt.
Das scheint alles Internetkram zu sein.
Ich wusste gar nicht, dass vscanf oder strftime Internetkram sind
(nur so als Beispiele). Aber man lernt ja nie aus.

Schön, dass deine Kristallkugel alle noch nicht offengelegten
Fehler der glibc schon geprüft und als ungefährlich eingestuft
hat. Das ist doch mal ein überzeugendes Argument für das statische
Linken deiner Programme ;-)
Helmut Schellong
2016-09-12 21:45:09 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Das scheint alles Internetkram zu sein.
Ich wusste gar nicht, dass vscanf oder strftime Internetkram sind
(nur so als Beispiele). Aber man lernt ja nie aus.
Ich benutzte das Wort 'scheint'.

Die bsh hat auch nichts mit vscanf und strftime zu tun.
Ich habe in bsh fast alles selbst entwickelt.
Es gibt CatS(), CatSn(), writef(), write1(), memcmp_F(),
xyz_F(n==70), etc.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-13 19:23:37 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Das scheint alles Internetkram zu sein.
Ich wusste gar nicht, dass vscanf oder strftime Internetkram sind
(nur so als Beispiele). Aber man lernt ja nie aus.
Ich benutzte das Wort 'scheint'.
Heisst "scheint" bei dir, dass das Gegenteil mindestens
genauso wahrscheinlich ist?
Post by Helmut Schellong
Die bsh hat auch nichts mit vscanf und strftime zu tun.
Ich habe in bsh fast alles selbst entwickelt.
Es gibt CatS(), CatSn(), writef(), write1(), memcmp_F(),
xyz_F(n==70), etc.
OMG. Du bastelst dir also deine ganz eigenen Fehler und
Unzulänglichkeiten zusammen.

"Reinvented wheels are often square."
Helmut Schellong
2016-09-13 19:49:15 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Die bsh hat auch nichts mit vscanf und strftime zu tun.
Ich habe in bsh fast alles selbst entwickelt.
Es gibt CatS(), CatSn(), writef(), write1(), memcmp_F(),
xyz_F(n==70), etc.
OMG. Du bastelst dir also deine ganz eigenen Fehler und
Unzulänglichkeiten zusammen.
Das Gegenteil ist der Fall.
Post by Thomas Koenig
"Reinvented wheels are often square."
Solche Sprichwörter sind Sprichwörter; die über meinen
Code nichts aussagen.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Helmut Schellong
2016-09-14 09:55:14 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Die bsh hat auch nichts mit vscanf und strftime zu tun.
Ich habe in bsh fast alles selbst entwickelt.
Es gibt CatS(), CatSn(), writef(), write1(), memcmp_F(),
xyz_F(n==70), etc.
OMG. Du bastelst dir also deine ganz eigenen Fehler und
Unzulänglichkeiten zusammen.
"Reinvented wheels are often square."
Nö.

Rainer W. schrieb:
---------------------------------------------------------------
Ausser in relative seltenen Faellen werden Vergleiche
unterschiedlicher Strings nach 1 - 3 Zeichen abbrechen koennen.
---------------------------------------------------------------

Da ich das seit Jahrzehnten weiß, hatte ich eine eigene
memcmp_F() entwickelt, die pur byte-weise vergleicht
und daher 'sofort' schnell ist.

Hauptteil:
===================================================================
.L45:
addq $1, %rax
cmpq %rdx, %rax
je .L44
.L40:
movzbl 1(%rdi,%rax), %ecx
movzbl 1(%rsi,%rax), %r8d
cmpb %r8b, %cl
je .L45
jmp .L39
===================================================================

libc:
Hier wundert mich, daß da misaligned auf 8-byte-Stücke zugegriffen wird.
Das müßte heftig Straftakte kosten.
Weiterhin werden hier auch von vornherein gleiche Strings
bis zum Ende verglichen.

ENTRY(memcmp)
cld /* set compare direction forward */
movq %rdx,%rcx /* compare by longs */
shrq $3,%rcx
repe
cmpsq
jne L5 /* do we match so far? */

movq %rdx,%rcx /* compare remainder by bytes */
andq $7,%rcx
repe
cmpsb
jne L6 /* do we match? */

xorl %eax,%eax /* we match, return zero */
ret

L5: movl $8,%ecx /* We know that one of the next */
subq %rcx,%rdi /* eight pairs of bytes do not */
subq %rcx,%rsi /* match. */
repe
cmpsb
L6: xorl %eax,%eax /* Perform unsigned comparison */
movb -1(%rdi),%al
xorl %edx,%edx
movb -1(%rsi),%dl
subl %edx,%eax
ret
END(memcmp)
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
G.B.
2016-09-14 13:16:12 UTC
Permalink
Post by Helmut Schellong
ENTRY(memcmp)
cld /* set compare direction forward */
movq %rdx,%rcx /* compare by longs */
shrq $3,%rcx
repe
cmpsq
Die hierin verborgene Mikroparallelität spielt deiner
Messung nach keine Rolle, im allgemeinen Fall des
Vergleichs beliebig langer void*?
Helmut Schellong
2016-09-14 17:36:13 UTC
Permalink
Post by G.B.
Post by Helmut Schellong
ENTRY(memcmp)
cld /* set compare direction forward */
movq %rdx,%rcx /* compare by longs */
shrq $3,%rcx
repe
cmpsq
Die hierin verborgene Mikroparallelität spielt deiner
Messung nach keine Rolle, im allgemeinen Fall des
Vergleichs beliebig langer void*?
Messung?
Ich tat nichts messen, gemessenen Schrittes.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-14 16:10:17 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
"Reinvented wheels are often square."
Nö.
---------------------------------------------------------------
Ausser in relative seltenen Faellen werden Vergleiche
unterschiedlicher Strings nach 1 - 3 Zeichen abbrechen koennen.
---------------------------------------------------------------
Da ich das seit Jahrzehnten weiß, hatte ich eine eigene
memcmp_F() entwickelt, die pur byte-weise vergleicht
und daher 'sofort' schnell ist.
"byte-weise" und "schnell" sind auf Prozessoren größer als Intel 8088
Antonyme. Mit "wortweise" kommt man langsam in die Nähe von "schnell".

Hast du gemessen?
Post by Helmut Schellong
Hier wundert mich, daß da misaligned auf 8-byte-Stücke zugegriffen wird.
Das müßte heftig Straftakte kosten.
Weiterhin werden hier auch von vornherein gleiche Strings
bis zum Ende verglichen.
ENTRY(memcmp)
cld /* set compare direction forward */
movq %rdx,%rcx /* compare by longs */
shrq $3,%rcx
repe
cmpsq
Hier werden keine gleichen Strings bis zum Ende verglichen. Tipp: "repe"
heißt "repeat while equal". Das bricht bei einem Unterschied in den
ersten 8 Bytes sofort ab.

Ich finde in glibc jedenfalls für mehrere Prozessoren jeweils
verschiedene memcpy's. Offenbar hat da jemand sich Gedanken gemacht, was
je nach Prozessor das schnellste ist.


Stefan
Helmut Schellong
2016-09-14 17:50:25 UTC
Permalink
[...]
Post by Stefan Reuther
Hier werden keine gleichen Strings bis zum Ende verglichen. Tipp: "repe"
heißt "repeat while equal". Das bricht bei einem Unterschied in den
ersten 8 Bytes sofort ab.
Die Pointer a und b: (a==b)==true

Das kommt vor in manchen Algorithmen.
Meine memcmp_F() hat diesen Test.
Kann Code im Falle des Falles mehrfach schneller machen.

static int memcmp_F(const void *d0, const void *s0, uint n)
{
const byte *d=d0, *s=s0;
if (n && d!=s) {
do if (*d!=*s) return (int)*d-(int)*s;
while (--n&&(++d,++s,1));
}
return 0;
}

Kann sein, daß ich noch Messungen mache.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2016-09-14 18:47:34 UTC
Permalink
Post by Helmut Schellong
static int memcmp_F(const void *d0, const void *s0, uint n)
{
const byte *d=d0, *s=s0;
if (n && d!=s) {
do if (*d!=*s) return (int)*d-(int)*s;
while (--n&&(++d,++s,1));
}
return 0;
}
Diese Funktion saugt.

int memcmp_G(void *p0, void *p1, unsigned n)
{
char *pp0, *pp1;
unsigned ofs;
int r;

if (!n || p0 == p1) return 0;

pp0 = p0;
pp1 = p1;
ofs = 0;
while (!(r = pp0[ofs] - pp1[ofs]) && ++ofs < n);

return r;
}

NB: Fuer gcc 4.7.2 ergibt das in beiden Faellen (fast) dieselbe
eigentliche Schleife, aber die vorsaetzlich Compiler-Verwirrung in _F hat
eine Instruktion mehr vor dem Ruecksprung und expliziten Code fuer den
ersten Vergleich.
Helmut Schellong
2016-09-15 01:06:45 UTC
Permalink
Post by Rainer Weikusat
Post by Helmut Schellong
static int memcmp_F(const void *d0, const void *s0, uint n)
{
const byte *d=d0, *s=s0;
if (n && d!=s) {
do if (*d!=*s) return (int)*d-(int)*s;
while (--n&&(++d,++s,1));
}
return 0;
}
Diese Funktion saugt.
int memcmp_G(void *p0, void *p1, unsigned n)
{
char *pp0, *pp1;
unsigned ofs;
int r;
if (!n || p0 == p1) return 0;
pp0 = p0;
pp1 = p1;
ofs = 0;
while (!(r = pp0[ofs] - pp1[ofs]) && ++ofs < n);
return r;
}
NB: Fuer gcc 4.7.2 ergibt das in beiden Faellen (fast) dieselbe
eigentliche Schleife, aber die vorsaetzlich Compiler-Verwirrung in _F hat
eine Instruktion mehr vor dem Ruecksprung und expliziten Code fuer den
ersten Vergleich.
Das mit dem expliziten Code stimmt.

Aber ich kündigte Messungen an:
=======================================================================
mall/stack 129.300 19.300 [æs] ta/tb = 6.70
Bem.: malloc/stack 1000x rekursiv PentiumIII700/UnixWare

mall/stack 233.500 20.100 [æs] ta/tb = 11.62
Bem.: malloc/stack 1000x rekursiv PentiumIII700/Linux

mall/stack 275.000 26.000 [æs] ta/tb = 10.74
Bem.: malloc/stack 1000x rekursiv PentiumIII700/WinNT

mall/stack 435.938 26.562 [æs] ta/tb = 16.41
Bem.: malloc/stack 1000x rekursiv PentiumIII700/FreeBSD43

mall/stack 4880.000 663.000 [æs] ta/tb = 7.36
Bem.: malloc/stack 1000x rekursiv Pentium60/OpenServer
......................................................................
memcmp/memcmp_F 0.256 4.513 [ns] ta/tb = 0.06
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp/memcmp_F 0.254 4.212 [ns] ta/tb = 0.06
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp/memcmp_F 0.270 4.212 [ns] ta/tb = 0.06
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp/memcmp_F 0.265 0.301 [ns] ta/tb = 0.88
Bem.: abcd, abcd, 5 CoreDuo3333/FreeBSD_10.1

memcmp/memcmp_F 37.676 4.511 [ns] ta/tb = 8.35
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp/memcmp_F 37.117 4.514 [ns] ta/tb = 8.22
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1
......................................................................
memcmp_G/memcmp_F 4.511 5.416 [ns] ta/tb = 0.83
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_G/memcmp_F 4.510 5.416 [ns] ta/tb = 0.83
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_G/memcmp_F 4.463 5.416 [ns] ta/tb = 0.82
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_G/memcmp_F 4.134 5.416 [ns] ta/tb = 0.76
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_G/memcmp_F 4.510 5.416 [ns] ta/tb = 0.83
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_F/memcmp_G 4.689 5.115 [ns] ta/tb = 0.92
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_F/memcmp_G 4.814 5.115 [ns] ta/tb = 0.94
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_G/memcmp_F 5.415 5.415 [ns] ta/tb = 1.00
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

memcmp_G/memcmp_F 5.415 5.414 [ns] ta/tb = 1.00
Bem.: abcd, abcD, 5 CoreDuo3333/FreeBSD_10.1

=======================================================================

Ich habe mein uraltes Meßprogramm in Betrieb genommen.
Ich mußte es von clock() auf getrusage() umbauen.

Die ersten drei Messungen (memcmp) machten mich argwöhnisch.
Die vierte (Gleichheit) machte die Sache für mich klar.

Der gcc5 benutzte nicht memcmp, sondern emulierte diese!
Der return-Wert war 1 und 0 bei Ungleichheit bzw. Gleichheit.
Das war falsch. memcmp_F lieferte 32.
Der Compiler optimierte stark, weil ich für ihn sichtbare
Zeichenketten-Konstanten verwendete.
Als ich die ersetzte durch 'char s1[64], s2[64];', gab es die Messungen
5 und 6, die korrekt sind. memcmp gab nun auch 32 zurück.
Meine memcmp_F ist also mehr als 8-mal schneller bei kurzen Strings.

Der gcc5 inline-te memcmp_F, ohne das Keyword 'inline'.
Das ist aber korrekt, da aus einer Quellcode-Library.
Der Unterschied ist sicher gering, da Argumente in Registern
übergeben werden.

Das Pärchen _G _F steckt in einer .o-Datei.
Gcc5 -DMEMCMPgf -opt pt.c ptf.o
Die erste Messung hatte immer bessere Werte, wie der Tausch G<->F zeigt.
Es befindet sich nun eine Dummy-Messung vor den eigentlichen Messungen.
Siehe die letzten beiden Messungen.

Die Funktion _G ist besser, weil sie weniger Code hat.
r = Subtraktion ist eine gute Maßnahme.
Der Typ char kann dazu führen, daß die 'a-b' sign-extended werden.
(int-Promotion)
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2016-09-15 02:12:59 UTC
Permalink
Hallo,
Post by Helmut Schellong
Der gcc5 benutzte nicht memcmp, sondern emulierte diese!
Der Sprachstandard erlaubt dem Compiler, Funktionsaufrufe von standardlibrary-
funktionen durch funktionsgleichen inline code zu ersetzen.
Post by Helmut Schellong
Der return-Wert war 1 und 0 bei Ungleichheit bzw. Gleichheit.
Das war falsch.
Nein, es entspricht der Dokumentation. Der Standard garantiert dir keine
bestimmten Werte, sondern lediglich (abhaengig vom Vergleichsergebnis)
einen Wert <0, =0 oder >0. Wenn du bestimmte Werte erwartest, ist das
*dein* Fehler.
Post by Helmut Schellong
Der gcc5 inline-te memcmp_F, ohne das Keyword 'inline'.
... was ihm laut Sprachstandard auch erlaubt ist. Nicht vom Standard
garantierte Annahmen darueber, wie der Compiler etwas umzusetzen habe,
fuehrte beim linux-kernel 2.0.35 zum crash, wenn er mit einer gcc-Version
neuer als 2.7.x uebersetzt wurde, weil neuere Compiler eine bessere
Code-Analyse machten und daher einen schmutzigen Hack (Verwendung eines
Variablenwertes ausserhalb seines Gueltigkeitsbereichs) zu komplett
disfunktionalem Code uebersetzte. Das kommt dabei heraus, wenn Leute
glauben, durch "besonders trickreiche Programmierung" besonders opti-
mieren zu wolle, ohne darauf zu achten, dass sie ggfs. Annahmen ueber
den erzeugten Code voraussetzen, die ihnen niemand garantiert.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Helmut Schellong
2016-09-15 11:12:46 UTC
Permalink
Post by Juergen Ilse
Post by Helmut Schellong
Der gcc5 benutzte nicht memcmp, sondern emulierte diese!
Der Sprachstandard erlaubt dem Compiler, Funktionsaufrufe von standardlibrary-
funktionen durch funktionsgleichen inline code zu ersetzen.
Das hatte der Compiler nicht gemacht.
Es hatte memcmp ganz weggelassen und nur den return-Wert gesetzt.
Auch das ist erlaubt.
Post by Juergen Ilse
Post by Helmut Schellong
Der return-Wert war 1 und 0 bei Ungleichheit bzw. Gleichheit.
Das war falsch.
Nein, es entspricht der Dokumentation. Der Standard garantiert dir keine
bestimmten Werte, sondern lediglich (abhaengig vom Vergleichsergebnis)
einen Wert <0, =0 oder >0. Wenn du bestimmte Werte erwartest, ist das
*dein* Fehler.
Ich bezog mich auf die man-Page:
========================================================================
The memcmp() function returns zero if the two strings are identical,
otherwise returns the difference between the first two differing bytes
(treated as unsigned char values, so that `\200' is greater than `\0',
========================================================================
Und ich benutzte ja die memcmp() aus der dortigen libc.
Post by Juergen Ilse
Post by Helmut Schellong
Der gcc5 inline-te memcmp_F, ohne das Keyword 'inline'.
... was ihm laut Sprachstandard auch erlaubt ist. Nicht vom Standard
garantierte Annahmen darueber, wie der Compiler etwas umzusetzen habe,
fuehrte beim linux-kernel 2.0.35 zum crash, wenn er mit einer gcc-Version
neuer als 2.7.x uebersetzt wurde, weil neuere Compiler eine bessere
Code-Analyse machten und daher einen schmutzigen Hack (Verwendung eines
Variablenwertes ausserhalb seines Gueltigkeitsbereichs) zu komplett
disfunktionalem Code uebersetzte. Das kommt dabei heraus, wenn Leute
glauben, durch "besonders trickreiche Programmierung" besonders opti-
mieren zu wolle, ohne darauf zu achten, dass sie ggfs. Annahmen ueber
den erzeugten Code voraussetzen, die ihnen niemand garantiert.
Ich weiß, daß der Compiler das darf.
Ich machte die Mitteilung, weil es um Zeitmessungen geht.
Es ist seriös und angebracht, dann solche Infos zu geben.

Idealerweise sollte man bei vergleichenden Zeitmessungen allen Funktionen
den gleichen Prototyp geben und alle Funktionen zu einer xyz.o kompilieren.

Bei Quellcode-Libraries ist das anders zu sehen.
Es ist okay, diese Funktionen normal als Quelle zu inkludieren, da es sie
in einer .o-Datei gar nicht gibt.
Andererseits ist das dann kein unverfälschter Vergleich von Algorithmen.
Es kommt also auf die Aufgabenstellung der Messung an.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2016-09-15 11:26:48 UTC
Permalink
Hallo,
Post by Helmut Schellong
Post by Juergen Ilse
Post by Helmut Schellong
Der return-Wert war 1 und 0 bei Ungleichheit bzw. Gleichheit.
Das war falsch.
Nein, es entspricht der Dokumentation. Der Standard garantiert dir keine
bestimmten Werte, sondern lediglich (abhaengig vom Vergleichsergebnis)
einen Wert <0, =0 oder >0. Wenn du bestimmte Werte erwartest, ist das
*dein* Fehler.
========================================================================
The memcmp() function returns zero if the two strings are identical,
otherwise returns the difference between the first two differing bytes
(treated as unsigned char values, so that `\200' is greater than `\0',
========================================================================
Und ich benutzte ja die memcmp() aus der dortigen libc.
Was ist die "dortige libc"? Auf dem Linux-System auf dem gerade mein
Newsreader leauft, besagt die man-page nur:
==========================================================================
RETURN VALUE
The memcmp() function returns an integer less than, equal to, or
greater than zero if the first n bytes of s1 is found, respectively, to
be less than, to match, or be greater than the first n bytes of s2.
==========================================================================
Dort steht nicht, dass der Rueckgabewert wirklich der Differenz der beiden
ersten unterschiedlichen Bytes als unsigned char entsprechen wuerde.
Post by Helmut Schellong
Idealerweise sollte man bei vergleichenden Zeitmessungen allen Funktionen
den gleichen Prototyp geben und alle Funktionen zu einer xyz.o kompilieren.
Protoypen der standard-library selbst in die Quelltexte einzufuegen statt
sie aus den entsprechenden Headern zu uebernehmen, ist IIRC laut Standard
auch schon "undefined" ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Helmut Schellong
2016-09-15 12:53:00 UTC
Permalink
Post by Juergen Ilse
Hallo,
Post by Helmut Schellong
Post by Juergen Ilse
Post by Helmut Schellong
Der return-Wert war 1 und 0 bei Ungleichheit bzw. Gleichheit.
Das war falsch.
Nein, es entspricht der Dokumentation. Der Standard garantiert dir keine
bestimmten Werte, sondern lediglich (abhaengig vom Vergleichsergebnis)
einen Wert <0, =0 oder >0. Wenn du bestimmte Werte erwartest, ist das
*dein* Fehler.
========================================================================
The memcmp() function returns zero if the two strings are identical,
otherwise returns the difference between the first two differing bytes
(treated as unsigned char values, so that `\200' is greater than `\0',
========================================================================
Und ich benutzte ja die memcmp() aus der dortigen libc.
Was ist die "dortige libc"? Auf dem Linux-System auf dem gerade mein
==========================================================================
RETURN VALUE
The memcmp() function returns an integer less than, equal to, or
greater than zero if the first n bytes of s1 is found, respectively, to
be less than, to match, or be greater than the first n bytes of s2.
==========================================================================
Dort steht nicht, dass der Rueckgabewert wirklich der Differenz der beiden
ersten unterschiedlichen Bytes als unsigned char entsprechen wuerde.
Beide Plattformen erfüllen den C-Standard.
Beide Compiler erfüllen den C-Standard.
Eine Plattform dokumentiert einen höheren Informationsgehalt des
return-Wertes.
Ein Compiler erfüllt nicht die Plattformvorgabe, was allerdings
verständlich ist.

Plattformen dürfen den Standard beliebig übererfüllen.
Compiler dürfen das auch, aber müssen wohl nicht den Plattformen
bei Übererfüllungen folgen.
Post by Juergen Ilse
Post by Helmut Schellong
Idealerweise sollte man bei vergleichenden Zeitmessungen allen Funktionen
den gleichen Prototyp geben und alle Funktionen zu einer xyz.o kompilieren.
Protoypen der standard-library selbst in die Quelltexte einzufuegen statt
sie aus den entsprechenden Headern zu uebernehmen, ist IIRC laut Standard
auch schon "undefined" ...
Das tue ich doch gar nicht, und habe es auch nicht geschrieben.

Der einen Funktion im Testprogramm gebe ich den Prototypen aus dem
Standard-Header, sofern es eine Standard-Funktion ist.
(<stdlib.h> <string.h> sind doch pauschal inkludiert!)
Der anderen Funktion im Testprogramm gebe ich den Prototypen aus
meinem Header, oder direkt.
Oder Mischformen davon.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2016-09-15 14:07:02 UTC
Permalink
[...]
Post by Helmut Schellong
Post by Rainer Weikusat
int memcmp_G(void *p0, void *p1, unsigned n)
{
char *pp0, *pp1;
unsigned ofs;
int r;
if (!n || p0 == p1) return 0;
pp0 = p0;
pp1 = p1;
ofs = 0;
while (!(r = pp0[ofs] - pp1[ofs]) && ++ofs < n);
return r;
}
[...]
Post by Helmut Schellong
=======================================================================
[...]
Post by Helmut Schellong
Die Funktion _G ist besser, weil sie weniger Code hat.
r = Subtraktion ist eine gute Maßnahme.
Das bietet sich als Beispiel fuer einen 'Wahrheittyp als schaedlich
eingestuft'-Text an: Der _F-code hatte einen Test gefolgt von einer
Subtraktion weil das ja 'irgendwie' zwei fundamental unterschiedliche
Dinge sind: Das Ergebnis von != ist ein 'Wahrheitswert' waehrend - (fuer
den gegebenen Fall) eine Ganzzahl berechnet wobei 'ganze Zahlen' und
'Wahrheitswerte' herkoemmlich als disjunkte Mengen empfunden werden.

In C sind sie das aber nicht: Sowohl != als auch - berechnen eine
Ganzzahl und Bedingungskonstrukte erwarten eine solche Zahl als
Argument. Deswegen sind != und - an dieser Stelle vollkommen
gleichberechtigt obwohl Fiktionen wie 'bool' das zu kaschieren
versuchen: Jede arithmetische Operation, deren Resultat den
Anforderungen genuegt, dh (hier) 0 bei Gleichheit, andernfalls
irgendein anderer Wert, kann als kontrollierender Ausdruck fuer while
benutzt werden[*].

[*] Dh auch eine Zuweisung falls man den berechneten Wert spaeter noch
benoetigt. Man koennte das natuerlich auch als

do r = pp0[ofs] - pp1[ofs]; while (!r && ++ofs < n);

ausdruecken.
G.B.
2016-09-15 15:00:14 UTC
Permalink
Post by Rainer Weikusat
Sowohl != als auch - berechnen eine
Ganzzahl und Bedingungskonstrukte erwarten eine solche Zahl als
Argument.
Ist die Zuverlässigkeit folgenden Tests von der Norm garantiert?

void charIs8() {
switch (1) {
case 0: break;
case CHAR_BIT == 8: break;
}
}
Helmut Schellong
2016-09-15 15:12:34 UTC
Permalink
Post by G.B.
Post by Rainer Weikusat
Sowohl != als auch - berechnen eine
Ganzzahl und Bedingungskonstrukte erwarten eine solche Zahl als
Argument.
Ist die Zuverlässigkeit folgenden Tests von der Norm garantiert?
void charIs8() {
switch (1) {
case 0: break;
case CHAR_BIT == 8: break;
}
}
Der Standard verlangt einen konstanten Integer-Ausdruck an der Stelle.
Zur Kompilierzeit steht '1' fest.
Das ist eine Konstante, und muß okay sein.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2016-09-15 15:19:51 UTC
Permalink
Post by G.B.
Post by Rainer Weikusat
Sowohl != als auch - berechnen eine
Ganzzahl und Bedingungskonstrukte erwarten eine solche Zahl als
Argument.
Ist die Zuverlässigkeit folgenden Tests von der Norm garantiert?
void charIs8() {
switch (1) {
case 0: break;
case CHAR_BIT == 8: break;
}
}
Ich denke nein. Ein case-Label muss mit einer 'integer constants
expression' assoziiert sein aber fuer CHAR_BIT wird lediglich 'constant
expression' gefordert. Es ist ausdruecklich davon ausgenommen, ein
'char' sein zu muessen (5.2.4.2.1|1) damit waere etwas wie

#define CHAR_BIT 8.0

zulaessig.

Claus Reibenstein
2016-09-12 08:06:39 UTC
Permalink
Post by Thomas Koenig
Redest du jetzt nur �ber deine Shell, bei der du solche Sachen machst?
^

Stell mal Deinen Reader richtig ein. Laut Header postest Du UTF-8. Der
Inhalt ist jedoch mitnichten UTF-8.

Gruß
Claus
Rainer Weikusat
2016-09-11 14:44:13 UTC
Permalink
[...]
Post by Helmut Schellong
Post by Peter J. Holzer
Ich könnte mir z.B. auch eine Datenstruktur vorstellen, bei der die
Position eines bestimmten Environment-Strings in environ durch eine
Hash-Funktion bestimmt wird. Wenn Du da Elemente verschiebst, werden sie
nicht mehr gefunden. (Und wenn Du Pech hast, führt der Zugriff auf das
Element, das nicht mehr da ist, wo es erwartet wird, zu einem falschen
Ergebnis oder zu einem SEGV.)
Rainer W. hat hier die FreeBSD-Implementation dazu eingeführt.
Die hat ein getrenntes internes Struktur-Array.
Es ist dort erkennbar, daß fast jede denkbare Manipulation von environ,
die keine vorsätzliche Sabotage ist, erlaubt ist.
Für die ist 'environ' quasi ein User-Objekt.
Wenn ich z.B. einen Pointer überschreibe und damit vernichte, so ist
der z.B. für free() in der internen Struktur weiterhin vorhanden.
Die suchen _getrennt_ in beiden Arrays.
Im internen bis n, im environ bis NULL (wenn die interne NULL ist).
Das ist so nicht ganz richtig: getenv durchsucht *environ falls die
interne Liste noch nicht angelegt wurde (envVars == NULL) oder falls der
environ-Zeiger nicht mehr auf das Feld zeigt, auf das er zeigte, als
interne Liste und *environ Liste zum letzten mal synchronisiert wurden
(environ != intEnviron).
Helmut Schellong
2016-09-11 18:36:15 UTC
Permalink
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Die suchen _getrennt_ in beiden Arrays.
Im internen bis n, im environ bis NULL (wenn die interne NULL ist).
Das ist so nicht ganz richtig: getenv durchsucht *environ falls die
interne Liste noch nicht angelegt wurde (envVars == NULL) oder falls der
environ-Zeiger nicht mehr auf das Feld zeigt, auf das er zeigte, als
interne Liste und *environ Liste zum letzten mal synchronisiert wurden
(environ != intEnviron).
Das stimmt.
Ich hielt es nicht für notwendig, in der beispielhaften Liste einen
2-3-fach längeren Text hinzusetzen.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Helmut Schellong
2016-09-11 10:18:12 UTC
Permalink
On 09/10/16 15:32, Peter J. Holzer wrote:
[...]
Post by Peter J. Holzer
Ich könnte mir z.B. auch eine Datenstruktur vorstellen, bei der die
Position eines bestimmten Environment-Strings in environ durch eine
Hash-Funktion bestimmt wird. Wenn Du da Elemente verschiebst, werden sie
nicht mehr gefunden. (Und wenn Du Pech hast, führt der Zugriff auf das
Element, das nicht mehr da ist, wo es erwartet wird, zu einem falschen
Ergebnis oder zu einem SEGV.)
Konkret in der Praxis würde das anders aussehen.
Hash-Werte können recht häufig Kollisionen aufweisen.
Man ist folglich gezwungen, nach dem Sprung per Hash-Index
pauschal ein String-Compare durchzuführen, wobei nach erkannter
Nichtübereinstimmung eine Compare-Suche im gesamten Array
vorgenommen werden muß.

Solche Konzepte werden von erfahrenen Implementierern nicht verwendet
werden, da sie insgesamt v i e l aufwendiger und langsamer sind, wenn
sie auf ein typisches Environment angewendet werden.
Das Environment wird von Login-Shells intensiv genutzt, jedoch von
weiterem Scripting fast gar nicht.
Deshalb ist es auch unsinnig, da besonderen Aufwand zu treiben.
Bei mir:
env | wc
64 72 2209

Auf allen von mir genutzten Plattformen (etwa 8, heute 3) funktioniert
mein direktes Löschen - seit 1995.
Das sind die realen Fakten!

Ich behaupte nicht, daß das unendlich so weiter geht, aber bei neuen
Compilern teste ich ohnehin.
Und ich habe heutzutage unsetenv() unter Unix zur Verfügung.
Unter Windows habe ich nur getenv und putenv.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-11 10:39:22 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Peter J. Holzer
Ich könnte mir z.B. auch eine Datenstruktur vorstellen, bei der die
Position eines bestimmten Environment-Strings in environ durch eine
Hash-Funktion bestimmt wird. Wenn Du da Elemente verschiebst, werden sie
nicht mehr gefunden. (Und wenn Du Pech hast, führt der Zugriff auf das
Element, das nicht mehr da ist, wo es erwartet wird, zu einem falschen
Ergebnis oder zu einem SEGV.)
Konkret in der Praxis würde das anders aussehen.
Hash-Werte können recht häufig Kollisionen aufweisen.
Wenn man sie ungünstig implementiert, ja.
Post by Helmut Schellong
Man ist folglich gezwungen, nach dem Sprung per Hash-Index
pauschal ein String-Compare durchzuführen, wobei nach erkannter
Nichtübereinstimmung eine Compare-Suche im gesamten Array
vorgenommen werden muß.
Niemand ist zu so einer dämlichen Implementierung "gezwungen".

Vernünftigerweise sucht man dann nur alle Strings durch, die den
gleichen Hashwert haben.
Helmut Schellong
2016-09-11 18:27:51 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Konkret in der Praxis würde das anders aussehen.
Hash-Werte können recht häufig Kollisionen aufweisen.
Wenn man sie ungünstig implementiert, ja.
Die bloße Möglichkeit reicht schon.
Post by Thomas Koenig
Post by Helmut Schellong
Man ist folglich gezwungen, nach dem Sprung per Hash-Index
pauschal ein String-Compare durchzuführen, wobei nach erkannter
Nichtübereinstimmung eine Compare-Suche im gesamten Array
vorgenommen werden muß.
Niemand ist zu so einer dämlichen Implementierung "gezwungen".
Vernünftigerweise sucht man dann nur alle Strings durch, die den
gleichen Hashwert haben.
Compare, wie ich sagte.
Woher erfährt man, welche Strings den gleichen Hash-Wert haben?
Man muß alles abklappern.

Davon abgesehen sind memcmp sehr schnell, weil abgebrochen
werden kann, sobald ein Zeichen nicht paßt.
Das ist statistisch sehr oft beim ersten Zeichen schon der Fall.

Eine doppelt verlinkte Liste halte ich für besser.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-11 19:18:28 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Konkret in der Praxis würde das anders aussehen.
Hash-Werte können recht häufig Kollisionen aufweisen.
Wenn man sie ungünstig implementiert, ja.
Die bloße Möglichkeit reicht schon.
Die bloße Möglichkeit, dass du sie ungünstig implementierst?
Es gibt genügend bekannte Algorithmen für Hashes, die gut
funktionieren.
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Man ist folglich gezwungen, nach dem Sprung per Hash-Index
pauschal ein String-Compare durchzuführen, wobei nach erkannter
Nichtübereinstimmung eine Compare-Suche im gesamten Array
vorgenommen werden muß.
Niemand ist zu so einer dämlichen Implementierung "gezwungen".
Vernünftigerweise sucht man dann nur alle Strings durch, die den
gleichen Hashwert haben.
Compare, wie ich sagte.
Woher erfährt man, welche Strings den gleichen Hash-Wert haben?
Man muß alles abklappern.
Sorry, das ist jetzt sehr grundlegende Informatik. Ist mir nicht
ganz klar, warum ich dir das erklären muss, aber was solls...

Du rechnest deinen Hash aus. Den verwendest du als Index in eine
Tablle. In der Tabelle hast du z.B. eine verkettete Liste der
verschiedenen Keyword-Value-Pairs, in dem du dann suchen kannst.

Im durchschnittlichen Fall bist du damit bei O(1), wenn du
keine pathologisch schlechte Hashfunktion verwendest.

Ein einfaches, wenn auch nicht perfektes Beispiel findet man z.B bei
https://gist.github.com/tonious/1377667
Post by Helmut Schellong
Davon abgesehen sind memcmp sehr schnell, weil abgebrochen
werden kann, sobald ein Zeichen nicht paßt.
Dieser Algorithmus O(n) für das Vergleichen von n Zeichenketten,
wenn du alle Werte durchgehst.
Rainer Weikusat
2016-09-11 20:24:54 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Konkret in der Praxis würde das anders aussehen.
Hash-Werte können recht häufig Kollisionen aufweisen.
Wenn man sie ungünstig implementiert, ja.
Die bloße Möglichkeit reicht schon.
Die bloße Möglichkeit, dass du sie ungünstig implementierst?
Es gibt genügend bekannte Algorithmen für Hashes, die gut
funktionieren.
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Man ist folglich gezwungen, nach dem Sprung per Hash-Index
pauschal ein String-Compare durchzuführen, wobei nach erkannter
Nichtübereinstimmung eine Compare-Suche im gesamten Array
vorgenommen werden muß.
Niemand ist zu so einer dämlichen Implementierung "gezwungen".
Vernünftigerweise sucht man dann nur alle Strings durch, die den
gleichen Hashwert haben.
Compare, wie ich sagte.
Woher erfährt man, welche Strings den gleichen Hash-Wert haben?
Man muß alles abklappern.
Sorry, das ist jetzt sehr grundlegende Informatik. Ist mir nicht
ganz klar, warum ich dir das erklären muss, aber was solls...
Du rechnest deinen Hash aus. Den verwendest du als Index in eine
Tablle. In der Tabelle hast du z.B. eine verkettete Liste der
verschiedenen Keyword-Value-Pairs, in dem du dann suchen kannst.
Im durchschnittlichen Fall bist du damit bei O(1), wenn du
keine pathologisch schlechte Hashfunktion verwendest.
Ein einfaches, wenn auch nicht perfektes Beispiel findet man z.B bei
https://gist.github.com/tonious/1377667
Post by Helmut Schellong
Davon abgesehen sind memcmp sehr schnell, weil abgebrochen
werden kann, sobald ein Zeichen nicht paßt.
Dieser Algorithmus O(n) für das Vergleichen von n Zeichenketten,
wenn du alle Werte durchgehst.
Nichtsdestotrotz ist Suchen durch Nacheinder-Abklappern in einem Feld
fuer 'kleine' Felder normalerweise schneller als Suchen in einer
Hashtabelle. Im besten Fall erfordert das Berechnung des Hash-Werts fuer
den zu suchenden String (normalerweise erheblich teurer als ein
vollstaender Vergleich weil der pro Zeichen nur eine Subtraktion
erfordert) plus einen vollstaendigen Vergleich. Im schlechtesten Fall
eine ergebnislose, lineare Suche im gefundenen Hash-chain.

Ausser in relative seltenen Faellen werden Vergleiche unterschiedlicher
Strings nach 1 - 3 Zeichen abbrechen koennen.
Thomas Koenig
2016-09-11 21:21:14 UTC
Permalink
Post by Rainer Weikusat
Post by Thomas Koenig
Dieser Algorithmus O(n) für das Vergleichen von n Zeichenketten,
wenn du alle Werte durchgehst.
Nichtsdestotrotz ist Suchen durch Nacheinder-Abklappern in einem Feld
fuer 'kleine' Felder normalerweise schneller als Suchen in einer
Hashtabelle.
Kontext war eine Shell. Hmm, schaun mer mal, wie viele
Environment-Variablen ich im Augenblick so habe...

$ printenv | wc -l
113

$ printenv | sed -e 's/=.*//' | wc -c
1342

Sind also (ohne die Newlines) im Schnitt knapp 11 Buchstaben
pro Schlüsselwort.

Müsste man tatsächlich mal benchmarken.

Möglicherweise wäre auch ein sortierter Array besser, da
ist man wenigstens "nur" bei maximal sieben Vergleichen
als bei maximal 113 wie beim simplen Durchsuchen. Dann ist
man mal wenigstens O(log n).
Post by Rainer Weikusat
Im besten Fall erfordert das Berechnung des Hash-Werts fuer
den zu suchenden String (normalerweise erheblich teurer als ein
vollstaender Vergleich weil der pro Zeichen nur eine Subtraktion
erfordert) plus einen vollstaendigen Vergleich. Im schlechtesten Fall
eine ergebnislose, lineare Suche im gefundenen Hash-chain.
Worst case ist natürlich ein Problem
Post by Rainer Weikusat
Ausser in relative seltenen Faellen werden Vergleiche unterschiedlicher
Strings nach 1 - 3 Zeichen abbrechen koennen.
Jep, aber das ein paar mal zuviel :-)
Rainer Weikusat
2016-09-12 14:11:31 UTC
Permalink
Post by Thomas Koenig
Post by Rainer Weikusat
Post by Thomas Koenig
Dieser Algorithmus O(n) für das Vergleichen von n Zeichenketten,
wenn du alle Werte durchgehst.
Nichtsdestotrotz ist Suchen durch Nacheinder-Abklappern in einem Feld
fuer 'kleine' Felder normalerweise schneller als Suchen in einer
Hashtabelle.
Kontext war eine Shell. Hmm, schaun mer mal, wie viele
Environment-Variablen ich im Augenblick so habe...
$ printenv | wc -l
113
$ printenv | sed -e 's/=.*//' | wc -c
1342
Sind also (ohne die Newlines) im Schnitt knapp 11 Buchstaben
pro Schlüsselwort.
Ich habe hier 22 Umgebungsvariablen mit einer durschnittlichen
Namenslaenge von 8.1 Zeichen.
Post by Thomas Koenig
Müsste man tatsächlich mal benchmarken.
Fuer Felder mit bis zu 32 Eintraegen habe ich das vor ein paar Jahren
mal getan: Hashing chancenlos.
Thomas Koenig
2016-09-12 18:21:26 UTC
Permalink
Post by Rainer Weikusat
Post by Thomas Koenig
Kontext war eine Shell. Hmm, schaun mer mal, wie viele
Environment-Variablen ich im Augenblick so habe...
$ printenv | wc -l
113
$ printenv | sed -e 's/=.*//' | wc -c
1342
Sind also (ohne die Newlines) im Schnitt knapp 11 Buchstaben
pro Schlüsselwort.
Ich habe hier 22 Umgebungsvariablen mit einer durschnittlichen
Namenslaenge von 8.1 Zeichen.
Post by Thomas Koenig
Müsste man tatsächlich mal benchmarken.
Fuer Felder mit bis zu 32 Eintraegen habe ich das vor ein paar Jahren
mal getan: Hashing chancenlos.
Wie war denn der Faktor zwischen den Implementierungen? Damit könnte
man die Größe abschätzen, ab der Hashing schneller wird.

Die bash verwendet (nach einem kurzen Blick in die Quellen) auch Hashes.
Helmut Schellong
2016-09-11 21:28:49 UTC
Permalink
[...]
Post by Rainer Weikusat
Post by Thomas Koenig
Post by Helmut Schellong
Davon abgesehen sind memcmp sehr schnell, weil abgebrochen
werden kann, sobald ein Zeichen nicht paßt.
Dieser Algorithmus O(n) für das Vergleichen von n Zeichenketten,
wenn du alle Werte durchgehst.
Nichtsdestotrotz ist Suchen durch Nacheinder-Abklappern in einem Feld
fuer 'kleine' Felder normalerweise schneller als Suchen in einer
Hashtabelle. Im besten Fall erfordert das Berechnung des Hash-Werts fuer
den zu suchenden String (normalerweise erheblich teurer als ein
vollstaender Vergleich weil der pro Zeichen nur eine Subtraktion
erfordert) plus einen vollstaendigen Vergleich. Im schlechtesten Fall
eine ergebnislose, lineare Suche im gefundenen Hash-chain.
Ausser in relative seltenen Faellen werden Vergleiche unterschiedlicher
Strings nach 1 - 3 Zeichen abbrechen koennen.
So ist das.

.......................................................
for (i=fstc[c]-1; i<sizeof(Fu)/sizeof(*Fu); ++i) {
if (c!=Fu[i].n[0]) { e=fnam; goto FUVE; }
if (l<=1||memcmp(fnam+1, Fu[i].n+1, l)==0) break;
}
.......................................................

Das ist der gesamte Code zum Suchen der Funktionsnamen
des neuen Gleitkomma-Moduls der bsh.
Die Namen sind sortiert.
Es wird zum ersten Namen gesprungen, der den gleichen
Anfangsbuchstaben hat (fstc).
Sobald der erste Buchstabe nicht paßt, also bis dahin kein
passender Name gefunden wurde, liegt ein Nichtfinden vor.
memcmp() muß den ersten Buchstaben gar nicht untersuchen.
Der Code ist Schellong-typisch rasend schnell.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-12 18:27:20 UTC
Permalink
Post by Helmut Schellong
Es wird zum ersten Namen gesprungen, der den gleichen
Anfangsbuchstaben hat (fstc).
Du machst also schon Binning, wenn auch ein ziemlich
primitives.

Wenn also jemand viele Variablen mit dem gleichen Anfangsbuchstaben
hat, wird deine Implementierung langsam?

Das erinnert mich an einen Gary-Larson-Cartoonband. Da war am
Ende eine alphabetische Tabelle der Strips drin. Alle Buchstaben
waren leer, bis auf "T", weil alle Einträge mit "The one about"
losgingen.
Post by Helmut Schellong
Sobald der erste Buchstabe nicht paßt, also bis dahin kein
passender Name gefunden wurde, liegt ein Nichtfinden vor.
memcmp() muß den ersten Buchstaben gar nicht untersuchen.
Der Code ist Schellong-typisch rasend schnell.
Ist das ein Codewort für "In einem ein bisschen pathologischen
Fall total langsam" ?
Helmut Schellong
2016-09-12 21:34:29 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Es wird zum ersten Namen gesprungen, der den gleichen
Anfangsbuchstaben hat (fstc).
Du machst also schon Binning, wenn auch ein ziemlich
primitives.
Ja, weil die Liste sortiert ist.
Ohne Verlinkung.
Primitiv == schnell
Post by Thomas Koenig
Wenn also jemand viele Variablen mit dem gleichen Anfangsbuchstaben
hat, wird deine Implementierung langsam?
Kaum.
Es gibt lokale Variablen-Module, mit jeweils sehr wenigen Namen.

Nein:
let "functions()"
f= acosh(f) f= acos(f) i= arith_()
f= asinh(f) f= asin(f) f= atan2(f,f)
f= atanh(f) f= atan(f) f= avogadro()
f= boltzmann() f= c() f= cart_polar(f,f,$)
f= cbrt(f) f= ceil(f) i= constants()
f= copysign(f,f) f= cosh(f) f= cos(f)
i= dec_hour(f,$,$) f= degtorad(f) f= e()
f= earthacc() f= ec() f= eps0()
f= epsilon() f= erfc(f) f= erf(f)
f= exp2(f) f= exp(f) f= expm1(f)
f= fabs(f) f= factorial(i) f= faraday()
f= fdim(f,f) f= floor(f) f= fma(f,f,f)
f= fmax(f,f) f= fmin(f,f) f= fmod(f,f)
f= frexp(f,$) i= functions() i= getround()
f= goldenratio() f= gravity() f= hour_m_s(i,i,i)
f= hypot(f,f) f= klitzing() f= ldexp(f,i)
f= lgamma(f) i= llrint(f) i= llround(f)
f= log10(f) f= log1p(f) f= log2(f)
f= logb(f) f= log(f) f= modf(f,$)
f= mue0() f= nan() f= nchoosek(i,i)
f= nearbyint(f) f= nextafter(f,f) f= nexttoward(f,f)
f= pi() f= pi2() f= planck()
f= plancke() f= polar_cart(f,f,$) f= pow(f,f)
f= quaequ3p(f,f,f) f= quaequ3m(f,f,f) f= quaequ2p(f,f)
f= quaequ2m(f,f) f= radtodeg(f) f= remainder(f,f)
f= remquo(f,f,$) f= reciprocal(f) f= rint(f)
f= root(f,f) f= round(f) f= rpar2(f,f)
f= rpar3(f,f,f) f= scalbln(f,i) i= setround(i)
f= sinh(f) f= sin(f) f= sqrt2()
f= sqrt3() f= sqrt(f) f= tanh(f)
f= tan(f) f= tgamma(f) f= trunc(f)
f= z0()


[...]
Post by Thomas Koenig
Ist das ein Codewort für "In einem ein bisschen pathologischen
Fall total langsam" ?
Nein.
Ich schrieb doch, daß es sich um die Gleitkommafunktionenliste handelt.
Das ist eine Konstante.
Die steht doch im zugänglichen Manual, nun auch hier.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-12 21:44:44 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Es wird zum ersten Namen gesprungen, der den gleichen
Anfangsbuchstaben hat (fstc).
Du machst also schon Binning, wenn auch ein ziemlich
primitives.
Ja, weil die Liste sortiert ist.
Ohne Verlinkung.
Primitiv == schnell
Post by Thomas Koenig
Wenn also jemand viele Variablen mit dem gleichen Anfangsbuchstaben
hat, wird deine Implementierung langsam?
Kaum.
Es gibt lokale Variablen-Module, mit jeweils sehr wenigen Namen.
Und das heisst?

Wenn ich mal leichtsinnigerweise deine Shell verwenden würde,
um Berechnungen durchzuführen, und meine Variablen heissen

a1, a2, a3, a4, a5, a6, , ..., a1000

wie legst du die dann ab? Wie viele Variablen müsstest du im Schnitt
durchsuchen, um eine bestimmte Variable im symbol table zu finden?
Helmut Schellong
2016-09-12 22:13:13 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Es wird zum ersten Namen gesprungen, der den gleichen
Anfangsbuchstaben hat (fstc).
Du machst also schon Binning, wenn auch ein ziemlich
primitives.
Ja, weil die Liste sortiert ist.
Ohne Verlinkung.
Primitiv == schnell
Post by Thomas Koenig
Wenn also jemand viele Variablen mit dem gleichen Anfangsbuchstaben
hat, wird deine Implementierung langsam?
Kaum.
Es gibt lokale Variablen-Module, mit jeweils sehr wenigen Namen.
Und das heisst?
Es gibt den globalen Variablen-Modul.
Auf der Grundebene gibt es einen lokalen Modul.
Jede Funktion hat einen eigenen Modul.
Jeder Block {{ ...}} hat einen eigenen Modul.
Post by Thomas Koenig
Wenn ich mal leichtsinnigerweise deine Shell verwenden würde,
um Berechnungen durchzuführen, und meine Variablen heissen
a1, a2, a3, a4, a5, a6, , ..., a1000
wie legst du die dann ab? Wie viele Variablen müsstest du im Schnitt
durchsuchen, um eine bestimmte Variable im symbol table zu finden?
In
http://www.schellong.de/htm/rpar.bsh.html
steht:
set BUF:32.$(( llround(ceil(log10(End/Beg))*E*sz+E*sz) ))

und weitere Vorkommnisse von BUF und BUFC.

Bei großen Mengen gleichartiger Inhalte lege ich _eine_ Puffer-Variable
an, bis 300 MegaByte, die in beliebige Abschnitte per Offset und Länge
zerteilt werden kann.
Es wird dabei nur 1 Name unter beispw. 10 globalen Namen gesucht.
Ein Array-Element wird auf einen Schlag adressiert.

In dem Skript lege ich binäre Float-Werte mit je 16 Byte in BUF ab.
Also 'long double' (C) direkt.
sz==16 wird von 'typeset -F' geliefert.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-13 19:19:46 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Wenn ich mal leichtsinnigerweise deine Shell verwenden würde,
um Berechnungen durchzuführen, und meine Variablen heissen
a1, a2, a3, a4, a5, a6, , ..., a1000
wie legst du die dann ab? Wie viele Variablen müsstest du im Schnitt
durchsuchen, um eine bestimmte Variable im symbol table zu finden?
In
http://www.schellong.de/htm/rpar.bsh.html
set BUF:32.$(( llround(ceil(log10(End/Beg))*E*sz+E*sz) ))
und weitere Vorkommnisse von BUF und BUFC.
Bei großen Mengen gleichartiger Inhalte lege ich _eine_ Puffer-Variable
an, bis 300 MegaByte, die in beliebige Abschnitte per Offset und Länge
zerteilt werden kann.
Also nochmal die Frage: Ich habe 1000 Variablen (in einem Block),
mit dem gleichen Anfangsbuchstaben. Wieviel von denen musst
du mit deiner Methode im Schnitt durchsuchen, bis du die richtige
findest? Nach deiner Beschreibung würde ich vermuten, 500, aber
ich habe auch die Relevanz deiner Antwort auf die Frage nicht
ganz feststellen können.
Helmut Schellong
2016-09-13 19:43:48 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
und weitere Vorkommnisse von BUF und BUFC.
Bei großen Mengen gleichartiger Inhalte lege ich _eine_ Puffer-Variable
an, bis 300 MegaByte, die in beliebige Abschnitte per Offset und Länge
zerteilt werden kann.
Also nochmal die Frage: Ich habe 1000 Variablen (in einem Block),
mit dem gleichen Anfangsbuchstaben. Wieviel von denen musst
du mit deiner Methode im Schnitt durchsuchen, bis du die richtige
findest? Nach deiner Beschreibung würde ich vermuten, 500, aber
ich habe auch die Relevanz deiner Antwort auf die Frage nicht
ganz feststellen können.
Es ist eine lineare Suche. Folglich 500.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2016-09-14 20:05:13 UTC
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Also nochmal die Frage: Ich habe 1000 Variablen (in einem Block),
mit dem gleichen Anfangsbuchstaben. Wieviel von denen musst
du mit deiner Methode im Schnitt durchsuchen, bis du die richtige
findest?
Es ist eine lineare Suche. Folglich 500.
Sowas würde ich nie akzeptieren - einen O(n) - Algorithmus,
wo es einen O(1) - Algorithmus gibt.

Naja, wer's für einen leicht patholotischen Fall sehr mieses
Verhalten haben will...
Helmut Schellong
2016-09-15 01:23:11 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Post by Thomas Koenig
Wieviel von denen musst
du mit deiner Methode im Schnitt durchsuchen, bis du die richtige
findest?
Es ist eine lineare Suche. Folglich 500.
Sowas würde ich nie akzeptieren - einen O(n) - Algorithmus,
wo es einen O(1) - Algorithmus gibt.
Naja, wer's für einen leicht patholotischen Fall sehr mieses
Verhalten haben will...
Du solltest mal die Funktionen von Rainer W. und mir und ihre
Meßwerte anschauen.
Die brauchen 5 ns für einen Vergleich, auf einer CPU von 2008.

Ich hatte doch lang und breit von lokalen Variablen-Modulen
geschrieben, mit jeweils wenigen Variablen. Weiterhin das
Konzept mit 'set BUF:32.size'.
DAS sind die Konzepte in bsh, die am häufigsten verwendet werden.

Aber 5 ns pro Vergleich ist nicht langsam.
Das sind 2,5 us bei 500 Variablen.
Ich würde da nicht von einem sehr miesen Verhalten sprechen.
5 ns sind dermaßen schnell, daß bei theoretisch überlegenen
Algorithmen das Präparieren schon länger dauert.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2016-09-12 16:22:54 UTC
Permalink
Post by Rainer Weikusat
Post by Thomas Koenig
Ein einfaches, wenn auch nicht perfektes Beispiel findet man z.B bei
https://gist.github.com/tonious/1377667
Post by Helmut Schellong
Davon abgesehen sind memcmp sehr schnell, weil abgebrochen
werden kann, sobald ein Zeichen nicht paßt.
Dieser Algorithmus O(n) für das Vergleichen von n Zeichenketten,
wenn du alle Werte durchgehst.
Nichtsdestotrotz ist Suchen durch Nacheinder-Abklappern in einem Feld
fuer 'kleine' Felder normalerweise schneller als Suchen in einer
Hashtabelle. Im besten Fall erfordert das Berechnung des Hash-Werts fuer
den zu suchenden String (normalerweise erheblich teurer als ein
vollstaender Vergleich weil der pro Zeichen nur eine Subtraktion
erfordert) plus einen vollstaendigen Vergleich.
Naja, wir reden nicht von Krypto, da reicht im Zweifelsfall eine eher
simplizistische Hashfunktion.

Die aus dem referenzierten gist ist nun gerade ziemlich ungünstig
implementiert, das sollte eher was in der Art
while( key[i] != '\0' ) {
hashval = (hashval << 8) | (hashval >> 24);
hashval += key[ i ];
i++;
}
sein, was man wiederum zu einem parallelen Algorithmus optimieren kann
(32 Bits auf einmal verarbeiten). So, wie es dasteht, berücksichtigt es
immer nur die letzten 4 Zeichen eines Strings und bricht ab, sobald es
4x (bzw. 8x) 0xFF in dem String findet.
Post by Rainer Weikusat
Im schlechtesten Fall
eine ergebnislose, lineare Suche im gefundenen Hash-chain.
Dafür erlaubt eine Hashtabelle andere schöne Sachen. Zum Beispiel, wenn
man auf Geschwindigkeit erpicht ist, berechnet man die Hashwerte schon
beim Parsen und speichert sie im AST, dann ist man bei der Ausführung
schneller.


Stefan
Helmut Schellong
2016-09-11 21:08:21 UTC
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Die bloße Möglichkeit reicht schon.
Die bloße Möglichkeit, dass du sie ungünstig implementierst?
Nein, die bloße Möglichkeit, daß es zu einer Kollision
kommen kann.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2016-09-09 15:08:01 UTC
Permalink
Post by Helmut Schellong
E n v i r o n m e n t
PATH=ppppppp etc.
Unter Windows das Kommando 'set' und unter Unix 'env'
liefern den Inhalt des sogenannten Environments.
Stets das aktuelle Environment liefert 'extern char **environ'.
Scheint durch die C-Norm nicht definiert zu werden, vgl

The set of environment names and the method for altering the environment
list are implementation-defined.
[7.20.4.5|2]
Helmut Schellong
2016-09-09 15:58:02 UTC
Permalink
Post by Rainer Weikusat
Post by Helmut Schellong
E n v i r o n m e n t
PATH=ppppppp etc.
Unter Windows das Kommando 'set' und unter Unix 'env'
liefern den Inhalt des sogenannten Environments.
Stets das aktuelle Environment liefert 'extern char **environ'.
Scheint durch die C-Norm nicht definiert zu werden, vgl
The set of environment names and the method for altering the environment
list are implementation-defined.
[7.20.4.5|2]
Das ist so. Der C-Standard nennt 'environ' nicht.
Aber POSIX definiert 'environ'.
Und ich verwende 'environ' seit 1995 mit mehreren Compilern
auf allen relevanten Plattformen, auch Windows.

========================================================================
J.5 Common extensions
The following extensions are widely used in many systems, but are not
portable to all implementations.

J.5.1 Environment arguments
In a hosted environment, the main function receives a third argument,
char *envp[], that points to a null-terminated array of pointers to char,
each of which points to a string that provides information about the
environment for this execution of the program.

7.22.4.6 The getenv function
The getenv function searches an environment list, provided by the
host environment, for a string that matches the string pointed to by name.
The set of environment names and the method for altering the environment
list are implementation-defined.
The implementation shall behave as if no library function calls
the getenv function.
Returns
The getenv function returns a pointer to a string associated with the
matched list member. The string pointed to shall not be modified
by the program, but may be overwritten by a subsequent call to the
getenv function. If the specified name cannot be found, a null pointer
is returned.
=========================================================================

Es muß also eine solche Umgebung geben.
J ist nicht normativ.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2016-09-09 19:25:37 UTC
Permalink
Post by Helmut Schellong
E n v i r o n m e n t
PATH=ppppppp etc.
Unter Windows das Kommando 'set' und unter Unix 'env'
liefern den Inhalt des sogenannten Environments.
Stets das aktuelle Environment liefert 'extern char **environ'.
Das ist ein Pointer auf 'extern char *env[n]'.
In env[] sind Zeichenketten "name=inhalt" eingehängt.
Der Name env[] ist ausgedacht, der reale Name ist unbekannt.
[...]
Post by Helmut Schellong
Ich frage mich nur, was ich - ganz genau - von
Any application that directly modifies the pointers to which
the environ variable points has undefined behavior.
zu halten habe.
Ich modifiziere environ nämlich direkt, seit 1995, ohne Probleme.
environ modifiziere ich nicht, aber *environ.
A=aaaaaaaaa
B=bbbbbbbbb
C=ccccccccc
NULL
A=aaaaaaaaa
C=bbbbbbbbb
NULL
NULL
Funktioniert makellos.
Muß es IMO auch.
if (environ == NULL || environ[0] == NULL)
return (NULL);
else if (envVars == NULL || environ != intEnviron)
return (__findenv_environ(name, nameLen));
else {
envNdx = envVarsTotal - 1;
return (__findenv(name, nameLen, &envNdx, true));
}

https://github.com/freebsd/freebsd/blob/master/lib/libc/stdlib/getenv.c

Das benutzt ein intern verwaltes Feld von Strukturen mit folgender
Definition:

static struct envVars {
size_t nameLen;
size_t valueSize;
char *name;
char *value;
bool active;
bool putenv;
} *envVars = NULL;

Dieses interne Feld wird als Seiteneffekt von setenv, putenv oder
unsetenv konstruiert und wie man am oben angefuehrten getenv-Auszug
sieht, bekommt diese C-Bibliothek allgemein nichts davon mit das environ-Zeiger
geaendert wurden.

NB: Ich halte diese Implementierung nicht fuer eine gute Idee aber das
geht am Kern der Sache vorbei.
Helmut Schellong
2016-09-09 20:18:32 UTC
Permalink
[...]
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Funktioniert makellos.
Muß es IMO auch.
if (environ == NULL || environ[0] == NULL)
return (NULL);
else if (envVars == NULL || environ != intEnviron)
return (__findenv_environ(name, nameLen));
else {
envNdx = envVarsTotal - 1;
return (__findenv(name, nameLen, &envNdx, true));
}
https://github.com/freebsd/freebsd/blob/master/lib/libc/stdlib/getenv.c
Bei mir:
/usr/src/lib/libc/stdlib/getenv.c

Beim Code oben sind die 'else' überflüssig.

[...]
Post by Rainer Weikusat
und wie man am oben angefuehrten getenv-Auszug
sieht, bekommt diese C-Bibliothek allgemein nichts davon mit das environ-Zeiger
geaendert wurden.
So soll es sein. :-)

Ich vermute, alle libc sind so und werden es bleiben.

Wie sollte man denn auch prüfen, daß sich Pointer verändert haben?!
Alle Pointer stets intern kopieren, und bei jeder Aktion alle
auf Gleichheit prüfen? - Beknackt!
SIGSEGV bei realer Speicherverletzung reicht doch.

Warum ist diese pure C-Code-Angelegenheit nebst Standard-Beteiligung OT?
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Peter J. Holzer
2016-09-10 13:43:24 UTC
Permalink
Post by Rainer Weikusat
if (environ == NULL || environ[0] == NULL)
return (NULL);
else if (envVars == NULL || environ != intEnviron)
return (__findenv_environ(name, nameLen));
else {
envNdx = envVarsTotal - 1;
return (__findenv(name, nameLen, &envNdx, true));
}
https://github.com/freebsd/freebsd/blob/master/lib/libc/stdlib/getenv.c
Das benutzt ein intern verwaltes Feld von Strukturen mit folgender
static struct envVars {
size_t nameLen;
size_t valueSize;
char *name;
char *value;
bool active;
bool putenv;
} *envVars = NULL;
Dieses interne Feld wird als Seiteneffekt von setenv, putenv oder
unsetenv konstruiert und wie man am oben angefuehrten getenv-Auszug
sieht, bekommt diese C-Bibliothek allgemein nichts davon mit das
environ-Zeiger geaendert wurden.
else if (envVars == NULL || environ != intEnviron)
Ich weiß nicht, was »intEnviron« ist, aber ich tippe mal auf “internal
environment pointer”, und nehme an, dass das eine Kopie von environ ist.
Wenn der Benutzer environ ändert, merkt das die C-Bibliothek also sehr
wohl und kann darauf reagieren (muss sie laut
http://pubs.opengroup.org/onlinepubs/9699919799/functions/environ.html
auch:

| Applications can change the entire environment in a single operation by
| assigning the environ variable to point to an array of character
| pointers to the new environment strings. After assigning a new value to
| environ, applications should not rely on the new environment strings
| remaining part of the environment, as a call to getenv(), [XSI] [Option
| Start] putenv(), [Option End] setenv(), unsetenv(), or any function that
| is dependent on an environment variable may, on noticing that environ
| has changed, copy the environment strings to a new array and assign
| environ to point to it.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Rainer Weikusat
2016-09-10 14:45:11 UTC
Permalink
"Peter J. Holzer" <hjp-***@hjp.at> writes:

[...]
Post by Peter J. Holzer
Post by Rainer Weikusat
Das benutzt ein intern verwaltes Feld von Strukturen mit folgender
[...]
Post by Peter J. Holzer
Post by Rainer Weikusat
Dieses interne Feld wird als Seiteneffekt von setenv, putenv oder
unsetenv konstruiert und wie man am oben angefuehrten getenv-Auszug
sieht, bekommt diese C-Bibliothek allgemein nichts davon mit das
environ-Zeiger geaendert wurden.
else if (envVars == NULL || environ != intEnviron)
Ich weiß nicht, was »intEnviron« ist, aber ich tippe mal auf “internal
environment pointer”, und nehme an, dass das eine Kopie von environ ist.
Wenn der Benutzer environ ändert, merkt das die C-Bibliothek also sehr
wohl und kann darauf reagieren (muss sie laut
http://pubs.opengroup.org/onlinepubs/9699919799/functions/environ.html
Quasi zur Abwechslung hatte ich mal kein Wort versehentlich weggelassen:
Gemeint waren Zeiger in dem Feld, auf das environ zeigt, nicht der
environ-Zeiger selber. Im konkreten Fall hiesse das, dass eine
Umbegungsvariable, die jemand durch Ueberschreiben eines solchen Zeigers
geloescht zu haben meint, weiterhin via getenv zur Verfuegung stuende.
Helmut Schellong
2016-09-10 16:15:15 UTC
Permalink
Post by Rainer Weikusat
Post by Peter J. Holzer
http://pubs.opengroup.org/onlinepubs/9699919799/functions/environ.html
Gemeint waren Zeiger in dem Feld, auf das environ zeigt, nicht der
environ-Zeiger selber. Im konkreten Fall hiesse das, dass eine
Umbegungsvariable, die jemand durch Ueberschreiben eines solchen Zeigers
geloescht zu haben meint, weiterhin via getenv zur Verfuegung stuende.
Ja, deshalb verwende ich auch nicht getenv().
Ich verwende nur environ und putenv.
In einem Subprozeß ist eine nach meiner Methode gelöschte
Env-Variable allerdings erfolgreich verschwunden.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Peter J. Holzer
2016-09-14 07:11:39 UTC
Permalink
Post by Rainer Weikusat
[...]
Post by Peter J. Holzer
Post by Rainer Weikusat
Das benutzt ein intern verwaltes Feld von Strukturen mit folgender
[...]
Post by Peter J. Holzer
Post by Rainer Weikusat
Dieses interne Feld wird als Seiteneffekt von setenv, putenv oder
unsetenv konstruiert und wie man am oben angefuehrten getenv-Auszug
sieht, bekommt diese C-Bibliothek allgemein nichts davon mit das
environ-Zeiger geaendert wurden.
else if (envVars == NULL || environ != intEnviron)
[...]
Post by Rainer Weikusat
Post by Peter J. Holzer
Wenn der Benutzer environ ändert, merkt das die C-Bibliothek also sehr
wohl und kann darauf reagieren (muss sie laut
http://pubs.opengroup.org/onlinepubs/9699919799/functions/environ.html
Gemeint waren Zeiger in dem Feld, auf das environ zeigt, nicht der
environ-Zeiger selber.
Sorry, ich habe nicht genau genug gelesen.
Post by Rainer Weikusat
Im konkreten Fall hiesse das, dass eine Umbegungsvariable, die jemand
durch Ueberschreiben eines solchen Zeigers geloescht zu haben meint,
weiterhin via getenv zur Verfuegung stuende.
So ist es. Ob diese Implementation der Anlass für die relativ
ausführliche Erklärung in der Rationale war?

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Lesen Sie weiter auf narkive:
Loading...