Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In Quickjs what is proper way to capture a string in a struct #154

Closed
anuragvohraec opened this issue Jan 8, 2023 · 1 comment
Closed

Comments

@anuragvohraec
Copy link

Hi,

I have following JS Code which i need to run in my quickjs app.

let e = new Event('test1');
print(e.type);

For this I have written a bare minimal example code to test this using quickjs core API.

  1. I have defined EventState to hold Event state.
  2. js_print to implement print method
  3. And then using Event_constructor and get_type_Event to implement Event class.
#include <quickjs/quickjs.h>
#include <iostream>

JSClassID newClassId=0;

struct EventState{
    std::string type;
};

static JSValue js_print(JSContext *ctx, JSValueConst this_val,
                        int argc, JSValueConst *argv)
{
    auto str = JS_ToCString(ctx, argv[0]);
    std::cout << "msg: "<<str << std::endl;
    JS_FreeCString(ctx, str);
    return JS_UNDEFINED;
}

static JSValue Event_constructor(JSContext *ctx, JSValueConst new_target,int argc, JSValueConst *argv){
    JSValue prototype;
    JSValue result=JS_UNDEFINED;
    auto id = newClassId;
    
    prototype = JS_GetPropertyStr(ctx,new_target,"prototype");

    if(JS_IsException(result)){
        return JS_EXCEPTION;
    }

    if(argc==0 || !JS_IsString(argv[0])){
        return JS_ThrowTypeError(ctx, "%s","Invalid event type");
    }
    
    result= JS_NewObjectProtoClass(ctx,prototype,id);
    JS_FreeValue(ctx, prototype);
    
    //set opaque if internal state needs to be maintained
    auto eventState = (EventState*)js_mallocz(ctx, sizeof(EventState));
    auto t = JS_ToCString(ctx, argv[0]);
    eventState->type.assign(t);
    JS_FreeCString(ctx, t);
    JS_SetOpaque(result, eventState);

    return result;
}

static JSValue set_readonly(JSContext *ctx, JSValueConst this_val, JSValue val,int magic){
    return JS_UNDEFINED;
}
static JSValue get_type_Event(JSContext *ctx, JSValueConst this_val,int magic){
    auto eventState = (EventState*)JS_GetOpaque(this_val, newClassId);
    return JS_NewString(ctx, &eventState->type[0]);
}

JSCFunctionListEntry Event_instanceMethods[1]={
    JS_CGETSET_MAGIC_DEF("type", get_type_Event, set_readonly,0),
};

void registerEventClass(JSContext *ctx){
    JSClassID id=0;
    newClassId = JS_NewClassID(&id);
    auto rt = JS_GetRuntime(ctx);
    char* className ="Event";

    JSClassDef  classDef;
    classDef.class_name=className;
    classDef.finalizer=[](JSRuntime* rt, JSValue val){
        auto s  = (EventState*)JS_GetOpaque(val, newClassId);
        if(s!=NULL){
            js_free_rt(rt, s);
        }
    };
    classDef.gc_mark=NULL;
    classDef.exotic=NULL;
    classDef.call=NULL;

    JS_NewClass(rt,newClassId,&classDef);
    
    JSValue prototype =JS_NewObject(ctx);
    //adding instance methods
    JS_SetPropertyFunctionList(ctx,prototype,Event_instanceMethods,1);

    auto new_class = JS_NewCFunction2(ctx,Event_constructor,className,1,JS_CFUNC_constructor,0);
    auto global_obj=JS_GetGlobalObject(ctx);
    JS_DefinePropertyValueStr(ctx, global_obj, className,
                        JS_DupValue(ctx, new_class),
                        JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
    JS_SetConstructor(ctx, new_class, prototype);
    JS_SetClassProto(ctx,newClassId,prototype);

    JS_FreeValue(ctx, new_class);
    JS_FreeValue(ctx,global_obj);

}

int main(){
        JSRuntime *rt;
        JSContext *ctx;
        JSValue evalVal;

        rt = JS_NewRuntime();
        ctx = JS_NewContext(rt);
        
        registerEventClass(ctx);

        auto global_object = JS_GetGlobalObject(ctx);
        auto printF = JS_NewCFunction(ctx, js_print, "print", 1);
        JS_SetPropertyStr(ctx, global_object, "print", printF);
		
        evalVal = JS_Eval(ctx, "let e = new Event('test1');\nprint(e.type);", 42, "<input>", 0);
        
        JS_FreeValue(ctx,global_object);
        JS_FreeValue(ctx, evalVal);
        
        JS_FreeContext(ctx);
        JS_FreeRuntime(rt);
        return 0;
}

But running this code gives me valgrind error :6 bytes in 1 blocks are definitely lost in loss record 1 of 1.
How to properly assign a string to struct and then deallocate it.

@anuragvohraec
Copy link
Author

anuragvohraec commented Feb 20, 2023

The proper way to solve this issue is at : StackOverFlow answer

GerHobbelt pushed a commit to GerHobbelt/quickjs that referenced this issue Jun 21, 2024
…ports (bellard#154)

* QTS_Eval now returns module exports if possible

* fix c bugs

* regen ffi & adapt new Eval call convention

* update evalCode docs

* docs

* resolve modules, sync unwrap promises

* fix type error

* doc

* fix quickjs-ng sync module exports

* remove .only

* disable ffi check when no tests ran

* stop asserting randomly about module evals

* allow context.unwrapResult(context.getPromiseState(x))

* doc promise state

* document vm.getPromiseState

* more doc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant