-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[scudo] Add __scudo_get_info
symbol to export stats to a buffer.
#130273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-compiler-rt-sanitizer Author: None (piwicode) ChangesAlso make possible to get the fragmentation stats from the primary allocator. Currenty, Full diff: https://github.com/llvm/llvm-project/pull/130273.diff 8 Files Affected:
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 5deb8c97f1c86..7ab17c5d204c0 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -633,14 +633,8 @@ class Allocator {
// sizing purposes.
uptr getStats(char *Buffer, uptr Size) {
ScopedString Str;
- const uptr Length = getStats(&Str) + 1;
- if (Length < Size)
- Size = Length;
- if (Buffer && Size) {
- memcpy(Buffer, Str.data(), Size);
- Buffer[Size - 1] = '\0';
- }
- return Length;
+ getStats(&Str);
+ return CopyToBuffer(Str, Buffer, Size);
}
void printStats() {
@@ -649,6 +643,12 @@ class Allocator {
Str.output();
}
+ uptr getFragmentationInfo(char *Buffer, uptr Size) {
+ ScopedString Str;
+ Primary.getFragmentationInfo(&Str);
+ return CopyToBuffer(Str, Buffer, Size);
+ }
+
void printFragmentationInfo() {
ScopedString Str;
Primary.getFragmentationInfo(&Str);
@@ -1739,6 +1739,20 @@ class Allocator {
return (Bytes - sizeof(AllocationRingBuffer)) /
sizeof(typename AllocationRingBuffer::Entry);
}
+
+ // Writes the string content to the specified buffer as a null terminated
+ // string, and returns the input string size (including terminal '\0') for
+ // buffer sizing purpose.
+ size_t copyToBuffer(const ScopedString &input, char *output_base,
+ size_t output_length) {
+ if (!output_base)
+ return 0;
+ // Assume that ScopedString internal vector terminal null exists and is not
+ // reported by length.
+ const size_t written = Min(input.length() + 1, output_length);
+ memcpy(output_base, input.data(), written);
+ return written;
+ }
};
} // namespace scudo
diff --git a/compiler-rt/lib/scudo/standalone/include/scudo/interface.h b/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
index a2dedea910cc0..6845b40c8b5cc 100644
--- a/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
+++ b/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
@@ -35,6 +35,23 @@ __attribute__((weak)) void __scudo_realloc_deallocate_hook(void *old_ptr);
void __scudo_print_stats(void);
+// Reports all allocators configuration and general statistics as a null
+// terminated text string.
+#ifndef M_INFO_TOPIC_STATS
+#define M_INFO_TOPIC_STATS 1
+#endif
+
+// Reports fragmentation statistics of the primary allocation as a null
+// terminated text string.
+#ifndef M_INFO_TOPIC_FRAGMENTATION
+#define M_INFO_TOPIC_FRAGMENTATION 2
+#endif
+
+// Writes allocator statistics to the buffer, truncating to the specified size
+// if necessary. Returns the full report size (before truncation) for buffer
+// sizing purpose, or zero if the topic is not supported.
+size_t __scudo_get_info(uint32_t topic, char *buffer, size_t size);
+
typedef void (*iterate_callback)(uintptr_t base, size_t size, void *arg);
// Determine the likely cause of a tag check fault or other memory protection
diff --git a/compiler-rt/lib/scudo/standalone/string_utils.cpp b/compiler-rt/lib/scudo/standalone/string_utils.cpp
index e584bd806e579..e60ae991352cf 100644
--- a/compiler-rt/lib/scudo/standalone/string_utils.cpp
+++ b/compiler-rt/lib/scudo/standalone/string_utils.cpp
@@ -238,4 +238,16 @@ void Printf(const char *Format, ...) {
va_end(Args);
}
+size_t CopyToBuffer(const ScopedString &input, char *output_base,
+ size_t output_length) {
+ if (output_base && output_length) {
+ // Assume that ScopedString internal vector ends with '\0' and that the
+ // terminal null is not reported by `length`.
+ const size_t written = Min(input.length(), output_length - 1);
+ memcpy(output_base, input.data(), written);
+ output_base[written] = '\0';
+ }
+ return input.length() + 1;
+}
+
} // namespace scudo
diff --git a/compiler-rt/lib/scudo/standalone/string_utils.h b/compiler-rt/lib/scudo/standalone/string_utils.h
index cf61e150f20e5..ccb3cf516d8fe 100644
--- a/compiler-rt/lib/scudo/standalone/string_utils.h
+++ b/compiler-rt/lib/scudo/standalone/string_utils.h
@@ -19,8 +19,8 @@ namespace scudo {
class ScopedString {
public:
explicit ScopedString() { String.push_back('\0'); }
- uptr length() { return String.size() - 1; }
- const char *data() { return String.data(); }
+ uptr length() const { return String.size() - 1; }
+ const char *data() const { return String.data(); }
void clear() {
String.clear();
String.push_back('\0');
@@ -45,6 +45,12 @@ class ScopedString {
void Printf(const char *Format, ...) FORMAT(1, 2);
+// Copies the string to the buffer, truncating if necessary.
+// Null-terminates the output if output_length is greater than zero.
+// Returns the original string's size (including null).
+size_t CopyToBuffer(const ScopedString &input, char *output_base,
+ size_t output_length);
+
} // namespace scudo
#endif // SCUDO_STRING_UTILS_H_
diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
index 9d665ef88c402..30f54ae4d0db8 100644
--- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -291,6 +291,12 @@ void ScudoCombinedTest<Config>::BasicTest(scudo::uptr SizeLog) {
Allocator->printStats();
Allocator->printFragmentationInfo();
+
+ {
+ char buffer[256] = {0};
+ EXPECT_LE(0, Allocator->getStats(buffer, sizeof(buffer)));
+ EXPECT_LE(0, Allocator->getFragmentationInfo(buffer, sizeof(buffer)));
+ }
}
#define SCUDO_MAKE_BASIC_TEST(SizeLog) \
diff --git a/compiler-rt/lib/scudo/standalone/tests/strings_test.cpp b/compiler-rt/lib/scudo/standalone/tests/strings_test.cpp
index f81e5036e83b0..71968ad308675 100644
--- a/compiler-rt/lib/scudo/standalone/tests/strings_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/strings_test.cpp
@@ -128,6 +128,46 @@ TEST(ScudoStringsTest, Padding) {
testAgainstLibc<int>("%03d - %03d", -12, -1234);
}
+TEST(ScudoStringsTest, CopyToBuffer) {
+ { // Call with null buffer.
+ scudo::ScopedString Str;
+ Str.append("abc");
+ EXPECT_EQ(4U, scudo::CopyToBuffer(Str, nullptr, 0));
+ }
+
+ { // Empty string.
+ scudo::ScopedString Str;
+ char buf[256] = {'0', '1'};
+ EXPECT_EQ(1U, scudo::CopyToBuffer(Str, buf, sizeof(buf)));
+ EXPECT_STREQ("", buf);
+ EXPECT_EQ(0, buf[0]); // Rest of the buffer remains unchanged.
+ }
+
+ { // Empty string in empty buffer.
+ scudo::ScopedString Str;
+ char buf[256] = {'0', '1'};
+ EXPECT_EQ(1U, scudo::CopyToBuffer(Str, buf, 0));
+ EXPECT_EQ('0', buf[0]); // Nothing changed because provided size is 0.
+ }
+
+ { // Some text fittinh in the buffer.
+ scudo::ScopedString Str;
+ Str.append("abc");
+ char buf[256] = {'0', '1', '2', '3', '4', '5'};
+ EXPECT_EQ(4U, scudo::CopyToBuffer(
+ Str, buf, sizeof(buf))); // Size includes terminal null.
+ EXPECT_STREQ("abc", buf);
+ }
+
+ { // Some text with overflows.
+ scudo::ScopedString Str;
+ Str.append("abc");
+ char buf[256] = {'0', '1', '2', '3', '4', '5'};
+ EXPECT_EQ(4U, scudo::CopyToBuffer(Str, buf, 3));
+ EXPECT_STREQ("ab", buf);
+ }
+}
+
#if defined(__linux__)
#include <sys/resource.h>
diff --git a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
index 60014a0f66bf5..725e3f3e25996 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
@@ -37,4 +37,15 @@ scudo::Allocator<scudo::Config, SCUDO_PREFIX(malloc_postinit)> SCUDO_ALLOCATOR;
extern "C" INTERFACE void __scudo_print_stats(void) { Allocator.printStats(); }
+extern "C" INTERFACE size_t __scudo_get_info(uint32_t topic, char *buffer,
+ size_t size) {
+ switch (topic) {
+ case M_INFO_TOPIC_STATS:
+ return Allocator.getStats(buffer, size);
+ case M_INFO_TOPIC_FRAGMENTATION:
+ return Allocator.getFragmentationInfo(buffer, size);
+ }
+ return 0;
+}
+
#endif // !SCUDO_ANDROID || !_BIONIC
diff --git a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
index e9d8c1e8d3db2..f649059b9c878 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
@@ -38,6 +38,16 @@ static scudo::Allocator<scudo::Config, SCUDO_PREFIX(malloc_postinit)>
// TODO(kostyak): support both allocators.
INTERFACE void __scudo_print_stats(void) { Allocator.printStats(); }
+INTERFACE size_t __scudo_get_info(uint32_t topic, char *buffer, size_t size) {
+ switch (topic) {
+ case M_INFO_TOPIC_STATS:
+ return Allocator.getStats(buffer, size);
+ case M_INFO_TOPIC_FRAGMENTATION:
+ return Allocator.getFragmentationInfo(buffer, size);
+ }
+ return 0;
+}
+
INTERFACE void __scudo_get_error_info(
struct scudo_error_info *error_info, uintptr_t fault_addr,
const char *stack_depot, size_t stack_depot_size, const char *region_info,
|
58148b5
to
8d5d2de
Compare
// Writes allocator statistics to the buffer, truncating to the specified size | ||
// if necessary. Returns the full report size (before truncation) for buffer | ||
// sizing purpose, or zero if the topic is not supported. | ||
size_t __scudo_get_info(uint32_t topic, void *buffer, size_t size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All parameters are capitalized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like parameters use snake_case in the interface.h. Could you please confirm that we want to Capitalize?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, we have so many different cases. We should probably change this in the future, but your interface is fine.
Also make possible to get the fragmentation stats from the primary allocator. Currenty, `__scudo_print_stats` symbol writes the report to the provided printer, which is not convenient for processing the result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Please take another look.
// Writes allocator statistics to the buffer, truncating to the specified size | ||
// if necessary. Returns the full report size (before truncation) for buffer | ||
// sizing purpose, or zero if the topic is not supported. | ||
size_t __scudo_get_info(uint32_t topic, void *buffer, size_t size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like parameters use snake_case in the interface.h. Could you please confirm that we want to Capitalize?
// Writes allocator statistics to the buffer, truncating to the specified size | ||
// if necessary. Returns the full report size (before truncation) for buffer | ||
// sizing purpose, or zero if the topic is not supported. | ||
size_t __scudo_get_info(uint32_t topic, void *buffer, size_t size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, we have so many different cases. We should probably change this in the future, but your interface is fine.
// Writes allocator statistics to the buffer, truncating to the specified size | ||
// if necessary. Returns the full report size (before truncation) for buffer | ||
// sizing purpose, or zero if the topic is not supported. | ||
size_t __scudo_get_info(uint32_t topic, void *buffer, size_t size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I had a comment about this, but I may have missed your reply.
Is there a reason to have this as one function and not two different functions that do different things? For example, are you planning to add more info types in the future.
Also make possible to get the fragmentation stats from the primary allocator.
Currenty,
__scudo_print_stats
symbol writes the report to the provided printer, which is not convenient for processing the result.