Fix readFromParcel in every backend
readFromParcel should check the size before reading a field and set
Parcel's data position on successful exit.
Previously, the first field was read without checking the available
data, which fails when the older version is empty.
Bug: 186632725
Bug: 186633641
Test: aidl_integration_test
Change-Id: I8cbe9cd280833e04ee5f1c58f26eca0a9bdf1076
diff --git a/generate_rust.cpp b/generate_rust.cpp
index 0b36ff6..3d8be91 100644
--- a/generate_rust.cpp
+++ b/generate_rust.cpp
@@ -562,25 +562,29 @@
out << "let parcelable_size: i32 = parcel.read()?;\n";
out << "if parcelable_size < 0 { return Err(binder::StatusCode::BAD_VALUE); }\n";
- // Pre-emit the common field epilogue code, shared between all fields:
- ostringstream epilogue;
- epilogue << "if (parcel.get_data_position() - start_pos) == parcelable_size {\n";
+ // Pre-emit the common field prolog code, shared between all fields:
+ ostringstream prolog;
+ prolog << "if (parcel.get_data_position() - start_pos) == parcelable_size {\n";
// We assume the lhs can never be > parcelable_size, because then the read
// immediately preceding this check would have returned NOT_ENOUGH_DATA
- epilogue << " return Ok(Some(result));\n";
- epilogue << "}\n";
- string epilogue_str = epilogue.str();
+ prolog << " return Ok(Some(result));\n";
+ prolog << "}\n";
+ string prolog_str = prolog.str();
out << "let mut result = Self::default();\n";
for (const auto& variable : parcel->GetFields()) {
+ out << prolog_str;
if (!TypeHasDefault(variable->GetType(), typenames)) {
out << "result." << variable->GetName() << " = Some(parcel.read()?);\n";
} else {
out << "result." << variable->GetName() << " = parcel.read()?;\n";
}
- out << epilogue_str;
}
-
+ // Now we read all fields.
+ // Skip remaining data in case we're reading from a newer version
+ out << "unsafe {\n";
+ out << " parcel.set_data_position(start_pos + parcelable_size)?;\n";
+ out << "}\n";
out << "Ok(Some(result))\n";
}