Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does PHP strlen() return negative length?

strlen($str) is returning negative values for a "huge string" that is created using str_repeat:

<?php

error_reporting(E_STRICT|E_ALL);
echo phpversion(); // 5.3.26
echo PHP_INT_MAX; // 9223372036854775807
ini_set('memory_limit', '-1');
ini_set('max_execution_time', 0);

$gb = 1024 * 1024 * 1024;
$str = str_repeat('a', 2 * $gb);
echo strlen($str); // gives int(-2147483648)
echo $str[0]; // Notice: Uninitialized string offset: 0

$str2 = str_repeat('a', 4 * $gb);
echo strlen($str2); // gives int(0)

$str3 = str_repeat('a', 123 + 4 * $gb);
echo strlen($str3); // gives int(123)

$str4 = str_repeat('a', 6 * $gb); // starts to wrap again...
echo strlen($str4); // gives int(-2147483648)
echo $str4[0]; // Notice: Uninitialized string offset: 0

$str5 = str_repeat('a', 123 + 8 * $gb);
echo strlen($str5); // gives int(123)

?>

Is this behavior defined?

Or is this a PHP bug?

like image 624
Pacerier Avatar asked Jul 10 '13 16:07

Pacerier


2 Answers

string can be as large as 2GB.

It looks like it is in fact (2GB - 1). This works fine on my x64 box:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024 -1);
echo $str[0];

... while this breaks:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024);
echo $str[0];

What you are doing is simply undefined, and the manual should be corrected. I would have expected a warning too.

Interestingly, this raises a fatal error:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024 -2); // 2GB - 2 bytes
$str .= 'b'; // ok
$str .= 'c'; // PHP Fatal error:  String size overflow


Update:

The bug report has been attended to. Documentation on php.net has been fixed and now writes "2147483647 bytes maximum".

like image 50
RandomSeed Avatar answered Oct 02 '22 14:10

RandomSeed


I suppose you're simply overflowing an int with your large string. From a manual:

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.

So it should be OK if your string size can fit into int.

like image 34
Jk1 Avatar answered Oct 02 '22 13:10

Jk1