Problem/Motivation

We no longer need SafeMarkup::set(). All the work on documenting or removing has shown that removing is always possible - #2280965: [meta] Remove every SafeMarkup::set() call

Suggested commit

git commit -m 'Issue #2554889 by Berdir, Cottser, Daniel_Rose, JeroenT, RavindraSingh, Wim Leers, YesCT, akalata, alexpott, alimac, aneek, catch, cdulude, chx, cilefen, cmanalansan, crowdcg, cwells, davidhernandez, dawehner, dtraft, effulgentsia, harjotsingh, hass, ianthomas_uk, joelpittet, josephdpurcell, justAChris, kbaringer, lauriii, lduerig, leslieg, lokapujya, mpdonadio, peezy, pwolanin, realdream, sclapp, stefan.r, tim.plunkett, webchick, xjm: Remove SafeMarkup::set() from the codebase.'

This includes everyone from this issue, #2297703: [meta] Refactor and remove as many SafeMarkup::set() calls as possible and #2280965: [meta] Remove every SafeMarkup::set() call and people who joined a very long call about how to finish all the issues.

Proposed resolution

  • Remove the method.
  • Use reflection in a helper method for testing in SafeMarkupTest

Remaining tasks

  • Write patch
  • Review
  • Commit

User interface changes

None

API changes

Remove SafeMarkup::set()

Data model changes

None

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

alexpott’s picture

Status: Active » Needs review
FileSize
4.69 KB

Here's the removal from SafeMarkupTest

Wim Leers’s picture

Whew, must've felt … liberating, to be able to roll that patch! :D

cilefen’s picture

dawehner’s picture

It is so great that this is actually possible now!

  1. +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
    @@ -20,53 +20,45 @@
    +    $reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
    

    Everytime I see a class reference not using ::CLASS a kitten dies :)

  2. +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
    @@ -20,53 +20,45 @@
    +    $reflected_property->setAccessible(true);
    

    nitpick: true => TRUE

Wim Leers’s picture

The most important change is missing: SafeMarkup::set() is not being removed yet! But that's blocked on those other issues landing first, of course.

Everytime I see a class reference not using ::CLASS a kitten dies :)

:D

dawehner’s picture

Oh for sure, but we are at a point where we can finally consider removing it.

Wim Leers’s picture

Yep, that's what I said :)

alexpott’s picture

Status: Needs review » Postponed (maintainer needs more info)

Postponing on all the other issues that are part of #2280965: [meta] Remove every SafeMarkup::set() call

alexpott’s picture

Status: Postponed (maintainer needs more info) » Postponed
alexpott’s picture

Issue summary: View changes

git commit -m 'Issue #2554889 by kbaringer, mpdonadio, xjm, Cottser, alexpott, joelpittet, davidhernandez, cilefen, cwells, Wim Leers, akalata, stefan.r, josephdpurcell, sclapp, harjotsingh, justAChris, peezy, leslieg, lokapujya, RavindraSingh, cdulude, effulgentsia, chx, catch, crowdcg, webchick, aneek, JeroenT, dawehner, realdream, dtraft, YesCT, lauriii, hass, Daniel_Rose, alimac, cmanalansan, lduerig, pwolanin: Remove SafeMarkup::set() from the codebase.'
This includes everyone from #2297703: [meta] Refactor and remove as many SafeMarkup::set() calls as possible and #2280965: [meta] Remove every SafeMarkup::set() call and people who joined a very long call about how to finish all the issues.

stefan.r’s picture

The last submitted patch, 12: 2554889-11.patch, failed testing.

alexpott’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
    @@ -35,57 +35,22 @@ class SafeMarkup {
    +   *   The escaping strategy. See self::setMultiple(). Defaults to 'html'.
    

    I think we should just remove the See self::set() it's not useful.

  2. +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
    @@ -100,12 +65,23 @@ public static function isSafe($string, $strategy = 'html') {
    +   * This method is for internal use only. It is used in the batch and form
    

    There is an issue to mark SafeMarkup::setMultiple as internal somewhere...

  3. +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
    @@ -100,12 +65,23 @@ public static function isSafe($string, $strategy = 'html') {
    +   *   every string in this list will be represented by a an associative
    +   *   array with as key the string and as value an asssociative array
    +   *   with the escaping strategy used for this string as a key and
    +   *   the boolean TRUE as a value. Two escaping strategies are supported
    

    by a an? This text does not make much sense atm.

stefan.r’s picture

Status: Needs work » Needs review
FileSize
1.77 KB
10.23 KB

1. I think you mean ::setMultiple(), not ::set()? An explanation was added in ::setMultiple() of the escaping strategies... but I agree it's not hard to find anyway so let's remove.
2. Let's remove that as well and leave that for the other issue.
3. Rewrote this to "Every string in this list will be represented by a multidimensional array in which the keys are the string and the escaping strategy used for this string, and in which the value is the boolean TRUE."

Status: Needs review » Needs work

The last submitted patch, 15: 2554889-13.patch, failed testing.

xjm’s picture

ianthomas_uk’s picture

setMultiple issue is #2557893: Mark SafeMarkup::setMultiple as internal

Before this patch, the escaping strategies are documented on SafeMarkup::set(), but this removes that documentation. It would seem more sensible to move it to the remaining public API that uses it, SafeMarkup::isSafe().

Status: Needs work » Needs review

lauriii queued 15: 2554889-13.patch for re-testing.

stefan.r’s picture

@ianthomas_uk it wasn't removed, it was moved to ::setMultiple(). It does make more sense to put it on the single public API though, so let's move it there.

However even if it will be marked as internal it would still be good to have some kind of reference to the actual escaping strategies on ::setMultiple(), so I just added a "See self::isSafe() for the list of supported escaping strategies." there.

dawehner’s picture

Just grepped for SafeMarkup::set() and there are indeed also no references in documentation.

I could not find anything to complain about. Read through SafeMarkup itself and it seems good and consistent now.

stefan.r’s picture

reroll now that setMultiple() has been marked as @internal

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Let's do this then!

+++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
@@ -35,58 +35,29 @@ class SafeMarkup {
+   * marked as safe (never partial markup). For example, you should never mark
+   * string such as '<' or '<script>' safe.

s/mark string/mark a string/, can be fixed on commit.

alexpott’s picture

Do we think there is any margin in warning contrib before doing this. @laurii has said that many contrib modules are using SafeMarkup::set() - i know composer_manager and devel are using it.

davidhernandez’s picture

Issue tags: +Needs change record

I would think at least.

cilefen’s picture

Can we just reference this one? https://www.drupal.org/node/2311123

ianthomas_uk’s picture

How much warning were you thinking? If you want modules to be working in Beta 14 and/or at Barcelona, then you'd want to remove this ASAP (which is a very obvious warning), or delay until after that date.

If contrib authors have been paying attention, they will have known this is coming. The method was documented "This method is for internal use. Do not use it to prevent escaping of markup;" when it was first committed (admittedly no @internal or underscore prefix) and there has been a big push to remove its use from core. That doesn't help the users of any broken modules of course...

lauriii’s picture

I'm +1 for doing this ASAP so modules / sites will have as much of time as possible to adapt for this change. I also referenced a CR for this one.

lauriii’s picture

Issue tags: -Needs change record
cilefen’s picture

I edited https://www.drupal.org/node/2549395 to refer to the other CR with strategies. Does that make sense for everyone?

davidhernandez’s picture

That change record might be enough but it was published a week ago. Do we assume everyone was paying attention or do we need something more attention grabbing? It does have set() mentioned with a link to the strategies. Thanks, Chris.

lauriii’s picture

I think we can republish the change record. xjm said that she will be posting a blog post about the changes. Beside these two I think we need extensive documentation page which contains all the information about autoescaping in one page. Right now its in multiple change records and its hard to find. My opinion is still that these should not be blocking this issue getting commited.

mpdonadio’s picture

I think the other good idea is to make a Drupal 8 specific section (or maybe a separate version) of the Handle text in a secure fashion page.

joelpittet’s picture

joelpittet’s picture

davidhernandez’s picture

I agree with the sentiment that if this is to be done then do it sooner rather than later.

Berdir’s picture

*If* contrib can be updated then removing it IMHO is OK.

The question is, are we sure that we covered all existing cases on contrib and custom now with better/alternative solutions?

A while ago I asked @alexpott about a use case I had with data attributes in #markup, just couldn't get that to work without SafeMarkup::set(). Not sure if that works now?

My code looks like this:

    return array(
      '#markup' => SafeMarkup::set('<div class="np8-adition" data-np8-adition-url="' . htmlentities($script_url) . '"></div>'),
    );

The problem is that the data attribute is destroyed. Obviously, #allowed_tags doesn't help as the problem is not a tag. Doing some testing, SafeString::create() works, but that's marked as internal. And it seems like the actual problem is the 8 in the data attribute.. data-np-adition-url works fine ;) seems like our data attribute detection has a bug?

Anyway, while I could remove that, there are likely valid use cases where you want to print out attributes that *will* be blocked? I guess #template should work then?

ianthomas_uk’s picture

@berdir unless you've got a better way of identifying any cases that contrib needs SafeMarkup::set() for, that sounds like a good argument for removing ASAP. That way we've got maximum time to fix and fix any issues that do arise. Fixes could include reverting this patch if that's necessary.

Regarding your specific example, that sounds like a core bug that you've been able to use SafeMarkup to work around (I checked the html spec and couldn't see why numbers wouldn't be allowed). We should file and fix the core bug, in the meantime you can work around it by removing the 8.

xjm’s picture

Priority: Major » Critical
Status: Reviewed & tested by the community » Needs work
Issue tags: +Triaged D8 critical, +Needs change record updates

Discussed with @alexpott, @catch, @effulgentsia, and @webchick. We agreed that this issue is critical, and removing SafeMarkup::set() as soon as possible will give modules that were already (mis)using as much chance to update as possible.

Also, we need to update the change records for this before committing it, and also ideally announce this and the other method removals/deprecations on g.d.o/core.

catch’s picture

SafeString::create() works, but that's marked as internal.

You can create your own class implementing SafeStringInterface. See the 'implemented by' list on https://api.drupal.org/api/drupal/core!lib!Drupal!Component!Utility!Safe... for examples.

lauriii’s picture

xjm: I was wondering if you could explain which parts needs to be updated? I'm more than happy to do the actual work :)

dawehner’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs change record updates

it, and also ideally announce this and the other method removals/deprecations on g.d.o/core.

Safemarkup::set() was always considered as bad API, so I'm not sure why we need it for this particular method. I do agree for the other methods like checkPlain / format ... its way more important to inform people about those.

If you search for SafeMarkup::set() practically just https://www.drupal.org/node/2549395 appears.
I also searched for just SafeMarkup and a few issues appeared (https://www.drupal.org/node/2506757, https://www.drupal.org/node/2392803, https://www.drupal.org/node/2445441, https://www.drupal.org/node/2296163, https://www.drupal.org/node/2302363 and https://www.drupal.org/node/1312890)
but none of them call out to SafeMarkup::set(), so I'm not sure why we should update them as part of this issue.

xjm’s picture

https://www.drupal.org/node/2311123 includes nothing about render arrays or the item list template, but leveraging render arrays was one of the ways we were able to get rid a lot of SafeMarkup::set() usage in core. Also the links in https://www.drupal.org/node/2549395 are not accessible; we should add actual link text (unlike what I did here) ;). Finally, we need a g.d.o/core post announcing this as well given the impact.

Edit: Also, we need to cover how to do things that are incompatible with Xss::filterAdmin() somewhere.

xjm’s picture

Also the SafeMarkup::format() example in https://www.drupal.org/node/2311123 arguably should be a Twig template. Anyway, I updated it with stubs for how it should be updated. I also think it should actually stop to exist as a separate thing entirely and be merged into https://www.drupal.org/node/2296163 because its title makes no sense now (I had filed an issue for this to happen several months ago but looks like it hasn't happened).

I can work on these things later if someone else doesn't get to them first.

catch’s picture

Issue tags: +beta target

Tagging this as beta target since it's a deliberate API change that we want to expose to contrib as soon as possible.

webchick’s picture

Assigned: Unassigned » xjm

The patch here looks straight-forward enough, but probably needs @xjm's sign-off on whether the docs gate is met.

xjm’s picture

Found it -- this is the existing issue for the change records: #2494297: [no patch] Consolidate change records relating to safe markup and filtering/escaping to ensure cross references exist

I'm working on getting the CRs up to date and accurate enough so that at least 80% of reasons people might have added SafeMarkup::set() to their contrib or custom code are covered. When that's done, I'll prepare a short g.d.o/core post announcing this change as well as the checkPlain() deprecation, and then review and probably commit this patch within the next couple days.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 22: 2554889-22.patch, failed testing.

star-szr’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
9.28 KB
chx’s picture

Yaaaaay! Thank you all so much for finally getting here!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 49: remove-2554889-49.patch, failed testing.

tim.plunkett’s picture

stefan.r’s picture

Status: Needs review » Reviewed & tested by the community

reroll looks sane

xjm’s picture

Thanks for the reroll! Just a note that I'm still working on the necessary docs updates for this. Getting close to having the minimum necessary information in https://www.drupal.org/node/2296163 (thanks @lauriii for also helping with this). I'll review the patch for commit once that's done and once I've posted to g.d.o/core announcing it.

xjm’s picture

xjm’s picture

Assigned: xjm » Unassigned
Status: Reviewed & tested by the community » Needs work

Alright, the announcement is out, and the CRs are not 100% ship-shape but I think good enough to commit this.

  1. +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
    @@ -35,57 +35,28 @@ class SafeMarkup {
    -   * This method is for internal use. Do not use it to prevent escaping of
    -   * markup; instead, use the appropriate
    -   * @link sanitization sanitization functions @endlink or the
    -   * @link theme_render theme and render systems @endlink so that the output
    -   * can be themed, escaped, and altered properly.
    -   *
    -   * This marks strings as secure for the entire page render, not just the code
    -   * or element that set it. Therefore, only valid HTML should be
    -   * marked as safe (never partial markup). For example, you should never do:
    -   * @code
    -   *   SafeMarkup::set('<');
    -   * @endcode
    -   * or:
    -   * @code
    -   *   SafeMarkup::set('<script>');
    -   * @endcode
    

    I think this documentation needs to be adapted and added to setMultiple() now. While it is marked @internal, it is still a public method, and now the only way for other code to add stuff to the safe list, so we definitely need to warn people off. We could replace the words "This method is for internal use" with the stronger wording on the @internal for that method already.

  2. +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
    @@ -21,53 +21,45 @@
    -  public function testSet($text, $message) {
    -    $returned = SafeMarkup::set($text);
    -    $this->assertTrue(is_string($returned), 'The return value of SafeMarkup::set() is really a string');
    -    $this->assertEquals($returned, $text, 'The passed in value should be equal to the string value according to PHP');
    -    $this->assertTrue(SafeMarkup::isSafe($text), $message);
    -    $this->assertTrue(SafeMarkup::isSafe($returned), 'The return value has been marked as safe');
    +  protected function safeMarkupSet($string, $strategy = 'html') {
    +    $reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
    +    $reflected_property = $reflected_class->getProperty('safeStrings');
    +    $reflected_property->setAccessible(true);
    +    $current_value = $reflected_property->getValue();
    +    $current_value[$string][$strategy] = TRUE;
    +    $reflected_property->setValue($current_value);
    +    return $string;
    ...
    -   * Tests SafeMarkup::set() and SafeMarkup::isSafe() with different providers.
    +   * Tests $this->safeMarkupSet() and SafeMarkup::isSafe() with different providers.
    

    So, I kind of get that the intent here is to test the safe list without the explicit public setter. However, it's weird to say we test a helper method on the test. Maybe it would be better to use SafeMarkup::setMultiple()?

  3. +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
    @@ -21,53 +21,45 @@
    -  public function providerSet() {
    -    // Checks that invalid multi-byte sequences are escaped.
    -    $tests[] = array("Foo\xC0barbaz", 'Foo�barbaz', 'Invalid sequence "Foo\xC0barbaz" is escaped', TRUE);
    -    $tests[] = array("Fooÿñ", 'SafeMarkup::set() does not escape valid sequence "Fooÿñ"');
    -    $tests[] = array(new TextWrapper("Fooÿñ"), 'SafeMarkup::set() does not escape valid sequence "Fooÿñ" in an object implementing __toString()');
    -    $tests[] = array("<div>", 'SafeMarkup::set() does not escape HTML');
    

    As far as I can tell we are totally losing this test coverage. We should move it to a test for SafeMarkup::setMultiple() I think.

Finally, I think the proposed commit message also needs to be updated to merge in contributors who only commented here and not on one of the children (e.g. tim.plunkett). People who helped with the CR issues were @stefan.r, @effulgentsia, @alexpott, and @lauriii and they are already covered. Thanks!

Sorry for the delay in reviewing -- sorting out the docs issues took awhile!

alexpott’s picture

  1. I agree
  2. I think using reflection in the SafeMarkupTest is absolutely fine - if we manage to do the SafeMarkup::format and t() work we can remove SafeMarkup::setMultiple() too.
  3. The invalid multi-byte sequences are checked in providerCheckPlain/testCheckPlain and the fact that set does not escape html is tested everywhere - if we remove that test we should move that stuff to the SafeMarkup::format()
ianthomas_uk’s picture

Assigned: Unassigned » ianthomas_uk

I'll do (1).

We can't just swap in setMultiple for set in 2 and 3, because setMultiple doesn't return the string.

ianthomas_uk’s picture

Assigned: ianthomas_uk » Unassigned
Status: Needs work » Needs review
FileSize
9.19 KB
1.31 KB
stefan.r’s picture

@ianthomas_uk per #57 could we replace "This method is for internal use" with "This is called by FormCache, StringTranslation and the Batch API. It should not be used anywhere else."? I think it's fine to repeat both on the method docs and in the internal notice.

stefan.r’s picture

Issue summary: View changes

updating suggested commit message to include everyone who commented in this issue

stefan.r’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
@@ -100,12 +71,29 @@ public static function isSafe($string, $strategy = 'html') {
+   * (...) For example, you should never do:
+   * @code
+   *   SafeMarkup::setMultiple(['<' => ['html' => TRUE]]);
+   * @endcode
+   * or:
+   * @code
+   *   SafeMarkup::setMultiple(['<script>' => ['all' => TRUE]]);
+   * @endcode

I think this bit is irrelevant, people should never call this method to begin with.

ianthomas_uk’s picture

#61: I prefer the text as it is now. Your suggestion makes it sound like it is fine to use setMultiple while translating strings, or during a batch operation, which is not the case. I don't think the existing documentation does that because that line starts @internal.

#63: Our audience includes developers writing for use cases we've documented. While those use cases are valid it's helpful to have this documentation as a reminder (once they are not we can just remove the function). If a contrib module does decide to use the method, against our advice, at least they might be a little safer if we keep these examples and I don't see that we gain anything by dropping them. If you're just trying to make life harder for people using the function, replace the whole docblock with "@internal Do not use" or similar.

ianthomas_uk’s picture

Status: Needs work » Needs review
xjm’s picture

@alexpott:

The invalid multi-byte sequences are checked in providerCheckPlain/testCheckPlain and the fact that set does not escape html is tested everywhere - if we remove that test we should move that stuff to the SafeMarkup::format()

Hmm, I'm not sure I agree. Testing a method that is explicitly supposed to escape things unconditionally seems different from something that is not...

Is the first item in the provider actually bogus maybe? It looks like it may have been copied from the checkPlain() one without modification (and so the $message parameter is not actually the message but the expected output from the checkPlain() provider).

However, as far as I can tell, it is not explicitly tested that setMultiple() handles objects with the __toString() (unless I missed that somewhere in the test; please tell me if so).

@ianthomas_uk:

We can't just swap in setMultiple for set in 2 and 3, because setMultiple doesn't return the string.

No, but we could test that all of these sequences are safe once set with setMultple(), which (edit) would confirm they were not altered during setting.

Also:

+++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
@@ -21,53 +21,45 @@
-   * Tests SafeMarkup::set() and SafeMarkup::isSafe() with different providers.
+   * Tests $this->safeMarkupSet() and SafeMarkup::isSafe() with different providers.

Let's at least remove the words "$this->safeMarkupSet() and"?

lauriii’s picture

It seems like it is actually not possible to make SafeMarkup::setMultiple mark a TextWrapper safe because it takes the string that is supposed to be marked as safe as an array key, but array key cannot be object.

alexpott’s picture

Status: Needs review » Needs work

@lauriii and all the other tests have equivalents elsewhere - I guess there is no harm in adding extra tests.

  1. +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
    @@ -66,0 +67,39 @@
    +      'SafeMarkup::set() does not escape valid sequence "Fooÿñ"'
    ...
    +    $tests[] = array("<div>", 'SafeMarkup::set() does not escape HTML');
    

    This should be SafeMarkup::setMultiple() ...

  2. +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
    @@ -66,0 +67,39 @@
    +    $tests[] = array(
    +      new TextWrapper("Fooÿñ"),
    +      'SafeMarkup::set() does not escape valid sequence "Fooÿñ" in an object implementing __toString()'
    +    );
    ...
    +    SafeMarkup::setMultiple([(string) $text => ['html' => TRUE]]);
    

    This is silly. There is no point in doing this.

lauriii’s picture

Status: Needs work » Needs review
FileSize
10.35 KB
1.36 KB

Ok I removed the test cases that didn't make much sense.

lauriii’s picture

alexpott’s picture

Status: Needs review » Reviewed & tested by the community

Everything from #66 has been addressed - as pointed out #67 object support is not an issue because array keys don't support objects. All other test coverage is move to a test for SafeMarkup::setMultiple().

  • xjm committed 87425f3 on 8.0.x
    Issue #2554889 by Berdir, Cottser, Daniel_Rose, JeroenT, RavindraSingh,...
xjm’s picture

Status: Reviewed & tested by the community » Fixed

Re: #67, lol doh :)

That addresses all my concerns. Committed and pushed to 8.0.x. Amazing work!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

jmuzz’s picture

Status: Closed (fixed) » Needs work

A call to SafeMarkup::set() results in a full screen error when I try to use dpm(). Try the following from drupal's root dir to find the remaining calls:

grep -r 'SafeMarkup::set(' *

My result is:

modules/libraries/tests/modules/libraries_test/libraries_test.module:    drupal_set_message(SafeMarkup::set("The <em>$group</em> callback group was invoked."));
modules/devel/devel.module:    return SafeMarkup::set($output);
modules/devel/src/Form/SettingsForm.php:      '#description' => SafeMarkup::set(t('Select the error handler(s) to use, in case you <a href="@choose">choose to show errors on screen</a>.', array('@choose' => $this->url('system.logging_settings'))) . '<ul>' .
cilefen’s picture

Status: Needs work » Closed (won't fix)

Libraries is a contrib module.

cilefen’s picture

Status: Closed (won't fix) » Closed (fixed)
rlmumford’s picture

All three of those are in contributed modules. You should raise issues on those modules http://www.drupal.org/project/devel and http://www.drupal.org/project/libraries to fix the problem.

ianthomas_uk’s picture

As is devel, which is the module that provides dpm. Check you've got the latest version, and if the problem still happens search for, then open an issue in the devel queue.

jmuzz’s picture

Oh you got me, sorry I really thought it was core.