From 5ddb1b8ea77b398fe7bd174444071566fdf64b0b Mon Sep 17 00:00:00 2001 From: Vyacheslav Egorov Date: Wed, 9 Aug 2023 12:59:31 +0000 Subject: [PATCH] [vm/service] Use getline to read /proc/self/smaps Previously the code was using `fgets` with a fixed size buffer. This lead to a confusing behavior where lines longer than 255 characters would be read in multiple chunks and cause crashes in the parsing code. Additionally make extraction of the path component slightly more robust by searching for path field forward rather than backwards. Path might contain white space and searching backwards might stumble on that. This is a reland of 95474f44f1719346993a33423aa07096705859ad with changes to android min-sdk to make android ARM builds succeed (getline requires SDK 18+). TEST=manually Change-Id: I8b36fcd178680aed7f856bc884a5cd188a5f6e85 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319480 Commit-Queue: Slava Egorov Reviewed-by: Martin Kustermann --- build/config/android/config.gni | 2 +- runtime/vm/service.cc | 39 +++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/build/config/android/config.gni b/build/config/android/config.gni index 6dbbf38c775..cf91e85eeb7 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni @@ -73,7 +73,7 @@ if (is_android) { if (current_cpu == "x64" || current_cpu == "arm64") { android_api_level = 22 } else { - android_api_level = 16 + android_api_level = 19 } # Toolchain root directory for each build. The actual binaries are inside diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index 9b75d36d175..8e7d396faed 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -4562,14 +4562,44 @@ static void AddVMMappings(JSONArray* rss_children) { } MallocGrowableArray mappings(10); - char line[256]; + char* line = nullptr; + size_t line_buffer_size = 0; char path[256]; char property[32]; size_t start, end, size; - while (fgets(line, sizeof(line), fp) != nullptr) { + while (getline(&line, &line_buffer_size, fp) > 0) { if (sscanf(line, "%zx-%zx", &start, &end) == 2) { - // Mapping line. - strncpy(path, strrchr(line, ' ') + 1, sizeof(path) - 1); + // Each line has the following format: + // + // start-end flags offset dev inode path + // + // We want to skip 4 fields and get to the last one (path). + // Note that we can't scan backwards because path might contain white + // space. + const intptr_t kPathFieldIndex = 5; + + char* path_start = line; + intptr_t current_field = 0; + while (*path_start != '\0') { + // Field separator. + if (*path_start == ' ') { + // Skip to the first non-space. + while (*path_start == ' ') { + path_start++; + } + current_field++; + if (current_field == kPathFieldIndex) { + break; + } + continue; + } + path_start++; + } + if (current_field != kPathFieldIndex) { + continue; // Malformed input. + } + + strncpy(path, path_start, sizeof(path) - 1); int len = strlen(path); if ((len > 0) && path[len - 1] == '\n') { path[len - 1] = 0; @@ -4606,6 +4636,7 @@ static void AddVMMappings(JSONArray* rss_children) { } } fclose(fp); + free(line); // Free buffer allocated by getline. for (intptr_t i = 0; i < mappings.length(); i++) { JSONObject mapping(rss_children);