The docs say that drupal_render() will pass a renderable array to theme() if #theme is set and in this case it is the responsibility of the theme function called to render children as required.
Currently drupal_render() does this:
// Call the element's #theme function if it is set. Then any children of the
// element have to be rendered there. If the internal #render_children
// property is set, do not call the #theme function to prevent infinite
// recursion.
if (isset($elements['#theme']) && !isset($elements['#render_children'])) {
$elements['#children'] = theme($elements['#theme'], $elements);
}
// If #theme was not set and the element has children, render them now.
// This is the same process as drupal_render_children() but is inlined
// for speed.
if ($elements['#children'] === '') {
foreach ($children as $key) {
$elements['#children'] .= drupal_render($elements[$key]);
}
}
The problem is that if theme() returns an empty string for some reason, drupal_render() then ignores the theme function's decision to not render the children elements and tries to go ahead and recursively render the children anyway.