tondrej / chakracore-delphi

Delphi and Free Pascal bindings and classes for Microsoft's ChakraCore library
https://tondrej.blogspot.com/search/label/chakracore
MIT License
137 stars 34 forks source link

EAccessViolation using Variants branch #17

Closed danielrippa closed 3 years ago

danielrippa commented 3 years ago

First, I'd like to thank you for such a great work.

Regarding the EAccessViolation:

I'm compiling using barebones freepascal on Windows: Free Pascal Compiler version 3.2.0 [2020/06/04] for i386

Windows 10 Pro 20H2 Build 19042.685

Using code from the gist from in your October post (https://tondrej.blogspot.com/2020/10/variant-support-in-chakracore-delphi.html)

I have added a writeln at the end:

  ...
  finally
    VarClear(MyObj);
    VarClear(Json);
    Context.Free;
    Runtime.Free;
  end;
  WriteLn('After freeing.');
end.

Code runs ok:

Hello, world!
{"name":"world"}
After freeing.

But throws exceptions afterwards:

An unhandled exception occurred at $732ECF2F:
EAccessViolation: Access violation
  $732ECF2F
  $00440BF6
  $0041DF78
  $00415DF6
  $00412833

An unhandled exception occurred at $732ECF2F:
EAccessViolation: Access violation
  $732ECF2F
  $00440BF6
  $0041DF78
  $00415DF6
  $00412833
  $0040D959
  $76F771E2
  $76F771B4
  $76F63B36
  $00440BF6
  $0041DF78
  $00415DF6
  $00412833
danielrippa commented 3 years ago

WmiSample works fine without exceptions.

tondrej commented 3 years ago

Thanks for the report. I can reproduce the problem. The reason is temporary variant arrays created by invoking methods on javascript value variants. I'll try to fix it.

In the meantime, the workaround is to make sure all your variant using code gets out of scope before freeing the context and the runtime. For example:

procedure Test(Context: TChakraCoreContext);
var
  Global, Json, MyObj: Variant;
begin
  // assign javascript Global to a Variant
  Global := JsValueToVariant(Context.Global);

  // read its (JSON) property and assign it to another Variant
  Json := Global.JSON;

  // call its method, assign result to another Variant
  MyObj := Json.parse('{ "name": "world" }');

  // access property
  Writeln(Format('Hello, %s!', [MyObj.name]));

  // call another method
  Writeln(Json.stringify(MyObj));
end;

procedure Main;
var
  Runtime: TChakraCoreRuntime;
  Context: TChakraCoreContext;
begin
  Runtime := nil;
  Context := nil;
  try
    Runtime := TChakraCoreRuntime.Create;
    Context := TChakraCoreContext.Create(Runtime);
    Context.Activate;

    Test(Context);
  finally
    Context.Free;
    Runtime.Free;
  end;
  Writeln('after freeing');
end;
tondrej commented 3 years ago

I've updated the gist, too.

danielrippa commented 3 years ago

Wow. That was fast! I confirm the workaround works fine.

Thanks!