Index: src/wp-includes/class-wp-query.php
===================================================================
--- src/wp-includes/class-wp-query.php	(revision 55419)
+++ src/wp-includes/class-wp-query.php	(working copy)
@@ -1964,18 +1964,20 @@
 			}
 		}
 		$post_type = $q['post_type'];
-		if ( empty( $q['posts_per_page'] ) ) {
-			$q['posts_per_page'] = get_option( 'posts_per_page' );
+		if( isset( $q['posts_per_page'] ) && ( is_numeric( $q['posts_per_page'] ) || is_bool( $q['posts_per_page'] ) ) ) {
+			$q['posts_per_page'] = $q['posts_per_page'];
+		} else {
+			$q['posts_per_page'] = get_option( 'posts_per_page', 10 );
 		}
-		if ( isset( $q['showposts'] ) && $q['showposts'] ) {
+		if( isset( $q['showposts'] ) && $q['showposts'] ) {
 			$q['showposts']      = (int) $q['showposts'];
 			$q['posts_per_page'] = $q['showposts'];
 		}
-		if ( ( isset( $q['posts_per_archive_page'] ) && 0 != $q['posts_per_archive_page'] ) && ( $this->is_archive || $this->is_search ) ) {
+		if ( isset( $q['posts_per_archive_page'] ) && ( is_numeric( $q['posts_per_archive_page'] ) || is_bool( $q['posts_per_archive_page'] ) ) && ( $this->is_archive || $this->is_search ) ) {
 			$q['posts_per_page'] = $q['posts_per_archive_page'];
 		}
 		if ( ! isset( $q['nopaging'] ) ) {
-			if ( -1 == $q['posts_per_page'] ) {
+			if ( -1 == (int) $q['posts_per_page'] ) {
 				$q['nopaging'] = true;
 			} else {
 				$q['nopaging'] = false;
@@ -1994,8 +1996,6 @@
 		$q['posts_per_page'] = (int) $q['posts_per_page'];
 		if ( $q['posts_per_page'] < -1 ) {
 			$q['posts_per_page'] = abs( $q['posts_per_page'] );
-		} elseif ( 0 == $q['posts_per_page'] ) {
-			$q['posts_per_page'] = 1;
 		}
 
 		if ( ! isset( $q['comments_per_page'] ) || 0 == $q['comments_per_page'] ) {
@@ -3589,7 +3589,7 @@
 		 */
 		$this->found_posts = (int) apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
 
-		if ( ! empty( $limits ) ) {
+		if ( ! empty( $limits ) && 0 != $q['posts_per_page'] ) {
 			$this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
 		}
 	}
Index: tests/phpunit/tests/query/postsPerPage.php
===================================================================
--- tests/phpunit/tests/query/postsPerPage.php	(nonexistent)
+++ tests/phpunit/tests/query/postsPerPage.php	(working copy)
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @group query
+ */
+class Tests_Query_PostsPerPage extends WP_UnitTestCase {
+	public $q;
+
+	public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
+		// More than posts_per_page default of 10
+		// This number is verified in the 'test_posts_per_page_all' method.
+		self::factory()->post->create_many( 11 );
+	}
+
+	public function set_up() {
+		parent::set_up();
+		unset( $this->q );
+		$this->q = new WP_Query();
+	}
+
+	public function _get_post_count( $args = array() ) {
+		$args = wp_parse_args(
+			$args,
+			array(
+				'fields' => 'ids',
+			)
+		);
+
+		return count( $this->q->query( $args ) );
+	}
+
+	public function test_posts_per_page_integer_positive() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => 2,
+		) );
+
+		$this->assertSame( 2, $count );
+	}
+
+	/**
+	 * @ticket 24142
+	 */
+	public function test_posts_per_page_integer_zero() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => 0,
+		) );
+
+		$this->assertSame( 0, $count );
+	}
+
+	public function test_posts_per_page_string_numeric() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => '2',
+		) );
+
+		$this->assertSame( 2, $count );
+	}
+
+	public function test_posts_per_page_string_non_numeric() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => 'foo',
+		) );
+
+		$this->assertSame( 10, $count );
+	}
+
+	public function test_posts_per_page_boolean_true() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => true,
+		) );
+
+		$this->assertSame( 1, $count );
+	}
+
+	/**
+	 * @ticket 24142
+	 */
+	public function test_posts_per_page_boolean_false() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => false,
+		) );
+
+		$this->assertSame( 0, $count );
+	}
+
+	public function test_posts_per_page_null() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => null,
+		) );
+
+		$this->assertSame( 10, $count );
+	}
+
+	public function test_posts_per_page_empty_string() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => null,
+		) );
+
+		$this->assertSame( 10, $count );
+	}
+
+	public function test_posts_per_page_array() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => array(),
+		) );
+
+		$this->assertSame( 10, $count );
+	}
+
+	public function test_posts_per_page_negative() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => -2,
+		) );
+
+		$this->assertSame( 2, $count );
+	}
+
+	public function test_posts_per_page_all() {
+		$count = $this->_get_post_count( array(
+			'posts_per_page' => -1,
+		) );
+
+		$this->assertSame( 11, $count );
+	}
+}
\ No newline at end of file
