Skip to content

Commit 0dd057d

Browse files
committed
PHPC-849: Fix leaking of current element in setTypeMap()
1 parent 8033c1b commit 0dd057d

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/MongoDB/Cursor.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,23 @@ PHP_METHOD(Cursor, setTypeMap)
227227
return;
228228
}
229229

230+
/* Check if the existing element needs to be freed before we overwrite
231+
* visitor_data, which contains the only reference to it. */
232+
if (!Z_ISUNDEF(intern->visitor_data.zchild)) {
233+
php_phongo_cursor_free_current(intern);
234+
}
235+
230236
phongo_bson_typemap_to_state(typemap, &state.map TSRMLS_CC);
231237

232238
intern->visitor_data = state;
239+
240+
/* If the cursor has a current element, we just freed it and should restore
241+
* it with a new type map applied. */
242+
if (mongoc_cursor_current(intern->cursor)) {
243+
const bson_t *doc = mongoc_cursor_current(intern->cursor);
244+
245+
phongo_bson_to_zval_ex(bson_get_data(doc), doc->len, &intern->visitor_data);
246+
}
233247
}
234248
/* }}} */
235249

tests/cursor/bug0849-001.phpt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
PHPC-849: Cursor::setTypeMap() leaks current element if called during iteration
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
$manager = new MongoDB\Driver\Manager(STANDALONE);
10+
11+
$bulk = new MongoDB\Driver\BulkWrite();
12+
$bulk->insert(['_id' => 1]);
13+
$bulk->insert(['_id' => 2]);
14+
$bulk->insert(['_id' => 3]);
15+
$manager->executeBulkWrite(NS, $bulk);
16+
17+
$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([]));
18+
$cursor->setTypeMap(['root' => 'stdClass']);
19+
20+
foreach ($cursor as $i => $document) {
21+
// Type map will apply to the next iteration, since current element is already converted
22+
$cursor->setTypeMap(['root' => ($i % 2 ? 'stdClass' : 'array')]);
23+
var_dump($document);
24+
}
25+
26+
?>
27+
===DONE===
28+
<?php exit(0); ?>
29+
--EXPECTF--
30+
object(stdClass)#%d (%d) {
31+
["_id"]=>
32+
int(1)
33+
}
34+
array(1) {
35+
["_id"]=>
36+
int(2)
37+
}
38+
object(stdClass)#%d (%d) {
39+
["_id"]=>
40+
int(3)
41+
}
42+
===DONE===

0 commit comments

Comments
 (0)