NativeScript / NativeScript/android

Reading `SomeClass.null` permanently breaks that class's static `valueOf()`

Đang mở
#1,986 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Ngôn ngữ chính
C++
Star
563
Fork
144
Merge trung bình
10 giờ 46 phút
Pull request đã merge (30 ngày)
14

Mô tả

Summary

Reading the typed-null marker SomeJavaClass.null permanently breaks SomeJavaClass.valueOf(...) for the remaining life of the isolate — it silently starts returning null for every argument.

The .null getter deletes the class's Java static valueOf and replaces it with an internal shim that unconditionally returns null. Because the marker object is the constructor function itself, that shim lands directly on the class.

This is not specific to any one class; it hits any class that has both a static valueOf and gets a typed null taken from it. In practice java.lang.String.valueOf(...) is broken from app startup in most apps, because passing java.lang.String.null is the idiomatic way to disambiguate a null argument.

Reproduction

Any app, evaluated in the runtime (here via the inspector):

String(java.lang.Double.valueOf(1))   // "1.0"      <- correct
typeof java.lang.Double.null          // "function" <- touch the marker once
String(java.lang.Double.valueOf(1))   // "null"     <- now permanently broken
java.lang.Double.toString(1)          // "1.0"      <- other statics unaffected

The property is visibly deleted and re-added — valueOf moves from its metadata slot to the end of the key order:

Object.getOwnPropertyNames(java.lang.Double).indexOf("valueOf")  // 19 (of 35) before
Object.getOwnPropertyNames(java.lang.Double).indexOf("valueOf")  // 34 (of 35) after

java.lang.String shows the post-mutation shape from startup in any app that uses java.lang.String.null:

String(java.lang.String.valueOf(7))                 // "null"
Object.getOwnPropertyNames(java.lang.String)
// [... "copyValueOf", "format", "join", "extend", "CASE_INSENSITIVE_ORDER", "null", "class", "valueOf"]
//                                                                                          ^ moved to last
Expected vs actual
  • Expected: java.lang.String.valueOf(42)"42"; taking SomeClass.null has no effect on that class's static methods.
  • Actual: returns null, silently, forever after the first read of .null on that class.
Root cause

test-app/runtime/src/main/cpp/MetadataNode.cpp, NullObjectAccessorGetterCallback (the getter installed for .null):

auto thiz = info.This();          // the class constructor function itself
...
auto funcTemplate = FunctionTemplate::New(isolate, MetadataNode::NullValueOfCallback);
thiz->Delete(context, V8StringConstants::GetValueOf(isolate));
thiz->Set(context, V8StringConstants::GetValueOf(isolate),
          funcTemplate->GetFunction(context).ToLocalChecked());
...
info.GetReturnValue().Set(thiz);  // the marker IS the ctor function

and NullValueOfCallback is simply:

args.GetReturnValue().SetNull();

So the "make this object read as null" shim is installed on the class object rather than on a distinct marker object, and it overwrites a real Java static of the same name. The guard around it (hiddenVal.IsEmpty()) only makes it happen once — it does not make it reversible.

Suggested direction

Return a dedicated marker object from the .null getter instead of the constructor function itself — e.g. an empty object carrying the same MetadataNodeKeys internal fields plus the null-node private value, with valueOf installed on that. The argument-resolution path already identifies typed nulls via the NULL_NODE_NAME private value, so it should not need the marker to be the class object.

Failing that, at minimum the shim should not clobber a name that exists in the class's metadata.

Affected versions
  • Reproduced on @nativescript/android 9.0.x (V8 10.3.22), the currently published runtime.
  • Also reproduces unchanged on a local branch running V8 14.9.207.39, so it is independent of the V8 version — this is long-standing, not a recent regression.

Tested on an API 35 arm64 emulator.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với test-app/runtime/src/main/cpp/MetadataNode.cpp, đọc NullObjectAccessorGetterCallback và NullValueOfCallback, sau đó chạy bản tái hiện inspector với java.lang.Double hoặc java.lang.String. Hoàn thành khi việc đọc marker .null của một class không còn thay đổi hành vi static valueOf của nó, trong khi việc phân giải đối số typed-null vẫn nhận diện marker.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
android, cpp, javascript
Lĩnh vực
mobile-dev
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
55/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.