From ce465e3d29ca8813e48b0fa923ae6a1bbe0f695c Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Mon, 2 Sep 2024 15:54:44 -0300 Subject: [PATCH] fix: generate correct metadata when overflowing signed short values --- .../src/com/telerik/metadata/Generator.java | 11 +++++- .../src/src/com/telerik/metadata/Writer.java | 34 ++++++++++++++++++- .../runtime/src/main/cpp/MetadataReader.cpp | 17 +++++++--- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Generator.java b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Generator.java index 5e11277a4..6a53cea27 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Generator.java +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Generator.java @@ -27,6 +27,8 @@ public class Generator { private static final String MDG_BLACKLIST = "blacklist.mdg"; private static final String METADATA_JAVA_OUT = "mdg-java-out.txt"; + private static boolean verbose_mode = false; + /** * @param args arguments */ @@ -69,7 +71,13 @@ public static void main(String[] args) { FileOutputStream oss = new FileOutputStream(new File(metadataOutputDir, "treeStringsStream.dat")); FileStreamWriter outStringsStream = new FileStreamWriter(oss); - new Writer(outNodeStream, outValueStream, outStringsStream).writeTree(root); + if (verbose_mode) { + FileOutputStream ods = new FileOutputStream(new File("metadata-debug.json")); + FileStreamWriter outDebugStream = new FileStreamWriter(ods); + new Writer(outNodeStream, outValueStream, outStringsStream, outDebugStream).writeTree(root); + } else { + new Writer(outNodeStream, outValueStream, outStringsStream).writeTree(root); + } } catch (Throwable ex) { System.err.println(String.format("Error executing Metadata Generator: %s", ex.getMessage())); ex.printStackTrace(System.out); @@ -83,6 +91,7 @@ private static void enableFlaggedFeatures(String[] args) { String filePath = arg.replace(ANALYTICS_ARGUMENT_BEGINNING, ""); AnalyticsConfiguration.enableAnalytics(filePath); } else if (VERBOSE_FLAG_NAME.equals(arg)) { + verbose_mode = true; MetadataFilterConsoleLogger.INSTANCE.setEnabled(true); } else if (SKIP_FLAG_NAME.equals(arg)) { System.out.println("Skipping metadata generation: skip flag used."); diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Writer.java b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Writer.java index 1d76f2550..36777a831 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Writer.java +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Writer.java @@ -1,5 +1,7 @@ package com.telerik.metadata; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import com.telerik.metadata.TreeNode.FieldInfo; import com.telerik.metadata.TreeNode.MethodInfo; @@ -10,6 +12,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -18,14 +21,20 @@ public class Writer { private final StreamWriter outNodeStream; private final StreamWriter outValueStream; private final StreamWriter outStringsStream; + private final StreamWriter outDebugStream; private int commonInterfacePrefixPosition; public Writer(StreamWriter outNodeStream, StreamWriter outValueStream, StreamWriter outStringsStream) { + this(outNodeStream, outValueStream, outStringsStream, null); + } + public Writer(StreamWriter outNodeStream, StreamWriter outValueStream, + StreamWriter outStringsStream, StreamWriter outDebugStream) { this.outNodeStream = outNodeStream; this.outValueStream = outValueStream; this.outStringsStream = outStringsStream; + this.outDebugStream = outDebugStream; } private final static byte[] writeUniqueName_lenBuff = new byte[2]; @@ -214,6 +223,10 @@ public void writeTree(TreeNode root) throws Exception { d.push(root); while (!d.isEmpty()) { TreeNode n = d.pollFirst(); + if (Short.toUnsignedInt((short)(curId + 1)) < Short.toUnsignedInt(curId)) { + // we have overflowed our maximum (16 bit) metadata size + throw new Exception("Metadata is too big and has overflown our current limit, please report this issue"); + } n.id = n.firstChildId = n.nextSiblingId = curId++; String name = n.getName(); @@ -351,7 +364,7 @@ public void writeTree(TreeNode root) throws Exception { while (!d.isEmpty()) { TreeNode n = d.pollFirst(); - nodeData[0] = n.firstChildId + (n.nextSiblingId << 16); + nodeData[0] = (n.firstChildId & 0xFFFF) | (n.nextSiblingId << 16); nodeData[1] = n.offsetName; nodeData[2] = n.offsetValue; @@ -364,5 +377,24 @@ public void writeTree(TreeNode root) throws Exception { outNodeStream.flush(); outNodeStream.close(); + + if (outDebugStream != null) { + d.push(root); + JsonArray rootArray = new JsonArray(); + while (!d.isEmpty()) { + TreeNode n = d.pollFirst(); + JsonObject obj = new JsonObject(); + obj.addProperty("id", Short.toUnsignedInt(n.id)); + obj.addProperty("nextSiblingId", Short.toUnsignedInt(n.nextSiblingId)); + obj.addProperty("firstChildId", Short.toUnsignedInt(n.firstChildId)); + obj.addProperty("name", n.getName()); + obj.addProperty("nodeType", n.nodeType); + rootArray.add(obj); + d.addAll(n.children); + } + outDebugStream.write(rootArray.toString().getBytes()); + outDebugStream.flush(); + outDebugStream.close(); + } } } diff --git a/test-app/runtime/src/main/cpp/MetadataReader.cpp b/test-app/runtime/src/main/cpp/MetadataReader.cpp index 9fb9daa78..5c37dfdcb 100644 --- a/test-app/runtime/src/main/cpp/MetadataReader.cpp +++ b/test-app/runtime/src/main/cpp/MetadataReader.cpp @@ -2,6 +2,7 @@ #include "MetadataMethodInfo.h" #include "Util.h" #include +#include using namespace std; using namespace tns; @@ -54,20 +55,28 @@ MetadataTreeNode* MetadataReader::BuildTree() { while (true) { uint16_t childNodeDataId = childNodeData - rootNodeData; + + MetadataTreeNode* childNode; // node (and its next siblings) already visited, so we don't need to visit it again if (m_v[childNodeDataId] != emptyNode) { + childNode = m_v[childNodeDataId]; + __android_log_print(ANDROID_LOG_ERROR, "TNS.error", "Consistency error in metadata. A child should never have been visited before its parent. Parent: %s Child: %s. Child metadata id: %u", node->name.c_str(), childNode->name.c_str(), childNodeDataId); break; + } else { + childNode = new MetadataTreeNode; + childNode->name = ReadName(childNodeData->offsetName); + childNode->offsetValue = childNodeData->offsetValue; } - - MetadataTreeNode* childNode = new MetadataTreeNode; childNode->parent = node; - childNode->name = ReadName(childNodeData->offsetName); - childNode->offsetValue = childNodeData->offsetValue; node->children->push_back(childNode); m_v[childNodeDataId] = childNode; + if (childNodeDataId == childNodeData->nextSiblingId) { + break; + } + childNodeData = rootNodeData + childNodeData->nextSiblingId; } }