Index: ogr/ogrsf_frmts/shape/shpopen.c
===================================================================
--- ogr/ogrsf_frmts/shape/shpopen.c	(révision 13775)
+++ ogr/ogrsf_frmts/shape/shpopen.c	(copie de travail)
@@ -1494,7 +1494,9 @@
 SHPReadObject( SHPHandle psSHP, int hEntity )
 
 {
+    int                  nEntitySize, nRequiredSize;
     SHPObject		*psShape;
+    char                 pszErrorMsg[128];
 
 /* -------------------------------------------------------------------- */
 /*      Validate the record/entity number.                              */
@@ -1505,27 +1507,39 @@
 /* -------------------------------------------------------------------- */
 /*      Ensure our record buffer is large enough.                       */
 /* -------------------------------------------------------------------- */
-    if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )
+    nEntitySize = psSHP->panRecSize[hEntity]+8;
+    if( nEntitySize > psSHP->nBufSize )
     {
-	psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
-	psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
+	psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
         if (psSHP->pabyRec == NULL)
         {
             char szError[200];
 
+            /* Reallocate previous successfull size for following features */
+            psSHP->pabyRec = malloc(psSHP->nBufSize);
+
             sprintf( szError, 
                      "Not enough memory to allocate requested memory (nBufSize=%d). "
                      "Probably broken SHP file", psSHP->nBufSize );
             psSHP->sHooks.Error( szError );
             return NULL;
         }
+
+        /* Only set new buffer size after successfull alloc */
+	psSHP->nBufSize = nEntitySize;
     }
 
+    /* In case we were not able to reallocate the buffer on a previous step */
+    if (psSHP->pabyRec == NULL)
+    {
+        return NULL;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Read the record.                                                */
 /* -------------------------------------------------------------------- */
     if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 
-        || psSHP->sHooks.FRead( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, 
+        || psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, 
                   psSHP->fpSHP ) != 1 )
     {
         /*
@@ -1544,7 +1558,16 @@
     psShape->nShapeId = hEntity;
     psShape->bMeasureIsUsed = FALSE;
 
+    if ( 8 + 4 > nEntitySize )
+    {
+        snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
+                    hEntity, nEntitySize); 
+        psSHP->sHooks.Error( pszErrorMsg );
+        SHPDestroyObject(psShape);
+        return NULL;
+    }
     memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
+
     if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
 
 /* ==================================================================== */
@@ -1560,6 +1583,14 @@
 	int32		nPoints, nParts;
 	int    		i, nOffset;
 
+        if ( 40 + 8 + 4 > nEntitySize )
+        {
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
+                     hEntity, nEntitySize); 
+            psSHP->sHooks.Error( pszErrorMsg );
+            SHPDestroyObject(psShape);
+            return NULL;
+        }
 /* -------------------------------------------------------------------- */
 /*	Get the X/Y bounds.						*/
 /* -------------------------------------------------------------------- */
@@ -1583,15 +1614,38 @@
 	if( bBigEndian ) SwapWord( 4, &nPoints );
 	if( bBigEndian ) SwapWord( 4, &nParts );
 
-        if (nPoints < 0 || nParts < 0)
+        if (nPoints < 0 || nParts < 0 ||
+            nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
         {
-#ifdef USE_CPL
-            CPLError(CE_Failure, CPLE_AppDefined,
-                     "nPoints=%d, nParts=%d : bad value(s). Probably broken SHP file", nPoints, nParts );
-#endif
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
+                        hEntity, nPoints, nParts);
+            psSHP->sHooks.Error( pszErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
+        
+        /* With the previous checks on nPoints and nParts, */
+        /* we should not overflow here and after */
+        /* since 50 M * (16 + 8 + 8) = 1 600 MB */
+        nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
+        if ( psShape->nSHPType == SHPT_POLYGONZ
+            || psShape->nSHPType == SHPT_ARCZ
+            || psShape->nSHPType == SHPT_MULTIPATCH )
+        {
+            nRequiredSize += 16 + 8 * nPoints;
+        }
+        if( psShape->nSHPType == SHPT_MULTIPATCH )
+        {
+            nRequiredSize += 4 * nParts;
+        }
+        if (nRequiredSize > nEntitySize)
+        {
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
+                        hEntity, nPoints, nParts, nEntitySize);
+            psSHP->sHooks.Error( pszErrorMsg );
+            SHPDestroyObject(psShape);
+            return NULL;
+        }
 
 	psShape->nVertices = nPoints;
         psShape->padfX = (double *) calloc(nPoints,sizeof(double));
@@ -1610,11 +1664,10 @@
             psShape->panPartStart == NULL ||
             psShape->panPartType == NULL)
         {
-#ifdef USE_CPL
-            CPLError(CE_Failure, CPLE_AppDefined,
-                     "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d). "
-                     "Probably broken SHP file", nPoints, nParts );
-#endif
+            snprintf(pszErrorMsg, 128,
+                     "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
+                     "Probably broken SHP file", hEntity, nPoints, nParts );
+            psSHP->sHooks.Error( pszErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
@@ -1629,6 +1682,25 @@
 	for( i = 0; i < nParts; i++ )
 	{
 	    if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
+
+            /* We check that the offset is inside the vertex array */
+            if (psShape->panPartStart[i] < 0 ||
+                psShape->panPartStart[i] >= psShape->nVertices)
+            {
+                snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
+                         hEntity, i, psShape->panPartStart[i], psShape->nVertices); 
+                psSHP->sHooks.Error( pszErrorMsg );
+                SHPDestroyObject(psShape);
+                return NULL;
+            }
+            if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
+            {
+                snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
+                         hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]); 
+                psSHP->sHooks.Error( pszErrorMsg );
+                SHPDestroyObject(psShape);
+                return NULL;
+            }
 	}
 
 	nOffset = 44 + 8 + 4*nParts;
@@ -1695,7 +1767,7 @@
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
+        if( nEntitySize >= nOffset + 16 + 8*nPoints )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
@@ -1723,18 +1795,40 @@
 	int32		nPoints;
 	int    		i, nOffset;
 
+        if ( 44 + 4 > nEntitySize )
+        {
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
+                     hEntity, nEntitySize); 
+            psSHP->sHooks.Error( pszErrorMsg );
+            SHPDestroyObject(psShape);
+            return NULL;
+        }
 	memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
+
 	if( bBigEndian ) SwapWord( 4, &nPoints );
 
-        if (nPoints < 0)
+        if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
         {
-#ifdef USE_CPL
-            CPLError(CE_Failure, CPLE_AppDefined,
-                     "nPoints=%d : bad value. Probably broken SHP file", nPoints );
-#endif
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d",
+                     hEntity, nPoints); 
+            psSHP->sHooks.Error( pszErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
+
+        nRequiredSize = 48 + nPoints * 16;
+        if( psShape->nSHPType == SHPT_MULTIPOINTZ )
+        {
+            nRequiredSize += 16 + nPoints * 8;
+        }
+        if (nRequiredSize > nEntitySize)
+        {
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
+                     hEntity, nPoints, nEntitySize); 
+            psSHP->sHooks.Error( pszErrorMsg );
+            SHPDestroyObject(psShape);
+            return NULL;
+        }
         
 	psShape->nVertices = nPoints;
         psShape->padfX = (double *) calloc(nPoints,sizeof(double));
@@ -1747,11 +1841,10 @@
             psShape->padfZ == NULL ||
             psShape->padfM == NULL)
         {
-#ifdef USE_CPL
-            CPLError(CE_Failure, CPLE_AppDefined,
-                     "Not enough memory to allocate requested memory (nPoints=%d). "
-                     "Probably broken SHP file", nPoints );
-#endif
+            snprintf(pszErrorMsg, 128,
+                     "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
+                     "Probably broken SHP file", hEntity, nPoints );
+            psSHP->sHooks.Error( pszErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
@@ -1807,7 +1900,7 @@
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
+        if( nEntitySize >= nOffset + 16 + 8*nPoints )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
@@ -1840,6 +1933,14 @@
         psShape->padfZ = (double *) calloc(1,sizeof(double));
         psShape->padfM = (double *) calloc(1,sizeof(double));
 
+        if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
+        {
+            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
+                     hEntity, nEntitySize); 
+            psSHP->sHooks.Error( pszErrorMsg );
+            SHPDestroyObject(psShape);
+            return NULL;
+        }
 	memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
 	memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
 
@@ -1866,7 +1967,7 @@
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )
+        if( nEntitySize >= nOffset + 8 )
         {
             memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
         

