Constructing an object crashes jvm

Constructing an object crashes the jvm because the constructor is not found. The signature is correct and the constructor exists.
This is my new object code:

JavaObject(jclass klass, const char *signature, ...) {
    std::cout << "constructing" << std::endl;
    va_list arg;
    va_start(arg, signature);
        
    jmethodID constructor = client->env->GetMethodID(klass, "<init>", signature);
    jobject newObject = client->env->NewObjectV(klass, constructor, arg);
    this->object = &newObject;
    va_end(arg);
}

And then:

// javaClass->getClass() is java.lang.String
String(jcharArray v1) : JavaObject(javaClass->getClass(), "([C)V", v1) {}

edit: my class is java.lang.String. It has the constructor String(char[]). Running javap -s gives me the signature.

>Solution :

You can never directly access the va_list value. You must call va_arg on it to get the arguments. va_list does not contain the first argument; it contains an unspecified type which can access the first argument by means of va_arg.

jobject newObject = client->env->NewObjectV(klass, constructor, va_arg(arg, ExpectedType));

But this is all academic, because we’re in C++ in 2023, not C in 1991. There’s no compelling reason to use va_list at all anymore; it’s just a less type-safe version of variadic parameter packs. Your signature should look something like

template <typename... Ts>
JavaObject(jclass klass, const char *signature, const Ts&... args)

To use args (which is now type-safe), you can expand it in another argument list as

client->env->NewObjectV(klass, constructor, args...);

You can use it in a std::tuple or other type that expects parameter packs, to perform runtime operations on the pack as a single data structure.

auto my_args = std::make_tuple(args...);

You can’t invoke undefined behavior by using parameter packs with the wrong types, as you’ll just get a compiler error rather than the runtime just dying in exciting ways.

Leave a Reply