-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Handle libxml2 OOM more consistently #11927
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
Conversation
Looks like this also got rid of the last use of PHP_ERR (which is non-standard, and vague). |
More weirdness: this got rid of the last way to return false from php-src/ext/dom/domimplementation.c Lines 161 to 167 in 620b622
Notice the hardcoded |
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.
LGTM, I suppose the PHP_ERR constant can be added to the deprecation chop board.
xmlFreeNode(nodep); | ||
php_dom_throw_error(errorcode, dom_get_strict_error(intern->document)); | ||
RETURN_FALSE; |
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.
Probably makes sense to rewrite this code prior to the if(errorcode == 0)
and use this as a guard as the only other case that seems to fail as far as I can see is on line 862.
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.
There's also nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
that has an out-parameter that can set the errorcode
. And on line 844 the error code can also be set initially. I think I'm going to keep it as-is because it has a single easy-to-spot error handling block for the errorcode
this way.
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.
Right 👍
if (errorcode != 0) { | ||
if (nodep != NULL) { | ||
xmlFreeProp((xmlAttrPtr) nodep); | ||
} | ||
xmlFreeProp((xmlAttrPtr) nodep); | ||
php_dom_throw_error(errorcode, dom_get_strict_error(intern->document)); | ||
RETURN_FALSE; | ||
} |
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.
Same comment
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.
Same reply as above ^^ :)
Probably? I need to go I'll have another think |
Okay, I think the throw is correct for Looking at the spec, the interesting part is step 3, which says:
And considering the implementation is simply:
However, this can only return false if the DOM document sets It seems the |
Hmm. The first step of
Yeah it would be a lot easier for sure. I'm not sure this is an easy deprecation though, I have no idea about how widely people use this. As a side note, we must be careful deprecating things that were removed for the live spec. The current live spec basically only takes into account HTML. So XML properties such as |
Sorry, I clearly am not awake anymore. True facepalm moment here. |
Sorry for asking this question in between: reading all these comments I get the feeling DOM could run out-of-memory but PHP would still work (and handle this error) without running out of memory itself? is PHP Userland code expected to handle a possible DOM out-of-memory error? |
In theory yes, as the ext/dom memory usage does not count against the PHP memory limit (due to limitations with libxml not allowing to pass a custom allocator). So an allocation could fail, return false/throw an exception and pass back to PHP if it hasn't reached its own memory limit. |
In theory they should be handled. In practice, if you're OOM in libxml2, then you're probably screwed anyway because the system allocator ran out of memory. Similarly for other libraries that PHP uses under the hood. The goal is unifying all of the OOM conditions into exceptions is to make the return value semantics easier, and more correct w.r.t. the DOM spec. Exceptions will also make sure you can more easily gracefully shut down the request, which should probably be what happens when you run out of memory. |
I see thx. the same is true for preg_* then, right? |
@Girgias do I change the return type of |
That memory is also allocated via the system allocator, so you're probably screwed there too if you run OOM. |
Would not make this change and leave it for later as currently it's not even a tentative type. But maybe @kocsismate can clarify? |
@@ -693,14 +694,13 @@ int dom_node_prefix_write(dom_object *obj, zval *newval) | |||
} | |||
if (ns == NULL) { | |||
ns = xmlNewNs(nsnode, nodep->ns->href, (xmlChar *)prefix); | |||
if (UNEXPECTED(ns == NULL)) { |
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.
Note to self: recheck if OOM is the only way in this path that this can return NULL.
@@ -172,7 +172,8 @@ PHP_METHOD(DOMImplementation, createDocument) | |||
if (localname != NULL) { | |||
xmlFree(localname); | |||
} | |||
RETURN_FALSE; | |||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true); |
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.
This makes it possible to add the tentative DOMDocument
return type :)
This is a continuation of commit c2a58ab, in which several OOM error handling was converted to throwing an INVALID_STATE_ERR DOMException. Some places were missed and they still returned false without an exception, or threw a PHP_ERR DOMException. Convert all of these to INVALID_STATE_ERR DOMExceptions. This also reduces confusion of users going through documentation [1]. Unfortunately, not all node creations are checked for a NULL pointer. Some places therefore will not do anything if an OOM occurs (well, except crash). On the one hand it's nice to handle these OOM cases. On the other hand, this adds some complexity and it's very unlikely to happen in the real world. But then again, "unlikely" situations have caused trouble before. Ideally all cases should be checked. [1] php/doc-en#1741
See php/doc-en#1741 for some background
This is a continuation of commit c2a58ab, in which several OOM error handling was converted to throwing an INVALID_STATE_ERR DOMException. Some places were missed and they still returned false without an exception, or threw a PHP_ERR DOMException.
Convert all of these to INVALID_STATE_ERR DOMExceptions. This also reduces confusion of users going through documentation [1].
Unfortunately, not all node creations are checked for a NULL pointer. Some places therefore will not do anything if an OOM occurs (well, except crash).
On the one hand it's nice to handle these OOM cases. On the other hand, this adds some complexity and it's very unlikely to happen in the real world. But then again, "unlikely" situations have caused trouble before. Ideally all cases should be checked.
[1] php/doc-en#1741
NOTE: since we don't handle all OOM cases, maybe the wording in UPGRADING should be relaxed.