Bug #70275 [Asn]: On recursion error, json_encode can eat up all system memory

From: Date: Mon, 16 May 2016 19:10:36 +0000
Subject: Bug #70275 [Asn]: On recursion error, json_encode can eat up all system memory
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-201139@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=70275&edit=1 ID: 70275 Updated by: bukka@php.net Reported by: royanee at gmail dot com Summary: On recursion error, json_encode can eat up all system memory Status: Assigned Type: Bug Package: JSON related PHP Version: 5.6.12 Assigned To: bukka Block user comment: N Private report: N New Comment: This is caused by the fact that parsing is not stopped internally when the first error (recursion in this case) is found. To fix this we will have to add a return check to all calls in encoder and allow php_json_encode to fill buffer with incomplete json. Ideally the php_json_encode will be changed to return value indicating that there is an error or all is ok (FAILURE or SUCCESS) instead of void. This can't go to bugfixing release and will have to wait for the next minor. Previous Comments: ------------------------------------------------------------------------ [2015-08-14 23:14:23] royanee at gmail dot com Description: ------------ When json_encode encounters recursion or other errors it will return false (as long as you are not using the largely undocumented constant JSON_PARTIAL_OUTPUT_ON_ERROR). Unfortunately, it waits until after it has processed all of the data to return the error. This was a problem for me when I was attempting to export an application state in JSON. As I was using the CLI, it ate up all of the system memory and at best it would have returned false if I could have waited an eternity for it to finish. I've included a test script with a nice handful of circular object references. Test script: --------------- $max_num_objects = 20; for ($num_objects = 5; $num_objects <= $max_num_objects; $num_objects++) { echo PHP_EOL . 'Number of Objects: ' . $num_objects . PHP_EOL; // Create the objects and link them to each other. $objects = new stdClass; for ($i = 0; $i < $num_objects; $i++) { $objects->$i = new stdClass; } for ($i = 0; $i < $num_objects; $i++) { for ($j = 0; $j < $num_objects; $j++) { if ($i != $j) { $objects->$i->$j = $objects->$j; } } } $starttime = microtime(true); serialize($objects); echo '$objects serialize: ' . number_format(microtime(true) - $starttime, 3) . ' seconds' . PHP_EOL; $starttime = microtime(true); if (json_encode($objects) === FALSE) { echo 'JSON Error #' . json_last_error() . ': ' . json_last_error_msg() . PHP_EOL; } echo '$objects json_encode: ' . number_format(microtime(true) - $starttime, 3) . ' seconds' . PHP_EOL; } Expected result: ---------------- Finishes in less than a second, ideally in a negligible amount of time. Example: ... Number of Objects: 10 $objects serialize: 0.000 seconds JSON Error #6: Recursion detected $objects json_encode: 0.000 seconds Actual result: -------------- ... Number of Objects: 10 $objects serialize: 0.000 seconds JSON Error #6: Recursion detected $objects json_encode: 7.227 seconds ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=70275&edit=1

« previous php.bugs (#201139) next »