datetimepicker
datetimepicker copied to clipboard
Fixed issue with hermes and prototype.toString
I was running into issues when rendering the datetimepicker on Android in release mode only (dev worked fine). Opening the Picker crashed my app (stacktrace attached).
Looking through the trace, i narrowed it down to an issue with the line if (Object.prototype.toString.call(value) === '[object Date]') {
in toMilliseconds
in utils.js
.
Wondering why this might be an issue and knowing that "release mode only" bugs are often related to hermes, I found that using Function.prototype.toString
is not supported when using hermes (Source: https://hermesengine.dev/docs/language-features/#miscellaneous-incompatibilities).
I therefore changed the way dates are detected. It works for me now.
09-20 15:22:20.248 8181 8236 E ReactNativeJS: TypeError: Object is not a function, js engine: hermes
09-20 15:22:20.265 8181 8237 E AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
09-20 15:22:20.265 8181 8237 E AndroidRuntime: Process: my.app.opsec, PID: 8181
09-20 15:22:20.265 8181 8237 E AndroidRuntime: com.facebook.react.common.JavascriptException: TypeError: Object is not a function, js engine: hermes, stack:
09-20 15:22:20.265 8181 8237 E AndroidRuntime: toString@1:761211
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:757790
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:761297
09-20 15:22:20.265 8181 8237 E AndroidRuntime: loadModuleImplementation@1:37666
09-20 15:22:20.265 8181 8237 E AndroidRuntime: guardedLoadModule@1:37172
09-20 15:22:20.265 8181 8237 E AndroidRuntime: metroRequire@1:36843
09-20 15:22:20.265 8181 8237 E AndroidRuntime: toString@1:761203
09-20 15:22:20.265 8181 8237 E AndroidRuntime: each@1:901982
09-20 15:22:20.265 8181 8237 E AndroidRuntime: toMilliseconds@1:901938
09-20 15:22:20.265 8181 8237 E AndroidRuntime: ?anon_0_@1:901455
09-20 15:22:20.265 8181 8237 E AndroidRuntime: asyncGeneratorStep@1:564346
09-20 15:22:20.265 8181 8237 E AndroidRuntime: _next@1:564616
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:564568
09-20 15:22:20.265 8181 8237 E AndroidRuntime: tryCallTwo@61:8
09-20 15:22:20.265 8181 8237 E AndroidRuntime: doResolve@216:24
09-20 15:22:20.265 8181 8237 E AndroidRuntime: Promise@82:13
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:564489
09-20 15:22:20.265 8181 8237 E AndroidRuntime: open@1:901380
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:903830
09-20 15:22:20.265 8181 8237 E AndroidRuntime: ?anon_0_@1:900212
09-20 15:22:20.265 8181 8237 E AndroidRuntime: asyncGeneratorStep@1:564346
09-20 15:22:20.265 8181 8237 E AndroidRuntime: _next@1:564616
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:564568
09-20 15:22:20.265 8181 8237 E AndroidRuntime: tryCallTwo@61:8
09-20 15:22:20.265 8181 8237 E AndroidRuntime: doResolve@216:24
09-20 15:22:20.265 8181 8237 E AndroidRuntime: Promise@82:13
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:564489
09-20 15:22:20.265 8181 8237 E AndroidRuntime: presentPicker@1:900697
09-20 15:22:20.265 8181 8237 E AndroidRuntime: open@1:899675
09-20 15:22:20.265 8181 8237 E AndroidRuntime: showOrUpdatePicker@1:905348
09-20 15:22:20.265 8181 8237 E AndroidRuntime: commitHookEffectListMount@1:296884
09-20 15:22:20.265 8181 8237 E AndroidRuntime: flushPassiveEffects@1:310457
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:309580
09-20 15:22:20.265 8181 8237 E AndroidRuntime: J@1:251141
09-20 15:22:20.265 8181 8237 E AndroidRuntime: R@1:251472
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:154377
09-20 15:22:20.265 8181 8237 E AndroidRuntime: _callTimer@1:153326
09-20 15:22:20.265 8181 8237 E AndroidRuntime: _callReactNativeMicrotasksPass@1:153490
09-20 15:22:20.265 8181 8237 E AndroidRuntime: callReactNativeMicrotasks@1:155457
09-20 15:22:20.265 8181 8237 E AndroidRuntime: __callReactNativeMicrotasks@1:57794
09-20 15:22:20.265 8181 8237 E AndroidRuntime: anonymous@1:56887
09-20 15:22:20.265 8181 8237 E AndroidRuntime: __guard@1:57635
09-20 15:22:20.265 8181 8237 E AndroidRuntime: flushedQueue@1:56798
09-20 15:22:20.265 8181 8237 E AndroidRuntime: callFunctionReturnFlushedQueue@1:56654
09-20 15:22:20.265 8181 8237 E AndroidRuntime:
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at com.facebook.react.modules.core.ExceptionsManagerModule.reportException(ExceptionsManagerModule.java:72)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at com.facebook.jni.NativeRunnable.run(Native Method)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:942)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
09-20 15:22:20.265 8181 8237 E AndroidRuntime: at java.lang.Thread.run(Thread.java:1012)
hello and thanks for the PR! Do you have a repro for your crash? (https://stackoverflow.com/help/minimal-reproducible-example)
The code we have there is a little odd, so this change probably makes sense... But there's a PR which I think is changing it and I'd like to get that one in first.
On another note, I'm not sure the explanation you gave is correct, I think for some reason, in your code, Object.prototype.toString
is an Object, instead of it being a function, or some weird value
was passed into that code... We're not really inspecting the source code of a function as described in the hermes docs.
You're right, my fix doesn't directly address the error message. It still fixes the crash in my specific case.
I don't have the time to provide you with a minimal reproducible example, sorry. I tried reproducing the error inside the hermes playground (https://hermesengine.dev/playground/) but it seems to be working there.
Here's what I tried:
// trying to reproduce the following message:
// TypeError: Object is not a function, js engine: hermes, stack:
// simple test
const value = new Date();
print(Object.prototype.toString.call(value));
// copying additional behavior from datetimepicker
const options = {
a: new Date(),
b: null,
c: undefined,
};
const keys = [ 'a', 'b', 'c', 'd' ];
keys.forEach(function each(key) {
const value = options[key];
// if (value instanceof Date) {
if (Object.prototype.toString.call(value) === '[object Date]') {
print('found date');
}
});
The PR you linked made exactly the same change I did, so feel free to close my PR.