-
Notifications
You must be signed in to change notification settings - Fork 47
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
Prevent truncating log tag name #83
Conversation
The currently hard-coded limit is 23 characters. This limit originates from the pre-Android 7.0 32-character limit on system property names, because Android's `liblog` allows setting the log level at runtime through `log.tag` system properties [1]. The limit meant that "log.tag.SOMETAG" must have been shorter than 32 bytes, leaving 23 bytes for the tag itself. The system property length limitation was removed in [2], so since 2017 it no longer applies, and some Android components already use longer tags [3][4]. This change increases the size of the stack-allocated buffer used for null-terminating the tag to 128 bytes, and adds support for even longer tags by falling back to heap-allocated CString when the tag is longer than that. The fallback path will introduce a performance penalty, but at the same time will allow manual level adjustment via log.tag. system property regardless of the tag length. [1] https://cs.android.com/android/platform/superproject/main/+/main:system/logging/logd/README.property;l=50?q=f:readme.property [2] https://android-review.googlesource.com/c/platform/bionic/+/327226 [3] https://cs.android.com/android/platform/superproject/main/+/main:device/generic/goldfish-opengl/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.cpp;l=20 [4] https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/biometrics/fingerprint/2.2/default/BiometricsFingerprint.cpp;l=16
@Nercury I'm not sure the PR triggered any notifications, and it seems you're the most active contributor to this repo. Would you find some time to review this (and also, rust-mobile/android_log-sys-rs#6 + #84)? It would be a great help in reusing those crates within AOSP. Thank you in advance! |
This looks ok. It's not your responsibility to clean up overall buffer mess; let's leave that for later/another PR. |
Ok, please address the @MarijnS95 comments before merging. |
Reading in between the lines, that's supported upstream now. It seems this change aims to increase the default buffer length a bit assuming most tags are a bit longer than the previous restrictive limit of 23 to reduce allocations, and fall back to a heap allocation if it's even bigger than the new "soft limit" of 128? |
@dextero note that there's a Line 215 in d51b7ff
|
To use exactly 128-byte long stack allocated buffer.
Also remove unnecessary to_owned call, and clean up _owned_tag use.
// Maximum length of a tag that does not require allocation. | ||
const LOGGING_TAG_MAX_LEN: usize = 127; |
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.
Nice opportunity for a doc-comment and a note regarding the NUL terminator being exempt from this limit?
// Maximum length of a tag that does not require allocation. | |
const LOGGING_TAG_MAX_LEN: usize = 127; | |
/// Maximum length(excluding NUL terminator) of a tag that does not require allocation. | |
const LOGGING_TAG_MAX_LEN: usize = 127; |
} else { | ||
// Tag longer than available stack buffer; allocate. | ||
// We're using either | ||
// - CString::as_bytes on config.tag, or |
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.
Ah, for config.tag
it's a "little unfortunate" that we have to jump through these hoops by going from CString
to &[u8]
and back to CStr
or CString
and let those APIs or ourselves append a NUL terminator again.
Not sure if there's a clean way to handle that without making this very complex while dealing with record.module_path()
as well 😅
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.
That's an excellent observation! Please see the latest commit for an update that makes the happy-path of having a preconfigured tag not go through all this copy-to-buffer-and-then-reinterpret-as-cstr stuff.
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.
Whoops, I didn't notice PR got merged in the meantime - I'll follow up with a cleanup.
// We're using either | ||
// - CString::as_bytes on config.tag, or | ||
// - str::as_bytes on record.module_path() | ||
// Neither of those include the terminating nullbyte. |
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.
Technically record.module_path()
returns a &str
which may contain interior NULs (and never has a terminating NUL, that's reserved for CString
/CStr
) but it seems unlikely that log
will ever return interior NULs here.
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.
TIL again 😅 Putting nullbytes in the module path sounds pretty evil though.
I guess the current code does handle this case by doing a pointer transmute into CStr::from_ptr
. I could do a similar thing here if that would make sense. WDYT?
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.
If the module_path()
included an interior NUL byte, the previous unsafe CStr::from_ptr()
"hack" would have cut off the tag right there. The new implementation correctly panics, because it doesn't understand and doesn't know how to handle this malformed user input.
Note that there is a builder API that trivially allows someone to set the module_path
to Some("hell\0there")
for example: https://docs.rs/log/latest/log/struct.RecordBuilder.html#method.module_path
There is no fixed-size length limit for the tag now. When writing the log entry to logd daemon, the entire tag is passed as is. The log reading API still has a limit of 5 * 1024 B, but that's on the entire "log entry" (tag + message + some metadata) . The "soft limit" pointed out by @MarijnS95 is there to avoid creating huge stack-allocated buffers. I increased it to 128 as 23 was restrictive enough that I ran into truncated tags 😄 |
@dextero looking at those links and seeing (Unless all of that is only available on newer Android versions / APIs of course) |
I guess back then I wanted to split log messages that overflow max char limit on whitespace. Without allocations. Hence the complexity. |
I am going to merge this and other PRs and then do more thorough scan before publishing. |
@Nercury not criticising what has been done so far, it's great to see the limitations from the API mapped out carefully to Rust 🥳! But now that we seem to want to support larger tags/messages here, and perhaps restrict (if needed via optional features / cfgs) to a newer Android API level in order to use simpler and less-constrained APIs, it might be advantageous to refactor. EDIT: With new length-based APIs we might also get away without allocating nor copying bytes. |
The currently hard-coded limit is 23 characters. This limit originates from the pre-Android 7.0 32-character limit on system property names, because Android's
liblog
allows setting the log level at runtime throughlog.tag
system properties [1]. The limit meant that "log.tag.SOMETAG" must have been shorter than 32 bytes, leaving 23 bytes for the tag itself.The system property length limitation was removed in [2], so since 2017 it no longer applies, and some Android components already use longer tags [3][4].
This change increases the size of the stack-allocated buffer used for null-terminating the tag to 128 bytes, and adds support for even longer tags by falling back to heap-allocated CString when the tag is longer than that. The fallback path will introduce a performance penalty, but at the same time will allow manual level adjustment via log.tag. system property regardless of the tag length.
[1] https://cs.android.com/android/platform/superproject/main/+/main:system/logging/logd/README.property;l=50?q=f:readme.property
[2] https://android-review.googlesource.com/c/platform/bionic/+/327226
[3] https://cs.android.com/android/platform/superproject/main/+/main:device/generic/goldfish-opengl/system/codecs/omx/plugin/GoldfishVideoDecoderOMXComponent.cpp;l=20
[4] https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/biometrics/fingerprint/2.2/default/BiometricsFingerprint.cpp;l=16