Skip to content

Prevent replacement of format strings in message#365

Merged
tsipinakis merged 3 commits intodunst-project:masterfrom
bebehei:issue-322
Sep 9, 2017
Merged

Prevent replacement of format strings in message#365
tsipinakis merged 3 commits intodunst-project:masterfrom
bebehei:issue-322

Conversation

@bebehei
Copy link
Member

@bebehei bebehei commented Aug 28, 2017

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

@bebehei bebehei force-pushed the issue-322 branch 2 times, most recently from 0b0e257 to 5f41365 Compare August 28, 2017 11:35
@bebehei bebehei changed the title Prevent replacement format strings in message content Prevent replacement of format strings in message Aug 28, 2017
Copy link
Member

@tsipinakis tsipinakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, sorry for the huge delay in getting through PRs, looks like it's going to be a while until I am up and running again.

I can't do a full review currently but here are a few passing remarks looking at the code.

char* tmp;
char *notification_replace_single_field(char *haystack, char **needle,
const char *replacement, enum markup_mode markup_mode) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is assuming that **needle is the beginning of a format flag, I think an assertion is in order to catch any bugs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed now the line below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I added another assertion, that needle points into haystack.

MARKUP_NO);
break;
default:
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should probably be a warning here, let's not silently ignore unknown items.

ASSERT_STR_EQ("Markup is removed and &amp; 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 &amp; escaped", (str = notification_replace_single_field(str, &substr, "<i>is removed</i> and & escaped", MARKUP_STRIP)));
ASSERT_EQ(strlen("Markup is removed and &amp; escaped"), substr - str);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use strlen here but hardcode all the others?

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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this more "C-ish" than the current signature? I changed it, now for evaluation.

@bebehei
Copy link
Member Author

bebehei commented Sep 4, 2017

Found a bug: format string <some stuff>%A creates endless loop

Fixed.

@bebehei bebehei force-pushed the issue-322 branch 7 times, most recently from 256f9ee to 31efd01 Compare September 6, 2017 11:45
@tsipinakis
Copy link
Member

Found a bug

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.

assert(*needle >= *haystack);
assert(*needle - *haystack <= strlen(*haystack));

char* input;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. There is no reason to have this declaration here and not a few lines bellow where input is first used
  2. 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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

assert(*needle[0] == '%');
// needle has to point into haystack
assert(*needle >= *haystack);
assert(*needle - *haystack <= strlen(*haystack));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved.

break;
default:
fprintf(stderr, "WARNING: format_string %%%c"
" is unknown\n", substr[1]);
Copy link
Member

@tsipinakis tsipinakis Sep 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Treated.

@bebehei
Copy link
Member Author

bebehei commented Sep 6, 2017

I'd love to have a regression test

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.

@tsipinakis
Copy link
Member

Can you squash 1aaf109 into ac5542a and resolve the conflicts?

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
@bebehei
Copy link
Member Author

bebehei commented Sep 7, 2017

Rebased and LGTM.

@tsipinakis
Copy link
Member

LGTM 👍

@tsipinakis tsipinakis merged commit 29aa4c7 into dunst-project:master Sep 9, 2017
@bebehei bebehei deleted the issue-322 branch September 9, 2017 15:52
bebehei added a commit to bebehei/dunst that referenced this pull request Oct 6, 2017
bebehei added a commit to bebehei/dunst that referenced this pull request Oct 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants