-
Notifications
You must be signed in to change notification settings - Fork 905
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
Fix some incorrect memory handling #5317
Merged
mkindahl
merged 2 commits into
timescale:main
from
Medvecrab:fix_memory_handling_branch
Feb 20, 2023
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
could you please remove this part as
strlcpy
should take care of the trailing zero - I've checked with valgrind and this doesn't cause/fix any issueThere 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'd like to defend this change.
Firstly, the first patch and the second patch solve different problems, that are only grouped in one issue because they are were found by valgrind together.
The thing with strlcpy is that it only copies amount of bytes up to length of source string and then terminates the string with zero.
In this case, key_data is a char array the size of NAMEDATALEN (which is 64). And metadata_key that is being copied there isn't always NAMEDATALEN long. And key_data is allocated at the top of the stack, and can contain junk. Or whatever was at the top of the stack. So it's better to fill it it with zeroes and only then copy something there.
For me, valgrind still shows first error stated in #5311, and pageinspect still shows junk. And with patch (initial or the ones linked below) this junk is gone and there are only zeroes.
Reproduction is simple - start postgres under valgrind and execute 'CREATE EXTENSION timescaledb;' with psql.
I can provide at least two alternative patches that will first fill the string with zeroes: see attachements
metadata_memory_fix_memcpy.patch
metadata_memory_fix_namedata.patch
If you'll like any of above patches, I'll replace current code in commit with that patch.
If you're still not convinced and can't reproduce it, I'll remove changes in metadata.c.
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.
Not sure I follow the reasoning here: strlcpy() copies the bytes from source to target and is guaranteed to null-terminate the string as long as the size is larger than 0.
From the manual of strlcpy():
So, if the source string is shorter, it will be copied fully into the target, and if it is longer, just the initial prefix will be copied and the string null-terminated, so it basically does the same as the code that you're replacing it with.
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.
Okay, maybe we aren't on the same page here. When manual of
strlcpy
says 'guarantee to NUL-terminate' it means the following: a sequence of symbols starting at an address with a symbolic name "buffer" will end with '\0', guaranteed. And if the buffer was a char pointer that is supposed to be dynamically allocated, that's fine. But in this case,key_data
isn't allocated dynamically. It's an array, size ofNAMEDATALEN
(64). And it's initially not guaranteed to be empty! When we copymetadata_key
(which isn't 100% confirmed to be exactly 64 chars long) into it withstrlcpy
, we get something like this inside: "metadata_key_value\0junk_symbols_until_64th...".key_data
is a char pointer, yes, and if we tried to pass it to, for example,strlen
after copying something into it withstrlcpy
, it would return us it's current length (amount of chars befor '\0'), not 64.But you say here in the comment (metadata.c, lines 158-159):
And that means, that any info left after that terminating zero will be pasted onto a page (as can be seen in #5311):
This can be dangerous, because when we calculate checksums of this page, if this junk if not the same every time, it can be problematic and lead to checksum missmatch.
The simplest solution, in my opinion, is to memset key_data with zeroes before copying anything into it.
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.
You actually have a very good point: the value for the
Name
field is a fixed-size char array (effectively, at least), which means that there will be random data added to the tuple.Note that this has nothing to do with whether the field is dynamically allocated or not, it is just a side-effect of copying
NAMEDATALEN
bytes from the source.However, your patch does not solve the problem in that case, since all you do is replicating the behavior of
strlcpy
with this change.I agree that a working change would be what you suggest: initialize the
key_data
variable with zeroes (it is an auto variable, so it is not automatically zero initialized) and then usestrlcpy
. You need to usestrlcpy
since you need to guarantee that the string is null-terminated even ifmetadata_key
is too long for the buffer.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.
Please let me chime in. As strncpy(3) says:
So, in general, strncpy and strlcpy are not equivalent. The Postgres function namestrcpy deliberately uses strncpy instead of strlcpy to zero-pad the destination.
I think it would be better to replace strlcpy here with namestrcpy to avoid potential confusion in future (please see the alternative patch metadata_memory_fix_namedata.patch mentioned above). I can imagine someone replacing strncpy with strlcpy again, because it's considered a safer alternative. But they are not really interchangable.
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.
Thank you, I missed that comment. In that case, moving away from
strlcpy
is an improvement, but I agree that usingnamestrcpy
is the better alternative.