Hozzászólások
Vgülis alapvetően egyetértek a veszélyes kódok számüzésével, habár ellentmod a "regi C alapelvekkel" miszerint hagyjuk a programozot veszelyesen kodolni, o tudja mit akar...
A segfaultok mibenletenek a felfedezese meg nem mindig olyan ordongos.
Az ilyen problemak okozta segfaultok nagyon egyszeruen es gyorsan felderithetok a gdb segitsegevel. Leforditod a progit debug modban, es a gdb poccre pontosan megmondja, hogy hol a hiba. NEm is igazan irt meg komoly programot az aki nem turkal mar hosszasan a debuggerben
:lol:
Tudom, hogy ez nem kenyelmes meg jo,(es lehet eccer majd en is szopok ilyen miatt) de a regi 5 10 eves kodokat igenis neha at kell nyalazni amennyiben atkerulnek ujrendszerekre. Mi lesz ha par ev mulva 64 biten futnanak, pl? A portolas mindigis resze volt ennek a szakmanak...
- A hozzászóláshoz be kell jelentkezni
Nézzétek meg az alábbi kis példaprogramot.
A program a hello stringet helyben nagybetûre
konvertálja és kiírja.
#include <stdio.h>
#include <ctype.h>
int main()
{
char *hello="Hello World!\n";
char *p=hello;
while( *p )
{
*p=toupper(*p);
p++;
}
printf("%s",hello);
return 0;
}
Ha a programot (GCC 3.4.2-vel) a
c++ -fwritable-strings ws.cpp
paranccsal fordítom, akkor fordító kiírja,
hogy a -fwritable-strings opció deprecated,
majd a végrehajtható program kiírja, hogy
HELLO WORLD.
Ha a programot a
c++ ws.cpp
paranccsal fordítom, akkor fordító nem ad warningot,
mégis a végrehajtható program azt írja ki, hogy
Segmentation Fault - core dumped.
Hangsúlyozom, nem az a kérdés,
hogy jó dolog-e stringeket helyben módosítani,
hanem, hogy a GCC-ben (C++-ban?) inkompatibilis
változások történnek. Emiatt 10 éve jól mûködõ,
-fwritable-strings opció nélkül is hibátlanul
forduló programok a jövõben váratlan segfaultokat
fognak csinálni.
Mi a véleményetek errõl?
- A hozzászóláshoz be kell jelentkezni
[quote:885ec66ce6="mrev"]Hangsúlyozom, nem az a kérdés,
hogy jó dolog-e stringeket helyben módosítani,
hanem, hogy a GCC-ben (C++-ban?) inkompatibilis
változások történnek.
Szerintem meg pont fordítva van. Nem az a kérdés, hogy jó dolog-e hogy a gcc-ben inkompatibilis változások történnek, hanem az, hogy jó dolog-e sztringeket helyben módosítani.
A gcc-ben nagyon sok egyéb inkompatibilis változás történt, egyre szigorúbban ragaszkodik a szabványokhoz, főleg c++ kódok terén, rahedli forrást patchelni kellett hogy a 2.95 után 3-assal, 3.2-essel, most 4-essel leforduljon.
Ha ragaszkodsz változatlan formában a 10 évvel ezelőtti, programozástechnikailag hibás, csak van-hozzá-gcc-workaround forráshoz, akkor nem látom okát, hogy miért akard a C-fordítót befrissíteni izomból, használd abból is a 10 évvel ezelőttit, jók lesznek azok együtt.
Az olyan intenzív dinamikus fejlődés, mint amit a gcc produkál (le a kalappal előtte, különösen ahhoz képest hogy GNU projekt), gyakorlatilag lehetetlen megoldani 100%-ig visszafelé kompatibilis módon, ők legalább tisztességesen felvállalják ezt, előre tervezik hogy mi mikor szűnik meg, kiírnak korrekt warningokat stb. Ezt szerintem így kell csinálni. A 100%-os kompatibilitásra törekvés igencsak lelassítaná a fejlődést és nehezebben átlátható bloatware-ré tenné a programot, tele jópár szükségtelen feature-rel.
- A hozzászóláshoz be kell jelentkezni
[quote:0095ad3c40="mrev"]Emiatt 10 éve jól mûködõ,
-fwritable-strings opció nélkül is hibátlanul
forduló programok a jövõben váratlan segfaultokat
fognak csinálni.
Ja, nem fognak váratlan segfaultot csinálni, mert nem fognak lefordulni, hiszen a gcc megmondja frankón hogy -fwritable-strings márpedig nem létezik. Ha meg kiszeded ezt az opciót, na ja, ha kiszedted volna már 10 évvel ezelőtt is segfaultolt volna, az tehát egy másik történet.
részlet man gcc-ből:
-fwritable-strings
Store string constants in the writable data segment and don't
uniquize them. This is for compatibility with old programs
which assume they can write into string constants.
Writing into string constants is a very bad idea; ``con-
stants'' should be constant.
- A hozzászóláshoz be kell jelentkezni
A -fwritable-strings opció már csak ezért is brain-damaged:
[code:1:90c83e5ac8]
#include <stdio.h>
void shift (char *p)
{
while (*p) {
(*p)++;
p++;
}
}
int main()
{
char *hello, *goodbye;
int i;
hello = "hello world";
shift(hello);
printf("%s\n", hello);
hello = "hello world";
shift(hello);
printf("%s\n", hello);
for (i = 0; i < 2; i++) {
goodbye = "goodbye cruel world";
shift(goodbye);
printf("%s\n", goodbye);
}
return 0;
}
[/code:1:90c83e5ac8]
ha kétszer egymás után ugyanazt az értéket adod egy sztringnek, az mást ad, mint ha cikluson belül teszed még kétszer. Vagyis a ciklus második végrehajtása során a goodbye változó _nem_ a "goodbye cruel world" szöveget kapja értékül, ami roppant mód félrevezető és olvashatatlanná teszi a forrást.
Szóval tényleg felejtendő ez a megoldás, tessék korrektül programozni, nem a kiskapuk kihasználásával :-)
- A hozzászóláshoz be kell jelentkezni
Szerintem se jó a stringeket helyben módosítani.
Viszont a -fwritable-strings megszûnésével a világon eddig
írt összes C++ kód újrafordítás után potenciálisan hibás lesz.
Ez az amiról szó van.
Ha az utóbbi 10 évben írtál félmillió C++ sort, vagy
neked kell karban tartani 10 millió sornyi C++ kódot,
akkor nem tudod, hogy ezekben hol van segfaultot okozó
string konverzió. A fordító nem keresi meg neked a hibákat:
ha megfigyelted, a hibás példa is warning mentesen fordul.
Természetesen 10 éve még nem létezett -fwritable-strings opció.
Más C++ fordítókban jelenleg sincs hasonló opció.
A témát azért nyitottam, hogy akinek van ilyen kódja,
az kezdjen el töprengeni rajta, hogyan fogja megtalálni
a hibákat. Lehetõleg ne úgy, hogy a programok segfaultolnak.
- A hozzászóláshoz be kell jelentkezni
[quote:ce7b0ac2fd="mrev"]Viszont a -fwritable-strings megszűnésével a világon eddig
írt összes C++ kód újrafordítás után potenciálisan hibás lesz.
Nem. Csak azok a C/C++ kódok lesznek potenciálisan hibásak, melyeket eddig a -fwritable-strings opcióval kellett fordítani. Ezek pedig nem csöndben sunyi módon lesznek hibásak, hanem a gcc kiköpi hogy ilyen opció márpedig nincs többé, így aki ezt használta, az feltételezhetően tudja hogy miért használta és tudja hogy nem annyi a megoldás hogy ezentúl kihagyja ezt az opciót.
Nagy különbség!
- A hozzászóláshoz be kell jelentkezni
Végignéztem az UHU-Linux 1.2 1200 forráscsomagjának fordítási naplóját, és egyedül a grub csomag esetén lehetett ezzel az opcióval találkozni. (Persze elvileg lehet még ilyen program, ami csöndben fordít, nem írva ki a parancsot, de ez nem túl valószínű.)
2005.02.02: grub cvs-ben javítják, így már neki sem kell.
2005.04.20: megjelenik a gcc 4.0, az első kiadás ami már nem támogatja ezt az opciót.
2005.05.08 (ma): grub 0.97, így már itt sem kell cvs-sel vacakolni.
A 2.7.2.3-tól kezdve a mostani 4.0-ig kismillió olyan változás volt a gcc-ben, ami jóval több programot érintett, mint ez most. Szóval no para :-D
- A hozzászóláshoz be kell jelentkezni
Csak hogy hozzaszoljak... stringeket helyben modositani nagyon is jo dolog. Ellenkezo esetben nagyon nagy memoriahasznalatot eredmenyezne egy-egy program (pl ha le akarom csapni a whitespacet a string vegerol, akkor azt igenis szeretnem ott helyben megtenni, es nem egy masolaton). Ami nagy bug, az a string konstansok helyben modositasa. Azt tenyleg komoly hiba.
Javaslatom, hogy a char *hello = "..." helyett legyen inkabb egy char *hello = strdup ("..."); es maris menni fog a cucc. Persze figyelni kell ra, hogy alkalmas idopontban ezt fel is kell szabaditani.[/i]
- A hozzászóláshoz be kell jelentkezni
[quote:4e77fb84c4="algernon"]stringeket helyben modositani nagyon is jo dolog. [...] Ami nagy bug, az a string konstansok helyben modositasa.
Valóban, teljesen jogos. Köszi a helyesbítést!
- A hozzászóláshoz be kell jelentkezni
Ha jogos, akkor mit szóltok ehhez?
extern void trim(char*); //helyben trimel
int main()
{
char * hello="Hello World ";
trim(hello);
...
}
Warning mentesen fordul, az eredmény pedig segfault.
Egyébként megnéztem:
A Borland C,
a Microsoft C,
a MinGW (windowsos GCC)
nem segfaultolnak hasonló helyzetben.
Most képzeld el, hogy te portolod az
Interbase-t GCC-re (Firebird). Hiába keresed
a -fwritable-strings opciókat a Borland szoftverében.
Ha az ember ilyen helyzetben van, kénytelen
programot írni a string literálok kikeresésére,
és kénytelen az összes elõfordulást ellenõrizni.
- A hozzászóláshoz be kell jelentkezni
[quote:7d03121c80="mrev"]Ha jogos, akkor mit szóltok ehhez?
extern void trim(char*); //helyben trimel
int main()
{
char * hello="Hello World ";
trim(hello);
...
}
char *hello = "hello word "; <- ITT A GOND!
char* konstanst ne akarj helyben modositani. Az altalaban a memorianak nem irhato reszeben van, ergo segfault. Ne csinald konstansra, es maris jo lesz.
Pl ez mukodni fog:
extern void trim (char *str);
int main (void)
{
char *hello;
hello = strdup("hello world ");
trim (hello);
printf ("%s\n", hello);
free (hello);
return 0;
}
- A hozzászóláshoz be kell jelentkezni
Akkor neked külön leírom: Nem az a bajom,
hogy ne tudnám ezt a hibát kijavítani, hanem az,
hogy a GCC-ben inkompatibilis változások vannak,
amitõl visszamenõleg hibássá válnak a korábban
elfogadott programok.
Külön bosszantó, ha erre azt írjátok, milyen jó,
hogy egy warning mentesen forduló program segfaultol.
Egyébként a GCC megtehetné, hogy megkövetelje
const char *hello=" Hello... ";
vagy
char *hello=(char*)"Hello...";
utóbbi esetben olyan kódot fordítva,
amiben a string literál módosítható.
De, egyiket sem teszi, a jelenlegi állapot pedig
ROSSZ.
- A hozzászóláshoz be kell jelentkezni
[quote:eeae549e1c="mrev"]Akkor neked külön leírom: Nem az a bajom,
hogy ne tudnám ezt a hibát kijavítani, hanem az,
hogy a GCC-ben inkompatibilis változások vannak,
amitõl visszamenõleg hibássá válnak a korábban
elfogadott programok.
...amely opcio mellesleg egy ideje deprecated, es a deprecated dolgokat gcc-bol ki szoktak irtani idonkent.
[quote:eeae549e1c="mrev"]
Külön bosszantó, ha erre azt írjátok, milyen jó,
hogy egy warning mentesen forduló program segfaultol.
[code:1:eeae549e1c]#include <stdio.h>
int main (void) { char *foo = NULL; printf ("%c\n", foo[1234]); return 0; }[/code:1:eeae549e1c]
Ez is warning nelkul fordul, aztan segfaultol. Van ilyen. Nem tud a compiler mindent elkapni helyetted.
Egyebkent, a kovetkezot latom a gcc 4.0 changesben:
GCC no longer accepts the -fwritable-strings option. Use named character arrays when you need a writable string.
Igy a fix meg egyszerubb, mint az, hogy dinamikusan allokalod. char *foo = "blabla" helyett char foo[] = "blabla".
Akar search & replace-el is meg lehet oldani. Mondjuk valahogy igy:
[code:1:eeae549e1c]printf ",s/char[ \t]*\*[ \t]*\(.*\)=[ \t]*\"/char \1[] = \"/g\nw\nq\n" | ed file.c[/code:1:eeae549e1c]
- A hozzászóláshoz be kell jelentkezni
[quote:b5c2407a87="mrev"]Egyébként a GCC megtehetné, hogy megkövetelje
const char *hello=" Hello... ";
Na igen, de ha valaki azt írja, hogy:
[code:1:b5c2407a87]char *hello = "Hello";[/code:1:b5c2407a87]
akkor arra gondol, hogy most a hello pointer a "Hello"-ra mutat, de bármikor változhat a helyzet, és mutathat pl egy dinamikusan létrehozott char tömbre.
A szabványt nem követő kódokat mindenképpen át kell nézni, mert visszafele kompatibilitást nem lehet feltételezni.
Ráadásul: a fordító sokszor azt csinálja, hogy ha több helyen áll a jobb oldalon pl a "hello" sztring, akkor az csak egyszer szerepel a binárisban, így még megbízhatatlanabb a sztringeket helyben módosító program.
- A hozzászóláshoz be kell jelentkezni
[quote:c6358494b1="mrev"]Külön bosszantó, ha erre azt írjátok, milyen jó,
hogy egy warning mentesen forduló program segfaultol.
A warningnak semmi köze a segfaulthoz. Nyilván kvázi esélye nincs lekövetnie a fordítónak, hogy itt a végrehajtás során read-only szegmensben akar majd módosítani a program ami segfaulthoz vezet.
- A hozzászóláshoz be kell jelentkezni
[quote:95338baf13="Panther"]Ráadásul: a fordító sokszor azt csinálja, hogy ha több helyen áll a jobb oldalon pl a "hello" sztring, akkor az csak egyszer szerepel a binárisban, így még megbízhatatlanabb a sztringeket helyben módosító program.
Így van, sőt, ha a több sztringkonstans közül az egyik a másiknak a végszelete, akkor is optimalizál: csak a hosszabbat tárolja le, a rövidebb egyszerűen egy pointer bele ennek a közepibe.
- A hozzászóláshoz be kell jelentkezni