Search code examples
dockermacosdeno

Why does libxml2_xpath fails by Invalid FFI pointer type, expected null, or External


Using Denos libxml2_xpath in a Pipline Application fails even under docker

running

docker run  
\--interactive  \\ 
\--tty   \\ 
\--platform linux/amd64   
\--rm     
\--volume $PWD:/app    
\--volume $HOME/.deno:/deno-dir    
\--workdir /app     
deno deno run --allow-read --allow-ffi --unstable examples/parse-xcb.ts

fails by

error: Uncaught (in promise) TypeError: Invalid FFI pointer type, expected null, or External
this.#ptr = lib.symbols.xmlCreatePushParserCtxt(
^
at new PushParseCtxt (https://deno.land/x/libxml2_xpath@v0.0.3/mod.ts:89:29)
at parseDocument (https://deno.land/x/libxml2_xpath@v0.0.3/mod.ts:442:17)
at eventLoopTick (ext:core/01_core.js:183:11)
at async file:///app/examples/parse-xcb.ts:9:15

Dockefile on Macbook M1

FROM --platform=linux/amd64 denoland/deno:1.37.0

RUN DEBIAN_FRONTEND=noninteractive  \
apt-get update                      \
&& apt-get install -qy              \
libxml2-utils                       \
libxml2-dev                         \
libxml2

Solution

  • That third-party lib is outdated (https://deno.land/x/libxml2_xpath), it's using pointer type when it should be buffer since it's passing a Uint8Array

    https://docs.deno.com/runtime/manual/runtime/ffi_api#supported-types

    As of Deno 1.25, the pointer type has been split into a pointer and a buffer type to ensure users take advantage of optimizations for Typed Arrays, and as of Deno 1.31 the JavaScript representation of pointer has become an opaque pointer object or null for null pointers.

    Once you change the source from that lib from:

      "xmlCreatePushParserCtxt": {
        parameters: ["pointer", "pointer", "pointer", "usize", "pointer"],
        result: "pointer",
        nonblocking: false,
      },
    

    to:

     "xmlCreatePushParserCtxt": {
        parameters: ["pointer", "pointer", "buffer", "usize", "buffer"],
        result: "pointer",
        nonblocking: false,
      },
    

    You no longer encounter that error. However, other errors get triggered because the library is quite outdated. It uses the unstable FFI API, which requires that the project be kept up to date.


    If you then change the constructor to:

      constructor(chunk: Uint8Array) {
        this.#ptr = lib.symbols.xmlCreatePushParserCtxt(
          null,
          null,
          chunk,
          chunk.length,
          cstr("<mem>"),
        );
        if (typeof this.#ptr !== 'object') {
          throw new Error(`${this.#ptr}`);
        }
      }
    

    The lib no longer crashes when calling parseDocument(stream). But it crashes when using XPathContext(doc). It won't work until you replace all the outdated FFI types.

    You should find a new library or update that one completely.