Prevent replacement of format strings in message#365
Prevent replacement of format strings in message#365tsipinakis merged 3 commits intodunst-project:masterfrom
Conversation
0b0e257 to
5f41365
Compare
| char* tmp; | ||
| char *notification_replace_single_field(char *haystack, char **needle, | ||
| const char *replacement, enum markup_mode markup_mode) { | ||
|
|
There was a problem hiding this comment.
Since this is assuming that **needle is the beginning of a format flag, I think an assertion is in order to catch any bugs.
There was a problem hiding this comment.
This is fixed now the line below.
There was a problem hiding this comment.
Also I added another assertion, that needle points into haystack.
| MARKUP_NO); | ||
| break; | ||
| default: | ||
| break; |
There was a problem hiding this comment.
There should probably be a warning here, let's not silently ignore unknown items.
test/notification.c
Outdated
| ASSERT_STR_EQ("Markup is removed and & escaped", (str = notification_replace_format("%a", "<i>is removed</i> and & escaped", str, MARKUP_STRIP))); | ||
| substr = strchr(str, '%'); | ||
| ASSERT_STR_EQ("Markup is removed and & escaped", (str = notification_replace_single_field(str, &substr, "<i>is removed</i> and & escaped", MARKUP_STRIP))); | ||
| ASSERT_EQ(strlen("Markup is removed and & escaped"), substr - str); |
There was a problem hiding this comment.
Why use strlen here but hardcode all the others?
src/notification.c
Outdated
| char *notification_replace_format(const char *needle, const char *replacement, | ||
| char *haystack, enum markup_mode markup_mode) { | ||
| char* tmp; | ||
| char *notification_replace_single_field(char *haystack, char **needle, |
There was a problem hiding this comment.
If we going to use a double pointer for the needle, I think it'd be better to also use it for the haystack and avoid the awkward assignments in notification_init.
There was a problem hiding this comment.
Is this more "C-ish" than the current signature? I changed it, now for evaluation.
|
Fixed. |
256f9ee to
31efd01
Compare
I'd love to have a regression test for this but that means it'd also print the warning with it. I've opened #368 to look into somehow controlling how logging works. |
src/notification.c
Outdated
| assert(*needle >= *haystack); | ||
| assert(*needle - *haystack <= strlen(*haystack)); | ||
|
|
||
| char* input; |
There was a problem hiding this comment.
While currently it's already in a similar way in master I think it's worth fixing these nitpicks since we're refactoring this anyway:
- There is no reason to have this declaration here and not a few lines bellow where
inputis first used - While it's pretty inconsistent across the project, we usually put the asterisk next to the variable name and not the type e.g.
char *input.
The rationale for this is simply that it gets confusing when using commas, for example inchar* a,bais a pointer whilebis not.
There was a problem hiding this comment.
While it's pretty inconsistent across the project, we usually put the asterisk next to the variable name and not the type e.g. char input.
The rationale for this is simply that it gets confusing when using commas, for example in char a,b a is a pointer while b is not.
Thanks for answering this question. I knew this was the C-specific equivalent of "tabs vs spaces", so I kept avoiding it, because I thought I could not understand all arguments. But thanks it's very clear now.
There is no reason to have this declaration here and not a few lines bellow where input is first used
So, while we're at these "religious" questions:
char *string = function_returning_string();
[begin of the block]
char *string;
[maybe some code]
string = function_returning_string();
I've seen both styles here in the project, but I haven't found a scheme. My observations had been, that a C-programmer rather uses the 2nd style.
What's better or when use what?
src/notification.c
Outdated
| assert(*needle[0] == '%'); | ||
| // needle has to point into haystack | ||
| assert(*needle >= *haystack); | ||
| assert(*needle - *haystack <= strlen(*haystack)); |
There was a problem hiding this comment.
This assertion should probably test for less than not less-than-or-equal: We don't want a trailing % at the end of the string, if anything it might trip over string_replace_at into undefined behaviour.
| break; | ||
| default: | ||
| fprintf(stderr, "WARNING: format_string %%%c" | ||
| " is unknown\n", substr[1]); |
There was a problem hiding this comment.
There should be a different message if substr[1] is \0, aka we're at the end of the string.
e.g. WARNING: Trailing % mark in format
I'd love that, too. But I consider this part of the function as "not testable yet". The function is too big and needs to be refactored to have a senseful unittest. |
To replace all occuring format strings inside the msg, replace_all had been used previously. This leads to buggy behavior, if a format string occurs in the replaced text, as the format string will get replaced again under certain conditions. Introducing a pointer, which skips the already replaced parts, will prevent doubly replacing format strings from content. Fixes dunst-project#322
|
Rebased and LGTM. |
|
LGTM 👍 |
Redo dunst-project#354, as it got pushed out in dunst-project#365
Redo dunst-project#354, as it got pushed out in dunst-project#365
To replace all occuring format strings inside the msg, replace_all had
been used previously. This leads to buggy behavior, if a format string
occurs in the replaced text, as the format string will get replaced
again under certain conditions.
Introducing a pointer, which skips the already replaced parts, will
prevent doubly replacing format strings from content.
Fixes #322