Jporta feladatbeadás, gyakori hibák, FAQ

Otthon jól fut, de a ... Jporta nem fogadja el!

Mi az alapvető különbség a saját fejlesztőkörnyezetem és a Jporta között?

  1. A Jporta LINUX-on fut.
    • Amennyiben az Ön fejlesztőkörnyezete Windows alapú, és a program szöveges adatfájlokat dolgoz fel, akkor gyakran okoz gondot a két rendszerben eltérő sorvégkezelés (\r \n vs. \n). Ötleteket ld. lent
    • Nincs Windows specifikus interfész és header
    • Egészen biztos, hogy a memóriakezelés eltérő, ezért másutt, más memóriaszemét keletkezik. Ha a programban inicializálatlan változó, terület van akkor annak tartalma biztosan el fog térni.
    • Eltérőek a változók méretei
  2. A futtatás és fordítás batch környezetben történik. Nincs interaktív felület.
    • A standard inputról várt adatokat egy szövegfájlba kel írni, és azt fel kell tölteni a Szabványos bemenet optional ponthoz. Amennyiben az inputon speciális karakterek is előfordulnak (pl. TAB), akkor ügyelni kell, hogy olyan editorral hozzuk létre a fájlt, ami kétes ilyen karaktert tárolni. Több editor a TAB-ot szóközökre cseréli!
    • Ha nem tölt fel ilyet, és a program a standard inputról próbál olvasni, akkor azonnal fájl végét fog kapni. Ha ezt nem kezeli, és újból olvas (tipikus hiba), akkor végtelen ciklusba kerül a program.
    • Mivel ilyenkor nem a terminálkezelőnek írjuk be az inputot, hanem közvetlenül a futó programnak, a beírt karakterek nem íródnak vissza (nincs echo). Érdemes feltételes fordítással betenni a programba, hogy a Jportan-n futva írja vissza a beolvasott szöveget.
    • Az eredményt a standard kimenetre, vagy a standard hibakimenetre kell írni, melynek tartalma megjelenítésre kerül a portálon, de ennek a nagysága limitált.
  3. A rendelkezésre álló erőforrások limitáltak
    • Limitált a használható memória mérete, és nincs megengedve minden rendszerhívás. Így pl. új processz sem indítható. A normál feladatokat ez a limitáció többnyire nem érinti. Ezzel kapcsolatban érdemes tudni, hogy system hívás új processzt indít. Azaz a system(clear) utasítás sem megengedett, ami amúgy is meglehetősen ágyúval verébre történet, ugyanis azért indít valaki új processzt, hogy letörölje a képernyőt? A memtrace.h a sysetem hívást ignorálja, de ehhez include-olni kell!
    • Limitált a futási idő is.

Tipikus hibák

  • Hiba Zip fájl feltöltésekor:
    The following files are not valid ZIP archives, or compression is unknown ... hibajelzés sérült zip fájlra utal, vagy a feltöltött Zip file olyan tömörítő algoritmust használ (pl. deflate64), amit a Jporta nem tud kitömöríteni. Használjon más algoritmust (pl. deflate) a deflate64 helyett.
  • Fordítási (linkelési) hiba:
    /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
    (.text+0x20): undefined reference to `main'
    collect2: error: ld returned 1 exit status
    make: *** [runnable] Error 1
    :
    A feltöltött zip nem tartalmaz olyan forrást, amiben main függvény található. Tipikus jele annak, hogy alkönyvtárba tették a forrásokat
  • Figyelmeztető üzenetből fordítási hiba:
    cc1plus: all warnings being treated as errors: A feladatkiírás szerint warning sem lehet a beadott kódban. Meg kell szüntetni a figyelmeztető üzeneteket.
  • Visszatérési érték: 120: Memóriakezelési hiba van a programban! Ha a jelenség a saját környezetben nem jön elő, akkor a következőkre kell gondolni:
    1. Valamiért (pl. CRLF probléma, file vége kezelés miatt) olyan ágra fut a program amin tényleg van hiba
    2. memtrace.h A lokális környezetben nincs használva, vagy rossz helyen van include-olva
    3. Inicializálatlan változó más környezetben más hatással van
  • Visszatérési érték: -9 The program was killed because it was running too long.::
    A program végtelen ciklusba került. A fő beolvasó ciklus nem vizsgálja az EOF lehetőségét a standard inputról. Érdemes kipróbálni a programunkat, hogy hogyan reagál indulás után egy ctrl-Z-re!
  • Visszatérési érték: -11:
    A program olyan memóriaterülethez próbált hozzáférni, ami nem elérhető a program számára. Rosszul használt pointer vagy NULL pointer okozhat ilyet.
  • Bármilyen visszatérési érték, üres kimenet:
    A program elszállt. Lehet, hogy írt ki valamit, de az az output stream pufferében maradt. Célszerű a pufferelést (ld. lentebb) kikapcsolni, és debug kiírásokkal behatárolni a hiba helyét.
  • Visszatérési érték: -31: Többnyire arra utal, hogy a kód olyan rendszerhívást használt, amit biztonsági okokból nem enged a Jporta. Ilyen pl. a system(), közvetlen device (/dev/tty) megnyitása.
    Jelenleg a fájl törlés sem megengedett (int std::remove( const char* fname)).
  • The program produced too much output, ..... :
    Valószínű végtelen ciklusban ír a standard kimenetre a program. Tipikusan nem, vagy rosszul kezeli a fájl végét. Ha elfogy az a text fájl, amit a szabványos bemenetként töltött fel, akkor file végét kap a program minden további olvasásra.

Ötletek a hibakereséshez

  • Mindenképpen próbálja ki a saját környezetében, hogy programindítás után ctrl-Z -t (Linuxon ctrl-D -t) nyom! Ha program ettől végtelen ciklusba esik, akkor elsőként ezt szüntesse meg!
  • Ha a program a saját környezetben jól fut, akkor valamilyen olyan hibára kell gyanakodni, ami a két rendszer közötti eltérésből adódik. Ilyen pl. a szövegfájlok CRLF problémája. Ha a saját környezete MS Windows, akkor az ilyen jellegű hibát úgy érdemes megkeresni, hogy bináris fájlmegnyitást használunk a szövegfájlokra is. Ekkor ugyanis mind a CR (\r) mind az LF (\n) karaktert megkapja a program. A probléma megoldására egy architektúra független getline-t mutat a mintafeladat (NF kesz):
    namespace cp {	    //cross-platform getline
    
      std::istream& getline(std::istream& is, std::string& str) {
        std::getline(is, str);
        if (str.size() && *str.rbegin() == '\r')
            str.erase(str.size()-1);
        return is;
      }
    }                                     
    
  • Másik eltérés, hogy a Jporta 64 bites Intel architektúrán fut. Az CodeBlocks win7,8,10 környezetben is többnyire 32 bites kódot állít elő. Ez a változók méretét, értékkészletét is befolyásolja.
  • A hiba behatárolását nehezíti, hogy egy távoli rendszeren kell azt megkeresni debugger nélkül. Ilyenkor nem marad más, mint nyomkövető kiírásokat tenni a kódba (ld. később), vagy a távoli környezetet kell a lokális környezetben leképezni, szimulálni. Egy ilyen megoldás található a GIT tárolóban amivel a NHF saját Linux környezetben ellenőrizhető úgy, ahogy a Jporta is ellenőrzi. A környezet a korábban megismert CIRCLE felhő rendszerben a következő lépésekkel állítható elő:
    • Nyissa meg a cloud.bme.hu oldalt! Itt válassza a KIFU-NIIF nevű adatközpontot, majd lépjen be a rendszerbe EduID-azonosítójával (az eduID ikonra kattintson)! Indítson el egy virtuális gépet a "C++ labor" sablonnal, és lépjen be a gépre! Az indítás részleteit itt találja (1–6. feladatok).
    • Lépjen be (ssh, putty)
    • Töltse le a NHF-hez kialakított pédarpojektet!
        git clone https://git.ik.bme.hu/Prog2/ell_feladat/NHF.git 
        # navigáljon a Test katalógusba
        cd NHF/Test
        # Másolja be (scp, WinSCP) ebbe a katalógusba a feladathoz beadandó fájljait 
        # (src.zip, adatok.zip, input.txt)! (Ne használjon szóközt, ékezetet a fájlnevekben!)
        # csomagolja ki a zip-eket:
        make unpack
        # fordítsa le programot:
        make CHK=MEMTRACE
        # vagy address sanitizereel:
        make 
        # futtasson interaktívan:
        ./exe
        # futtasson az input átirányításával:
        ./exe < input.txt
        # ha nem tölt fel input állományt, akkor az ennek a parancsnak felel meg:
        ./exe <  /dev/null
      
  • Nyomkövető kiírások: Fontos tudni, hogy legtöbb futtató környezet az I/O gyorsítása érdekében mind a kimentet, mind a bemenetet puffereli. A puffer normál körülmények között automatikusan ürül pl. input esetén, illetve a program megállásakor is. Abban az esetben viszont, amikor a program abnormálisan áll le ez, nem történik meg. A hibás programok rossz szokása, hogy gyakran abnormálisan állnak le. Lehet, hogy kiírtunk egy üzenetet, de az még a pufferben van amikor a program elszáll. Mit lehet tenni?
    • Minden kiírás után erőszakkal üríteni kell a puffert pl. így:
      #ifdef CPORTA
       std::cout << "ez egy fontos kiiras" << std::endl << std::flush;  // flush mint, manipulátor
       std::cout << "ez meg fontosabb";
       std::cout.flush()                                                // flush(), mint tagfüggvény
      #endif                                           
      
    • Másik lehetőség a pufferelés kikapcsolása pl. így:
      ...
      #include <cstdio>
      ...
      int main() {
          setbuf(stdout, 0);     // kikapcsolja a pufferelést, ahogyan a hftest-ben is
      

      A pufferelés kikapcsolását segíti a memtrace.h fejlécállomány: Ha a CPORTA makró definiálva van, de nincs definiálva a CPORTA_NOSETBUF makró, akkor a program indulásakor kikapcsolódik a pufferelés. Ehhez természetesen include-olni kell a memtrace.h fejlécállományt.

    • Az ilyen kiírásokat érdemes feltételes fordításba tenni. Így egy mozdulattal kiszedhetők, vagy éppen visszarakhatók.
      Bármelyik megoldást is választjuk, érdemes makróval vagy sablonnal segíteni a munkát segédeszközként. Pl:
      template <typename M>
      void debugMSG(std::ostream& os, M msg) {
      #ifdef DEBUG
          os << msg << std::flush;
      #endif // DEBUG
      ....
      // használat
      debugMSG(std::cout, "haho");
      
Utolsó frissítés: 2021-04-16 16.08