lukaskollmer / objc

🔮 NodeJS ↔ Objective-C bridge (experimental)
MIT License
98 stars 20 forks source link

Importing values from IOKit lib exceeds maximum call stack #33

Closed kernel-dev closed 2 years ago

kernel-dev commented 2 years ago

After importing IOKit using objc.import("IOKit"), it throws an error when attempting to access a function that would otherwise be a part of the library. For example, IOServiceMatching;

const objc = require("objc");

objc.import("IOKit");

const { IOServiceMatching } = objc; // => Err

Error stack:

node:buffer:448
function fromArrayBuffer(obj, byteOffset, length) {
                        ^

RangeError: Maximum call stack size exceeded
    at fromArrayBuffer (node:buffer:448:25)
    at from (node:buffer:301:14)
    at Object.readPointer (<anonymous>)
    at Object.get (/Users/***/Documents/sysinfo-ts/node_modules/ref-napi/lib/ref.js:461:31)
    at Object.deref (/Users/***/Documents/sysinfo-ts/node_modules/ref-napi/lib/ref.js:665:18)
    at Buffer.deref (/Users/***/Documents/sysinfo-ts/node_modules/ref-napi/lib/ref.js:1269:18)
    at proxy (/Users/***/Documents/sysinfo-ts/node_modules/ffi-napi/lib/_foreign_function.js:64:19)
    at new Selector (/Users/***/Documents/sysinfo-ts/node_modules/objc/src/selector.js:49:20)
    at Instance.call (/Users/***/Documents/sysinfo-ts/node_modules/objc/src/instance.js:39:18)
    at Instance.description (/Users/***/Documents/sysinfo-ts/node_modules/objc/src/instance.js:138:17)

Additional information:

I'm not sure if I'm just doing something incorrectly, or if it's not meant to do this.


UPDATE:

This will also fail, but with a different error:

const objc = require("objc");

objc.import("IOKit");

const { IOServiceMatching } = objc; // => Err

Stack:

/Users/***/Documents/sysinfo-ts/node_modules/objc/src/instance.js:54
      throw new Error(`Unable to find method ${selector.name} on object ${this.description()}`);
      ^

Error: Unable to find method UTF8String on object -2.39651e+16
    at Instance.call (/Users/***/Documents/sysinfo-ts/node_modules/objc/src/instance.js:54:13)
    at Object.apply (/Users/***/Documents/sysinfo-ts/node_modules/objc/src/proxies.js:27:19)
    at Object.get (/Users/***/Documents/sysinfo-ts/node_modules/objc/src/index.js:43:55)
    at Object.<anonymous> (/Users/***/Documents/sysinfo-ts/dist/index.js:4:9)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
    at node:internal/main/run_main_module:17:47
lukaskollmer commented 2 years ago

Had a look at this, two things:

  1. The call stack issue does indeed seem to be an error in this package, I'll fix that.
  2. I don't think IOKit will work with this at all, since it isn't an Objective-C framework but rather a C library. (Same reason why e.g. CoreFoundation wouldn't really work either...). You'll probably need to directly use the ffi module to interface w/ IOKit (the same way this package currently uses the ffi to interface w/ the objc runtime).
kernel-dev commented 2 years ago

Thank you a lot for the quick response. Apologies for the misleading issue, though, I had originally thought you could bundle it in Obj-C? I remember using it.

Otherwise, thank you. It's immensely appreciated :+1:

kernel-dev commented 2 years ago

An update:

I notice that you are importing frameworks with this format:

Meaning, IOKit should technically be applicable to this rule? It's supposedly an Obj-C framework, as far as I've been told.

It can also be found under /System/Library/Frameworks: image

It imports the framework just fine, but it can't import values from it properly.

lukaskollmer commented 2 years ago

A .framework can contain Objective-C and/or C code. In the case of IOKit, I'd be surprised if it contains any Objective-C code, tbh.

The symbol you tried to access above, IOServiceMatching, is itself defined as a C function, meaning that, even if IOKit were to contain ObjC code, this package wouldn't be able to access this function.

This package currently only supports accessing Objective-C symbols (primarily classes). You should be able to use the ffi-napi and ref-napi packages to interact with IOKit, though. You can have a look at the runtime.js file to see an example of how this would work. Essentially, you just have to define the signature of the function you want to access, bring in the library from somewhere (this might be the most difficult part, they moved a bunch of frameworks into the shared dyld cache in Big Sur...), and then can call it almost as if it were a "normal" function.

kernel-dev commented 2 years ago

I see!

Thank you for the elaboration, it means a lot :+1:

I'll likely create an IOKit wrapper as a Node lib and share it so that it's more accessible for anyone who wishes to use it 👍

kernel-dev commented 2 years ago

Sorry to contact you over this, but is it possible that I'd be allowed to contact you over Twitter? I've got some questions I'd like to ask regarding my implementations for IOKit that I'm not sure how to resolve; if you have any free time, and are willing to spare your free time to do so.

Thank you in advance.

lukaskollmer commented 2 years ago

Sure