Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C++][Java][JNI] Access Violation Exception

Pagina: 1
Acties:

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33
Ik denk dat ik iets fout doe met mijn geheugen allocatie en/of memory access.
Ik kom er niet meer uit, ik denk dat ik iets niet goed doe met mijn pointers of mijn malloc calls.

Ik heb heb al een paar uur lopen debuggen op dit probleem, maar ik snap niet waarom het niet werkt.

Dit is mijn simpele test programma met JNI:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
bool getArrayOfArrays(JNIEnv *env, jobjectArray* arrays, jbyteArray** arrayOfArrays, jbyte*** data, int numArrays)
{
    printf("Allocating arrayOfArrays\n");
    arrayOfArrays = (jbyteArray**)malloc(sizeof(jbyteArray*) * numArrays);
    *arrayOfArrays = (jbyteArray*)malloc(sizeof(jbyteArray) * numArrays);
    printf("Allocating *data\n");
    *data = (jbyte**)malloc(sizeof(jbyte**) * numArrays);
    printf("Allocating **data\n");
    **data = (jbyte*)malloc(sizeof(jbyte*) * numArrays);

    printf("*array = %d\n", *arrays);
    printf("*arrayOfArrays = %d\n", *arrayOfArrays);
    printf("*data = %d\n", *data);

    printf("accessing data\n");
    *data[0] = env->GetByteArrayElements((jbyteArray)env->GetObjectArrayElement(*arrays, 0), NULL);
    printf("accessing data[1]\n");
    *data[1] = NULL; // HIER is de crash.

    printf("returning\n");

    return true;
}

JNIEXPORT void JNICALL Java_Application_test
    (JNIEnv *env, jclass clazz, jobjectArray array) {
        jbyteArray* arrayOfArrays = NULL;
        jbyte** data = NULL;

        printf("array = %d\n", array);
        printf("arrayOfArrays = %d\n", arrayOfArrays);
        printf("data = %d\n",data);

        getArrayOfArrays(env, &array, &arrayOfArrays, &data, 2); //numArrays = 2

        printf("array = %d\n", array);
        printf("arrayOfArrays = %d\n", arrayOfArrays);
        printf("data = %d\n",data);
}


Java:
1
2
3
4
5
6
7
8
9
10
11
12
public class Application {
    static {
        System.loadLibrary("Test");
    }
    public static native void test(byte[][] test);

    public static void main(String[] args)
    {
        test(new byte[2][2048]);
    }

}


De foutmelding is:
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000007fd3ff13ad1, pid=10036, tid=2892
en de output voordat ie crasht is:
code:
1
2
3
4
5
6
7
8
9
10
11
array = 42332584
arrayOfArrays = 0
data = 0
Allocating arrayOfArrays
Allocating *data
Allocating **data
*array = 42332584
*arrayOfArrays = 12404624
*data = 12405824
accessing data
accessing data[1]


Zoals je kan zie gaat de malloc call goed (geen NULL als result), maar crasht ie zodra ik een (volgens mij) goede waarde probeer te accessen (namelijk data[1]).

Mijn doel is om de data en arrayOfArrays te vullen in de getArrays methode zodat ze toegankelijk zijn in de JNI test methode.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Voor een NxM array verwacht ik 1 keer een outer array allocatie van N groot, en vervolgens N keer een inner array allocatie van M groot. Jij denkt volgens mij dat je gewoon maar 1 keer een array van M groot hoeft te maken, maar daarmee heb je feitelijk slechts 1 rij van de 2d array gevuld.

Maar even los van dit fundamentele probleem heb ik niet heel echt het idee dat je ook maar enigszins een idee hebt van wat je aan het doen bent. Waarom zit je code überhaupt arrays te alloceren, als je Java code een al gealloceerde array aanlevert?

[ Voor 30% gewijzigd door .oisyn op 03-03-2013 03:59 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33
Ik heb ruimte nodig om de references naar de Java arrays op te slaan. Ik alloceer dus inderdaad alleen de N dimensie van de array en haal vervolgens de M dimensie als pointers naar de Java arrays.

Ik krijg vanuit java een jobjectArray welke dus N jbyteArrays bevat, de references naar de jbyteArrays sla ik op en ik haal vervolgens de (pointer naar de) elementen op.

Ik snap dat het lijkt alsof ik geen idee heb wat ik doe, vooral in dit stuk code probeer ik maar wat.

In principe snap ik niet waarom een call van malloc() voor 2x een jbyteArray pointer lukt, maar dat vervolgens een poging om het 2e element te accessen zorgt voor een access violation.

~edit:

Ik heb het probleem opgelost door ipv mijn C stijl malloc madness een std::vector te gebruiken en dan een pointer daar heen mee te geven aan mijn functie. :)

Mijn C++ license mag je intrekken hoor .oisyn ;)

[ Voor 42% gewijzigd door HMS op 03-03-2013 14:45 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Even voor de goede orde:
Java:
1
2
3
4
5
6
7
8
byte[][] a = new byte[2][2048];

// is hetzelfde als

byte[][] a;
a = new byte[][2];
for (int i = 0; i < 2; i++)
    a[i] = new byte[2048];

Zo'n zelfde lus mis ik in je C code. Op regel 7 alloceer je een array van numArrays aan pointer-naar-pointers. Op regel 9 alloceer je vervolgens numArray pointers, en die sla je op in het eerste element van de array die je op regel 7 gealloceerd hebt. De rest van de arrays van de elementen in de array blijven dus leeg.

[ Voor 37% gewijzigd door .oisyn op 03-03-2013 22:38 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33
Dat klopt. Die had ik in dit voorbeeld weg gelaten, misschien niet heel verstandig.

Wat ik wou doen was het volgende:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Java
byte[][] myArray = new byte[2][2048];
native_call(myArray);

// C
void native_call(JNIEnv *env, jclass clazz, jobjectArray myArray) {
    jbyteArray* byteArraysInMyArray = NULL;
    jbyte** dataInMyArray = NULL;

    getFromJava(env, &myArray, &byteArraysInMyArray, &dataInMyArray);

    // Doe iets met data
    // En doe cleanup(env, &byteArraysInMyArray, &dataInMyArray);
}

void getFromJava(JNIEnv *env, jobjectArray *myArray, jbyteArray* *byteArrays, jbyte** *data) {
    // Neem aan hardcoded aantal arrays 2.
    *byteArrays = malloc(sizeof(jbyteArray*) * 2);
    for(int i = 0; i < 2; ++i) {
        *byteArrays[i] = env->GetObjectArrayElement(*myArray, i);
    }

    *data = malloc(sizeof(data*) * 2);
    for(int i = 0; i < 2; ++i) {
        // Bij i = 1 zou hier een ACCESS_VIOLATION_EXCEPTION komen
        *data[i] = env->GetByteArrayElements(*byteArrays[i], NULL); 
    }
}

// Cleanup zou dan de references naar de data en arrays weer opruimen + free() om het geheugen terug te geven


edit: semi-pseudo ;)

En die code in de FP is inderdaad wel WTF waardig, ik snap ook niet wat ik denkende was 8)7.

Ik denk dat ik niet helemaal snap hoe de allocatie gaat.

Deze call:
C:
1
jbyteArray** arrays = malloc(sizeof(jbyteArray*) * 2);


Alloceert ruimte voor 2 pointers naar een jbyteArray op positie 0 van arrays?

[ Voor 12% gewijzigd door HMS op 04-03-2013 01:11 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23-11 03:08
Ja, maar je kunt ook de C++ operators new[]/delete[] (niet te verwarren met delete) gebruiken, zoals .oisyn suggereerde. (Tenzij de JNI/JVM specifieke eisen stelt aan hoe geheugen geälloceerd wordt, in verband met Java's garbage collection.)
Pagina: 1