Skip to content

Unexpected release of a managed pointer in wrapper.call #20095

@mike-lischke

Description

@mike-lischke

Please include the following in your bug report:

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.44-git
clang version 17.0.0 (https://github.com/llvm/llvm-project.git a8cbd27d1f238e104a5d5ca345d93bc1f4d4ab1f)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /opt/homebrew/Cellar/emscripten/3.1.44/libexec/llvm/bin

The Problem

In my C++ library there's a class that manages a list (vector) of std::unique_ptr and hence manages the life time of the objects (in this case instances of a Token class). When any of the tokens is needed the raw pointer is passed around, but of course must not be managed elsewhere.

One of the consumers of a token pointer is a listener class, which is bound with embind and its methods can be overriden in JS. The wrapper is defined as:

class ANTLRErrorListenerWrapper : public wrapper<ANTLRErrorListenerHelper> {
public:
  EMSCRIPTEN_WRAPPER(ANTLRErrorListenerWrapper);

  virtual ~ANTLRErrorListenerWrapper() noexcept override {
  }

  virtual void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, size_t charPositionInLine,
                           const std::string &msg, const RecognitionException &e) override {
    call<void>("syntaxError", recognizer, offendingSymbol, line, charPositionInLine, msg, e);
  }

This listener is overridden in JS:

import {
    ANTLRErrorListener as AEL
} from "../../src/antlr4-runtime.js";

const ANTLRErrorListener = AEL.extend<AEL>("AEL", {});
type ANTLRErrorListener = InstanceType<typeof ANTLRErrorListener>;

export class MySQLErrorListener extends ANTLRErrorListener {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    public syntaxError<T extends Token | number>(recognizer: Recognizer<any>, offendingSymbol: T | null,
        line: number, charPositionInLine: number, msg: string, e: RecognitionException | null): void {

    }

 
}

When the syntaxError method is called (from the wrapper code) it does everything nicely, but when it returns, the token value is deleted, even though it is managed by a unique_ptr. Is that a bug, a gotcha or an error on my side and how can I prevent the premature release?

Work Around

I just found a work around to avoid the premature release, by calling offendingSymbol.clone() in the syntaxError method body, though that looks a bit hackish to me...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions