What happens to allocated resources after throwing an Exception? - php

Exceptions are worse than goto statements, because they are going to each of the higher tires separately, to see if something would eventually catch them up; And they will left the function/method unfinished without freeing up their already allocated resources.
That's the main reason I have seen in many articles that are recommending against the use of Exceptions, mostly for C++ and Java developers.
I'm wondering if the same reason goes for PHP as well? The point regarding the PHP is that the script is gonna be finished/terminated usually within seconds from initialization. And I assume -- well, I hope; That PHP core is gonna free up all the resources that have been allocated to that particular script.
That being said, the reason that Exceptions left resources occupied wouldn't be a real concern here, because in any case all of those resources will be free soon by the time script finishes.
Is that correct or am I missing something here? If it's correct, then does that mean I can use Exceptions in PHP without being worried about Zombie Resources or they will stuck there for a while after the script terminates? Is PHP's GC mature enough to take care of those wasted resources?

PHP will free allocated memory, close resources and such when the associated variables go out of scope. That's PHP's primary mechanism for deallocation: scope. Since the scope of a function is typically very quickly exited when an exception is thrown, everything in it will be deallocated the same way as if you'd return from the function regularly. The same will also happen once the scripts ends, as you said.

Related

Replacement or equivalent to __destruct() and unset() for PHP 7+

I'm going through the journey of bringing our dating web app up to date past PHP 7+
I have been updating the depreciated code and squishing errors as they've popped up, thanks to the help of this site, and has a question in regards to our depreciated __destruct() functions.
I searched my error I was getting thrown, and found this link on github that solved my issue: https://github.com/sajari/simple-linkedin-php/issues/4
So supposedly the destruct functions break after PHP 7, and commenting them out DID fix my issue, but it left me worried.
Edit: Destruct still works, its just how my dated code was trying to
use it
I have one specific instances of the destruct being called in one of our class files that builds a job request page based on what job a user queries from our database.
/** free up memory
$tmp->__destruct();
unset($tmp);
**/
From what I can tell, everything is working fine, but I wonder what the consequences of this are. Should I replace it with some newer memory cleanup method? This app is so dated, I wonder if this clean-up is even needed anymore, or intentionally put in to stop a memory leak. My boss doesn't seem to know either.
I'm new to PHP in a professional sense, and would like to make sure this update still allows the same level of speed and usability for our clients.
Another stackoverflow question asked here: Deletion of a PHP object; also unset() and __destruct
A user answered by saying that the values are already cleared by the complete execution of a script, BUT could be explicitly cleared to stop any unintentional references.
This just lead to more questions. When that user means script, do they mean the specific function call?
To wrap this up, lets say that destruct and unset call was to stop a memory leak, what is an equivalent replacement for it?
Thanks!
I want to personally mark this question answered for my own sake. It
was extremely helpful!
$tmp->__destruct();
unset($tmp);
You should never be calling destructors directly like this. Calling unset($tmp) by itself will indirectly cause the destructor to fire when the object is removed. So, this code actually causes the destructor to be called twice, which is almost certainly not what you want.
When that user means script, do they mean the specific function call?
No, they mean that one particular PHP execution, from the first line of the first file to the last line of the last file. At the end of execution, everything is automatically freed. In PHP, this execution run usually refers to one single short web request, so explicit calls to unset() for the sake of "freeing memory" are virtually never needed because an implicit unset() is going to happen as soon as the request is done. You'd only ever have to worry about doing this manually if, for example, the $tmp object uses a massive amount of memory at the start of a request, doesn't need it for the rest of the request, and runs for a long time. If you're just calling unset() at the end of the request, it's useless.
It's most likely safe to remove both these lines. The first is redundant and the second is almost never needed.
Note, it's much more likely to use unset() to remove a variable from scope than to free memory, so take care to scan if there's some code later on that needs $tmp to not exist.

If I declare(ticks=1) but don't register a tick function, what sort of overhead does the resulting tick processing incur?

First of all - there seem to be many questions about the fundamentals of tick functionality, so I want to add the top user comment at php.net/declare to the pile for anyone looking for further information. I found it while digging around as I tried to figure out the following.
So, I'm working on writing a simple debug helper. I want to add function tracing and benchmarking - basically what tick functionality is perfect for.
Thing is, I want to enable and disable benchmarking depending on arbitrary conditions that occur during script processing. I'm not really looking for fixed debugging à la scoped declare() { ... }.
What I'm looking to do is to put declare(); at the top of my script, and then register and unregister my debugging/benchmarking (tick) function as appropriate. Un/registration won't happen (too) often, so is efficient and reasonable.
But then I got curious: when I don't have a tick function registered... does the fact that I've run declare(ticks=1); have any effect on execution efficiency? Does it cause any extra processing to become permanently enabled anyway?
Analysis of PHP(7)'s source code shows that the answer is technically yes, but I'm not yet sure how.
The answer seems to be in zend_compile.c:8200: it appears this function defers compilation processing to the appropriate routines, then if ticks are enabled it additionally emits a ZEND_TICKS opcode into the opline via zend_emit_tick() in :2167. The opcode reference page for TICKS seems consistent with this conclusion; it shows an example disassembled opcode listing which has TICKS opcodes scattered throughout it, and I was wondering how they got in there until I discovered the above.
The ZEND_TICKS handler (in zend_vm_def.h:6859) seems to call zend_ticks_function(). This is mapped to ticks_function() in zend.c:754, which is in turn mapped to php_run_ticks() in main.2013. This is finally defined in php_ticks.c, where it's all of:
void php_run_ticks(int count)
{
zend_llist_apply_with_argument(
&PG(tick_functions),
(llist_apply_with_arg_func_t) php_tick_iterator,
&count
);
}
Huh. Not bad.
But here's the thing. If I declare(ticks=1);, the above dispatch is being run for literally every statement executed. That's... ouch. For long-running scripts containing high-iteration-count, tight processing loops, I'm wondering how badly that'll add up.
Problem is, I'm not even sure how to benchmark this. The only way I could envisage to do so would be to synthesize some PHP bytecode and then figure out a way to inject that directly into the PHP bytecode interpreter.
And that leads to my question: how much of a performance impact does this additional dispatch have, in practice? How can I quantify it?
Obviously the above investigation was performed on the canonical PHP.net interpreter. I haven't looked into how HHVM does this at all (yet), but I wouldn't at all mind learning how it handles it.

PHP: closing sessions earlier in script = will it help a lot or a little in terms of performance?

Was wondering if it helps significantly in terms of performance and specially memory to close sessions as soon as you're done using them, usually in my case, at the top of the script.. I rarely need it open midway and onwards in my script, however I have been used to just leaving sessions open in case i needed it anywhere down the lines, and let the php auto close it at end of script = assuming this doesn't really cost much in terms of performance, if any.
Any ideas?
For a small application keeping the session open is okay. But for a big application with time intensive operation, this can pull down the performance of the application.

Security implications of ignore_user_abort() function

Has PHP's ignore_user_abort() function any security implication?
I'm thinking in DoS. For example, when having the function exposed to anonymous traffic in some code that is resource expensive.
As addition to the previous answer I'd like to add that the risk is not bigger, but is being shifted a little.
If the goal is to overload the server by calling an expensive script a lot of times, it is clear that calling ignore_user_abort(true); relieves the attacker from the need to keep the connection open. The script will continue to execute nevertheless of the connection status and consume resources.
In contrast without ignore_user_abort(true); the script would end its execution on the first output (if there happens no output the script will be as consuming as the first variant [1]).
In case of a DoS attack (and especially a DDoS attack) the attacker likely has absolutely no problem in opening (and holding open) a lot of connections. Therefore from this perspective ignore_user_abort makes no difference.
I can't think of any further security related implications of using this functionality.
I would even claim that most PHP developers do not really know that the execution of their scripts might stop somewhere in the middle just because the connection is lost. I think most would guess that their scripts will execute until the end in all cases although this is not the default setting.
I don't see any direct security implications with ignore_user_abort() function .
In terms of DoS attack , considering the containing script is
resource expensive
exposed to anonymous traffic
the concern should be of server overload which could lead to temporary or indefinite interruption or suspension of services .
If possible it would be wise to find alternatives for such a resource expensive code :
If the containing script is used to simulate cron task , it would be wise to use crontab instead .
If possible it would be wise to put programmatic restriction in place to run only one instance of such resource expensive code irrespective of how many page hits the containing script would get .
Hopefully this is of some help .

Have PHP dump heap on OutOfMemory exception

I am currently debugging a script that constantly runs into OutOfMemory exceptions. It is run as a cronjob and usually runs fine, but when the cronjob wasn't run for a while (for whatever reason) the script has to handle to many elements that queued up and will run into a OutOfMemory exception.
From examining the code I was not able to spot the problem. I believe one of the iterative function calls might leak memory, but I am not sure which one and where.
Is there an option to get PHP to dump the heap, when an OutOfMemory exception occurs? I might be able to spot the problem from there (most likely).
While I was not able to find a "dump heap on Exception" option, I did find get_defined_vars() which is basically a heap dump if called from a global scope. Using this I was able to see that there where hundreds (actually thousands) of still referenced database rows hanging around in my memory. This was due to a not freed mysql result resource somewhere in the infamous function that caused the leak. I found it and fixed it. It runs well now.
Well, easiest approach would be to use a try-catch block around that part of your script where the error possibly occurs and you will have to dump the stack in the catch part. The problem might be that the machine won't be able to react cause the memory is full and it terminates. I do not know if it helps to discard some variables to free up some memory to output some data.
EDIT: For this purpose use the php function debug-backtrace. This will give you a stack trace. So finding the error will be much likely in case the machine is still up.
Just do not load all objects together to memory, but read-as-you-process-them?
I've had lots of problems with simpleXML and memory leaks. They are a pain in the are to track down... took me days to figure out that simpleXML was causing then and then fix them.
As far as i know you cand programatically set a handled for OOM:)
Also, PHP's functions for displaying memory info fails to detect the memory leaks, i had scripts eating up ~1Gb of ram, but PHP's functions reported only 100Mb used:)
This is as good of a 'heap dump' as I'm able to quickly write in PHP. I take the defined variables and functions, then sort by their serialized length. Serialized length isn't a 100% reliable method for getting a variable's size, but it's pretty good, and generally useful for determining which objects are your memory hogs:
$memmap = array_map(function($var) { return strlen(serialize($var)); },
array_merge(get_defined_functions(), get_defined_vars()));
arsort($memmap);
var_dump($memmap);
You may want to tweak the callback function a bit if you'd like your results to be more verbose, or to recurse through the defined variables.
I've never seen PHP provide a native facility for this but a few other things might exist:
Try: https://github.com/mcfunley/php-heap/blob/master/php-heap.py
It could also be possible to write an extension to achieve the same.

Categories