Skip to content

Commit 48f19ef

Browse files
sjindel-googlecommit-bot@chromium.org
authored andcommitted
[vm/ffi] Fix snapshot serialization of FFI objects.
Change-Id: I78557211da79f5282339fbcf30b3f81ab56cb361 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106345 Commit-Queue: Samir Jindel <[email protected]> Auto-Submit: Samir Jindel <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent 7d0c3f9 commit 48f19ef

6 files changed

Lines changed: 116 additions & 11 deletions

File tree

runtime/vm/clustered_snapshot.cc

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "platform/assert.h"
88
#include "vm/bootstrap.h"
9+
#include "vm/class_id.h"
910
#include "vm/compiler/backend/code_statistics.h"
1011
#include "vm/compiler/frontend/bytecode_reader.h"
1112
#include "vm/compiler/relocation.h"
@@ -767,6 +768,74 @@ class SignatureDataDeserializationCluster : public DeserializationCluster {
767768
}
768769
};
769770

771+
#if !defined(DART_PRECOMPILED_RUNTIME)
772+
class FfiTrampolineDataSerializationCluster : public SerializationCluster {
773+
public:
774+
FfiTrampolineDataSerializationCluster()
775+
: SerializationCluster("FfiTrampolineData") {}
776+
~FfiTrampolineDataSerializationCluster() {}
777+
778+
void Trace(Serializer* s, RawObject* object) {
779+
RawFfiTrampolineData* data = FfiTrampolineData::RawCast(object);
780+
objects_.Add(data);
781+
PushFromTo(data);
782+
}
783+
784+
void WriteAlloc(Serializer* s) {
785+
s->WriteCid(kFfiTrampolineDataCid);
786+
const intptr_t count = objects_.length();
787+
s->WriteUnsigned(count);
788+
for (intptr_t i = 0; i < count; i++) {
789+
s->AssignRef(objects_[i]);
790+
}
791+
}
792+
793+
void WriteFill(Serializer* s) {
794+
intptr_t count = objects_.length();
795+
for (intptr_t i = 0; i < count; i++) {
796+
RawFfiTrampolineData* const data = objects_[i];
797+
AutoTraceObject(data);
798+
WriteFromTo(data);
799+
800+
// TODO(37295): FFI callbacks shouldn't be written to a snapshot. They
801+
// should only be referenced by the callback registry in Thread.
802+
ASSERT(data->ptr()->callback_id_ == 0);
803+
}
804+
}
805+
806+
private:
807+
GrowableArray<RawFfiTrampolineData*> objects_;
808+
};
809+
#endif // !DART_PRECOMPILED_RUNTIME
810+
811+
class FfiTrampolineDataDeserializationCluster : public DeserializationCluster {
812+
public:
813+
FfiTrampolineDataDeserializationCluster() {}
814+
~FfiTrampolineDataDeserializationCluster() {}
815+
816+
void ReadAlloc(Deserializer* d) {
817+
start_index_ = d->next_index();
818+
PageSpace* old_space = d->heap()->old_space();
819+
intptr_t count = d->ReadUnsigned();
820+
for (intptr_t i = 0; i < count; i++) {
821+
d->AssignRef(
822+
AllocateUninitialized(old_space, FfiTrampolineData::InstanceSize()));
823+
}
824+
stop_index_ = d->next_index();
825+
}
826+
827+
void ReadFill(Deserializer* d) {
828+
for (intptr_t id = start_index_; id < stop_index_; id++) {
829+
RawFfiTrampolineData* data =
830+
reinterpret_cast<RawFfiTrampolineData*>(d->Ref(id));
831+
Deserializer::InitializeHeader(data, kFfiTrampolineDataCid,
832+
FfiTrampolineData::InstanceSize());
833+
ReadFromTo(data);
834+
data->ptr()->callback_id_ = 0;
835+
}
836+
}
837+
};
838+
770839
#if !defined(DART_PRECOMPILED_RUNTIME)
771840
class RedirectionDataSerializationCluster : public SerializationCluster {
772841
public:
@@ -4308,6 +4377,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
43084377
return new (Z) SignatureDataSerializationCluster();
43094378
case kRedirectionDataCid:
43104379
return new (Z) RedirectionDataSerializationCluster();
4380+
case kFfiTrampolineDataCid:
4381+
return new (Z) FfiTrampolineDataSerializationCluster();
43114382
case kFieldCid:
43124383
return new (Z) FieldSerializationCluster();
43134384
case kScriptCid:
@@ -4944,6 +5015,8 @@ DeserializationCluster* Deserializer::ReadCluster() {
49445015
return new (Z) SignatureDataDeserializationCluster();
49455016
case kRedirectionDataCid:
49465017
return new (Z) RedirectionDataDeserializationCluster();
5018+
case kFfiTrampolineDataCid:
5019+
return new (Z) FfiTrampolineDataDeserializationCluster();
49475020
case kFieldCid:
49485021
return new (Z) FieldDeserializationCluster();
49495022
case kScriptCid:

runtime/vm/object.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8271,7 +8271,7 @@ RawFfiTrampolineData* FfiTrampolineData::New() {
82718271
Object::Allocate(FfiTrampolineData::kClassId,
82728272
FfiTrampolineData::InstanceSize(), Heap::kOld);
82738273
RawFfiTrampolineData* data = reinterpret_cast<RawFfiTrampolineData*>(raw);
8274-
data->ptr()->callback_id_ = -1;
8274+
data->ptr()->callback_id_ = 0;
82758275
return data;
82768276
}
82778277

runtime/vm/raw_object.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,13 +1034,17 @@ class RawFfiTrampolineData : public RawObject {
10341034
RawFunction* callback_target_;
10351035

10361036
VISIT_TO(RawObject*, callback_target_);
1037+
RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
10371038

1038-
// Callback id for callbacks, otherwise 0.
1039+
// Callback id for callbacks.
10391040
//
10401041
// The callbacks ids are used so that native callbacks can lookup their own
10411042
// code objects, since native code doesn't pass code objects into function
10421043
// calls. The callback id is also used to for verifying that callbacks are
10431044
// called on the correct isolate. See DLRT_VerifyCallbackIsolate for details.
1045+
//
1046+
// Will be 0 for non-callbacks. Check 'callback_target_' to determine if this
1047+
// is a callback or not.
10441048
uint32_t callback_id_;
10451049
};
10461050

runtime/vm/snapshot.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,12 @@ void SnapshotWriter::WriteMarkedObjectImpl(RawObject* raw,
11341134

11351135
#define SNAPSHOT_WRITE(clazz) case kFfi##clazz##Cid:
11361136

1137-
CLASS_LIST_FFI(SNAPSHOT_WRITE) { UNREACHABLE(); }
1137+
CLASS_LIST_FFI(SNAPSHOT_WRITE) {
1138+
SetWriteException(Exceptions::kArgument,
1139+
"Native objects (from dart:ffi) such as Pointers and "
1140+
"Structs cannot be passed between isolates.");
1141+
UNREACHABLE();
1142+
}
11381143
#undef SNAPSHOT_WRITE
11391144
default:
11401145
break;

tests/ffi/ffi.status

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,6 @@ data_not_asan_test: SkipByDesign # This test tries to allocate too much memory o
1313
function_structs_test: Skip
1414
structs_test: Skip
1515

16-
# dartbug.com/35934
17-
[ $compiler == app_jitk ]
18-
dynamic_library_test: Skip
19-
function_callbacks_test: Skip
20-
function_structs_test: Skip
21-
function_test: Skip
22-
negative_function_test: Skip
23-
2416
[ $arch == x64 || $arch == arm64 || $arch == simdbc64 ]
2517
enable_structs_test: SkipByDesign # Tests that structs don't work on 32-bit systems.
2618

@@ -44,3 +36,10 @@ enable_structs_test: SkipByDesign # Tests that structs don't work on 32-bit sys
4436

4537
[ $arch == simdbc64 ]
4638
function_callbacks_test: Skip # Issue 37140
39+
40+
# These tests trigger and catch an abort (intentionally) and terminate the VM
41+
# before it can generate a snapshot.
42+
[ $compiler == app_jitk ]
43+
function_callbacks_test/01: Skip
44+
function_callbacks_test/02: Skip
45+
function_callbacks_test/03: Skip

tests/ffi/snapshot_test.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
//
5+
// Checks that the VM throws an appropriate exception when FFI objects are
6+
// passed between isolates.
7+
8+
import 'dart:async';
9+
import 'dart:ffi';
10+
import 'dart:io';
11+
import 'dart:isolate';
12+
13+
import 'package:expect/expect.dart';
14+
15+
main(args) async {
16+
try {
17+
await Isolate.spawn(print, fromAddress<Pointer<Void>>(1));
18+
} catch (e) {
19+
Expect.type<ArgumentError>(e);
20+
return;
21+
}
22+
23+
throw "Test didn't throw an exception!";
24+
}

0 commit comments

Comments
 (0)