[ kopca @ 21.08.2008. 08:59 ] @
Pozdrav svima,

Software mi ima managed (.NET, C#) deo i unmanaged (c++) deo.
U unmanaged delu pozivam strlen u sledecem kodu:

Code:

if ((*currSourcePageScope)->pageScope != NULL) 
{
      int pageScopeSize = strlen((*currSourcePageScope)->pageScope);
}


U vecini slucajeva strlen odradi posao dobro, ali kad opteretim software,
jednostavno pukne sa 'Access violation reading location...'
(*currSourcePageScope)->pageScope je konstantni string koji dobija vrednost u
managed (C#, .NET) delu i prosledjuje se preko struct-a u unmanaged deo.

Code:

//pageScope je C# struct i PageScope je string.
pageScope.PageScope = Marshal.StringToHGlobalAnsi(this.CurrentJob.RipDescription.PageScopeTransformations[i].PageScope);
---
//kasnije se za taj string poziva marshaling utility za pravljenje pointera (interop marshalling) ka unmanaged delu:
IntPtr ptrPageScope = Marshal.AllocHGlobal(Marshal.SizeOf(pageScope));
Marshal.StructureToPtr(pageScope,ptrPageScope,false);


Kao da taj (*currSourcePageScope)->pageScope nije null terminated char* pa se strlen zbuni.

Please, help. Hvala unapred :)
[ mmix @ 21.08.2008. 09:16 ] @
Nesto mi ovde ne deluje nastimano. Kako ti izgleda pageScope struktura?
[ kopca @ 21.08.2008. 09:57 ] @
Code:

public struct GmgPageScope
{

        private IntPtr _pageScope;

        ...

        /// <summary>
        /// Page scope string pointer.
        /// </summary>
        public IntPtr PageScope
        {
            get { return this._pageScope; }
            set { this._pageScope = value; }
        }

        ...

}


Nasao sam nesto u vezi strlen f-je:
https://buildsecurityin.us-cer...bsi-rules/home/g1/852-BSI.html

Sad probavam da izmenim kod u skladu sa gore pomenutim linkom, pa ako bude poboljsanja javljam.
Test mi traje malo duze.
[ kopca @ 21.08.2008. 10:58 ] @
Ne, ponudjeno resenje na linku ne valja.
Kad je (*currSourcePageScope)->pageScope razlicito od NULL, ipak moze da bude <BadPtr>
i onda ni strlen ni strncpy ne mogu da ga svare... Ne znam kako da validiram onda taj pointer.
Pomozite molim vas, ko zna nesto, ovo me vec baca u ocajanje.
[ mmix @ 21.08.2008. 13:28 ] @
BadPtr mozes da dobijes samo kao posledica unpinovanog pointera u GC heapu koji je promenio lokaciju (ili offchance ako si dealocirao string ili strukturu sa unmanaged heap-a pre vremena sto pretpostavljam da nisi uradio). Ti nemas u svom C# kodu problem sa pinovanjem u GC jer i StringToHGlobalAnsi i AllocHGlobal alociraju na unmanaged heapu i ptrPageScope je sasvim sigurno Ok kad ga saljes u unmanaged code, tako da problem mora biti tu.

Kako si deklarisao currSourcePageScope i kako izgleda deklaracija tog tipa u unmanaged delu?


(PS> Nadam se da po povratku iz unamanged dela pozivas Marshal.FreeHGlobal() za string i strukturu, bez toga imas memory leak, nevezano za temu)
[ kopca @ 22.08.2008. 16:19 ] @
Generalno se u unmanaged deo jednoj metodi prosledjuje pokazivac (alociran u managed delu) kao void*.
Taj void* se konvertuje u c++ tip sa klasicnom konverzijom i deo tog tipa je:
Code:

   //ovo je struct:
   public struct SGMGPageScope {...}
   ...
   //tip koji se dobije konverzijom sadrzi ovako nesto:
   SGMGPageScope** PageScope;
   ...
   //za iteraciju kroz PageScope se koristi sledeci kod (source je deo gorepomenutog void*):
   SGMGPageScope **currSourcePageScope = source;
   while ((*currSourcePageScope) != NULL) 
   {
         psCount++;
         currSourcePageScope++;
   }


[Ovu poruku je menjao kopca dana 22.08.2008. u 17:31 GMT+1]
[ kopca @ 22.08.2008. 16:34 ] @
U managed delu jos se i poziva GC.KeepAlive(...) za pinovani objekat posle poziva metode kojoj se pinovani objekat prosledjuje.
[ mmix @ 22.08.2008. 19:15 ] @
Koliko vidim ti u stvari prosledjujes pointer na null-terminated niz SGMGPageScope* pointera? Kako si to izveo u managed delu pre castovanja u void*? I offshot, da li si stavio null ponter kao zadnji element niza, ako nisi onda je to verovatno uzrok tvog bug-a, pre ili kasnije ce tu uleteti "lazni" pointer, koji ce naravno sadrzati BadPtr na string?

Drugo, sta pinujes? Koliko sam video do sada, poprilicno si se potrudio da ne koristis pointere na managed resurse u unmanaged kodu (sto je po meni overkill kad postoji pinovanje, ali neko to preferira ovako) samim tim ne vidim sta pinujes? I na sta pozivas GC.KeepAlive()? Ako je zbog stringova i struktura koje si kopirao sa *HGlobal metodama onda nemas potrebe da to radis jer si pravio kopije u unmanaged heap-u, totalno je nevazno da li je GC pocistio originale, kopije nece biti dirane dok ih ne dealociras sa FreeHGlobal(), GC ti to sasvim sigurno nece dirati.
[ kopca @ 25.08.2008. 10:09 ] @
Citat:
mmix: Koliko vidim ti u stvari prosledjujes pointer na null-terminated niz SGMGPageScope* pointera? Kako si to izveo u managed delu pre castovanja u void*?


Code:

        public delegate bool DoMonzaJob(IntPtr job);
        ....
        public bool DoJob(GmgJobDescription jobDescription)
        {
            bool retVal = false;
            IntPtr jobPtr; 
            DoMonzaJob monzaDoJobCall; 

            //Allocating.
            jobPtr = Marshal.AllocHGlobal(Marshal.SizeOf(jobDescription));

            //Getting pointer to structure.
            Marshal.StructureToPtr(jobDescription, jobPtr, false);

            //Getting procedure address and executing imported dll function.
            lock (this._serviceStartLock)  //this._serviceStartLock je object koji se instancira u konstruktoru, nije staticki objekat.
            {
                if (this._serviceStarted) 
                {
                    monzaDoJobCall = (DoMonzaJob)this._monzaLoader.GetProcedureAddress(GmgRipConstants.DoMonzaJob, typeof(DoMonzaJob));
                    retVal = (bool)monzaDoJobCall(jobPtr);
                }
            }
                       
            //Deallocating.
            Marshal.FreeHGlobal(jobPtr);

            return retVal;
        }


Citat:
mmix:I offshot, da li si stavio null ponter kao zadnji element niza, ako nisi onda je to verovatno uzrok tvog bug-a, pre ili kasnije ce tu uleteti "lazni" pointer, koji ce naravno sadrzati BadPtr na string?


U unmanaged delu uvek napravim niz tih pointera i na kraju dodam jos jedan null clan u taj niz bas iz razloga da dobijem null terminated array.

Citat:
mmix:Drugo, sta pinujes? Koliko sam video do sada, poprilicno si se potrudio da ne koristis pointere na managed resurse u unmanaged kodu (sto je po meni overkill kad postoji pinovanje, ali neko to preferira ovako) samim tim ne vidim sta pinujes? I na sta pozivas GC.KeepAlive()? Ako je zbog stringova i struktura koje si kopirao sa *HGlobal metodama onda nemas potrebe da to radis jer si pravio kopije u unmanaged heap-u, totalno je nevazno da li je GC pocistio originale, kopije nece biti dirane dok ih ne dealociras sa FreeHGlobal(), GC ti to sasvim sigurno nece dirati.


ovo je poziv gore pomenute DoMonzaJob(...) metode:

Code:


      if (this._serviceStarted) 
      {
           retVal = this._monzaWraper.DoJob(description);
      }
      ....                          
      GC.KeepAlive(description);



DoJob metoda je lock-ovana tako da se sinhronizuju pozivi u unmanaged delu da idu jedan po jedan i GC.KeepAlive je pozvan da cuva description od koje se pravi pinovani objekat.

Hvala jos jednom na pomoci i strpljenju :)
[ kopca @ 25.08.2008. 10:13 ] @
Interesantno je to da se program javlja kod 'heavy load-a', tj. kad opteretim software do krajnje mere, onda se javlja bad pointer, inace sa manjim obimom sve radi kako treba, dakle bug nije 100% reproducible :)