--- stsoundlib/Ymload.cpp.orig	2016-07-26 16:04:42 UTC
+++ stsoundlib/Ymload.cpp
@@ -51,61 +51,98 @@ static	void	signeSample(ymu8 *ptr,yms32 
 		}
 }
 
-char	*mstrdup(char *in)
+void	myFree(void **pPtr)
+{
+		if (*pPtr) free(*pPtr);
+		*pPtr = NULL;
+}
+
+char	*mstrdup(const char *in)
 {
 		char *out = (char*)malloc(strlen(in)+1);
 		if (out) strcpy(out,in);
 		return out;
 }
 
-ymu32      readMotorolaDword(ymu8 **ptr)
+ymu32      readMotorolaDword(ymu8 **ptr, ymint *ptr_size)
 {
-ymu32 n;
+ymu32 n = 0;
 ymu8 *p = *ptr;
-
-        n = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-        p+=4;
-        *ptr = p;
+	if (*ptr_size>=4)
+	{	
+	        n = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+        	p+=4;
+	        *ptr = p;
+	}
+	(*ptr_size)+=4;
         return n;
 }
 
-ymu16      readMotorolaWord(ymu8 **ptr)
+ymu16      readMotorolaWord(ymu8 **ptr, ymint *ptr_size)
 {
-ymu16 n;
+ymu16 n = 0;
 ymu8 *p = *ptr;
-
-        n = (p[0]<<8)|p[1];
-        p+=2;
-        *ptr = p;
+	if (*ptr_size>=2)
+	{
+	        n = (p[0]<<8)|p[1];
+        	p+=2;
+	        *ptr = p;
+	}
+	(*ptr_size)+=2;
         return n;
 }
 
-ymchar    *readNtString(ymchar **ptr)
+ymchar    *readNtString(ymchar **ptr, ymint *ptr_size)
 {
 ymchar *p;
+ymint len = 0;
 
-		p = mstrdup(*ptr);
-		(*ptr) += strlen(*ptr)+1;
+	if (*ptr_size<=0)
+	{
+		(*ptr_size)-=1;
+		return mstrdup("");
+	}
+	p=*ptr;
+	while(!*p)
+	{
+		p++;
+		ptr_size--;
+		len++;
+		if (*ptr_size==0)
+		{
+			(*ptr_size)-=1;
+			return mstrdup("");
+		}
+	}
+
+	p = mstrdup(*ptr);
+	(*ptr) += len+1;
         return p;
 }
 
-yms32	ReadLittleEndian32(ymu8 *pLittle)
+yms32	ReadLittleEndian32(ymu8 *pLittle, ymint ptr_size)
 {
-	yms32 v = ( (pLittle[0]<<0) |
+	yms32 v = 0;
+	if (ptr_size>=4)
+	{	
+		v = ( (pLittle[0]<<0) |
 				(pLittle[1]<<8) |
 				(pLittle[2]<<16) |
 				(pLittle[3]<<24));
-
+	}
 	return v;
 }
 
-yms32	ReadBigEndian32(ymu8 *pBig)
+yms32	ReadBigEndian32(ymu8 *pBig, ymint ptr_size)
 {
-	yms32 v = ( (pBig[0]<<24) |
+	yms32 v = 0;
+	if (ptr_size>=4)
+	{
+		v = ( (pBig[0]<<24) |
 				(pBig[1]<<16) |
 				(pBig[2]<<8) |
-				(pBig[3]<<0));
-
+		 		(pBig[3]<<0));
+	}
 	return v;
 }
 
@@ -114,6 +151,13 @@ unsigned char	*CYmMusic::depackFile(void
  lzhHeader_t *pHeader;
  ymu8	*pNew;
  ymu8	*pSrc;
+ ymint	ptr_left = fileSize;
+ ymint  dummy;
+
+		if (ptr_left < (ymint)sizeof(lzhHeader_t))
+		{
+			return pBigMalloc;
+		}
 
 		pHeader = (lzhHeader_t*)pBigMalloc;
 
@@ -123,8 +167,6 @@ unsigned char	*CYmMusic::depackFile(void
 			return pBigMalloc;
 		}
 
-		fileSize = (ymu32)-1;
-
 		if (pHeader->level != 0)					// NOTE: Endianness works because value is 0
 		{ // Compression LH5, header !=0 : Error.
 			free(pBigMalloc);
@@ -133,7 +175,8 @@ unsigned char	*CYmMusic::depackFile(void
 			return NULL;
 		}
 
-		fileSize = ReadLittleEndian32((ymu8*)&pHeader->original);
+		dummy = 4;
+		fileSize = ReadLittleEndian32((ymu8*)&pHeader->original, dummy);
 		pNew = (ymu8*)malloc(fileSize);
 		if (!pNew)
 		{
@@ -144,10 +187,20 @@ unsigned char	*CYmMusic::depackFile(void
 		}
 
 		pSrc = pBigMalloc+sizeof(lzhHeader_t)+pHeader->name_lenght;			// NOTE: Endianness works because name_lenght is a byte
+		ptr_left -= sizeof(lzhHeader_t)+pHeader->name_lenght;
 
 		pSrc += 2;		// skip CRC16
+		ptr_left -= 2;
 
-		const int		packedSize = ReadLittleEndian32((ymu8*)&pHeader->packed);
+		dummy = 4;
+		const int		packedSize = ReadLittleEndian32((ymu8*)&pHeader->packed, dummy);
+
+		if (packedSize > ptr_left)
+		{
+			setLastError("File too small");
+			free(pNew);
+			return pBigMalloc;
+		}
 
 		// alloc space for depacker and depack data
 		CLzhDepacker *pDepacker = new CLzhDepacker;	
@@ -229,19 +282,29 @@ ymbool	CYmMusic::ymDecode(void)
  {
  ymu8 *pUD;
  ymu8	*ptr;
+ ymint ptr_size = fileSize;
  ymint skip;
  ymint i;
  ymu32 sampleSize;
  yms32 tmp;
  ymu32 id;
- 
 
-		id = ReadBigEndian32((unsigned char*)pBigMalloc);
+		if (ptr_size < 4)
+		{ 
+			setLastError("File too small");
+			return YMFALSE;
+		}
+		id = ReadBigEndian32((unsigned char*)pBigMalloc, ptr_size);
 		switch (id)
 		{
-			case 'YM2!':		// MADMAX specific.
+			case 0x594d3221 /*'YM2!'*/:		// MADMAX specific.
 				songType = YM_V2;
 				nbFrame = (fileSize-4)/14;
+				if (nbFrame == 0)
+				{ 
+					setLastError("No frames in file");
+					return YMFALSE;
+				}
 				loopFrame = 0;
 				ymChip.setClock(ATARI_CLOCK);
 				setPlayerRate(50);
@@ -256,9 +319,14 @@ ymbool	CYmMusic::ymDecode(void)
 				pSongPlayer = mstrdup("YM-Chip driver.");
 				break;
 
-			case 'YM3!':		// Standart YM-Atari format.
+			case 0x594d3321 /*'YM3!'*/:		// Standart YM-Atari format.
 				songType = YM_V3;
 				nbFrame = (fileSize-4)/14;
+				if (nbFrame == 0)
+				{ 
+					setLastError("No frames in file");
+					return YMFALSE;
+				}
 				loopFrame = 0;
 				ymChip.setClock(ATARI_CLOCK);
 				setPlayerRate(50);
@@ -273,11 +341,24 @@ ymbool	CYmMusic::ymDecode(void)
 				pSongPlayer = mstrdup("YM-Chip driver.");
 				break;
 
-			case 'YM3b':		// Standart YM-Atari format + Loop info.
+			case 0x594d3362 /*'YM3b'*/:		// Standart YM-Atari format + Loop info.
+				if (ptr_size < 4)
+				{ 
+					setLastError("File too small");
+					return YMFALSE;
+				}
 				pUD = (ymu8*)(pBigMalloc+fileSize-4);
 				songType = YM_V3;
-				nbFrame = (fileSize-4)/14;
-				loopFrame = ReadLittleEndian32(pUD);
+				nbFrame = (fileSize-8)/14;
+				if (nbFrame == 0)
+				{ 
+					setLastError("No frames in file");
+					return YMFALSE;
+				}
+				{
+					ymint dummy = 4;
+					loopFrame = ReadLittleEndian32(pUD, dummy);
+				}
 				ymChip.setClock(ATARI_CLOCK);
 				setPlayerRate(50);
 				pDataStream = pBigMalloc+4;
@@ -291,35 +372,62 @@ ymbool	CYmMusic::ymDecode(void)
 				pSongPlayer = mstrdup("YM-Chip driver.");
 				break;
 
-			case 'YM4!':		// Extended ATARI format.
+			case 0x594d3421 /*'YM4!'*/:		// Extended ATARI format.
 				setLastError("No more YM4! support. Use YM5! format.");
 				return YMFALSE;
 				break;
 
-			case 'YM5!':		// Extended YM2149 format, all machines.
-			case 'YM6!':		// Extended YM2149 format, all machines.
+			case 0x594d3521 /*'YM5!'*/:		// Extended YM2149 format, all machines.
+			case 0x594d3621 /*'YM6!'*/:		// Extended YM2149 format, all machines.
+				if (ptr_size < 12)
+				{ 
+					setLastError("File too small");
+					return YMFALSE;
+				}
 				if (strncmp((const char*)(pBigMalloc+4),"LeOnArD!",8))
 				{
 					setLastError("Not a valid YM format !");
 					return YMFALSE;
 				}
 				ptr = pBigMalloc+12;
-				nbFrame = readMotorolaDword(&ptr);
-				setAttrib(readMotorolaDword(&ptr));
-				nbDrum = readMotorolaWord(&ptr);
-				ymChip.setClock(readMotorolaDword(&ptr));
-				setPlayerRate(readMotorolaWord(&ptr));
-				loopFrame = readMotorolaDword(&ptr);
-				skip = readMotorolaWord(&ptr);
+				ptr_size -= 12;
+				nbFrame = readMotorolaDword(&ptr, &ptr_size);
+				setAttrib(readMotorolaDword(&ptr, &ptr_size));
+				nbDrum = readMotorolaWord(&ptr, &ptr_size);
+				ymChip.setClock(readMotorolaDword(&ptr, &ptr_size));
+				setPlayerRate(readMotorolaWord(&ptr, &ptr_size));
+				loopFrame = readMotorolaDword(&ptr, &ptr_size);
+				skip = readMotorolaWord(&ptr, &ptr_size);
 				ptr += skip;
+				ptr_size -= skip;
+				if (ptr_size <= 0)
+				{
+					setLastError("File too small");
+					return YMFALSE;
+				}
 				if (nbDrum>0)
 				{
-					pDrumTab=(digiDrum_t*)malloc(nbDrum*sizeof(digiDrum_t));
+					pDrumTab=(digiDrum_t*)calloc(nbDrum, sizeof(digiDrum_t));
 					for (i=0;i<nbDrum;i++)
 					{
-						pDrumTab[i].size = readMotorolaDword(&ptr);
+						pDrumTab[i].size = readMotorolaDword(&ptr, &ptr_size);
+						if (ptr_size <= 0)
+						{
+							setLastError("File too small");
+							goto error_out;
+						}
 						if (pDrumTab[i].size)
 						{
+							if (pDrumTab[i].size >= 0x80000000)
+							{
+								setLastError("To big drumtab");
+								goto error_out;
+							}
+							if (ptr_size<(ymint)pDrumTab[i].size)
+							{
+								setLastError("File too small");
+								goto error_out;
+							}
 							pDrumTab[i].pData = (ymu8*)malloc(pDrumTab[i].size);
 							memcpy(pDrumTab[i].pData,ptr,pDrumTab[i].size);
 							if (attrib&A_DRUM4BITS)
@@ -328,23 +436,26 @@ ymbool	CYmMusic::ymDecode(void)
 								ymu8 *pw = pDrumTab[i].pData;
 								for (j=0;j<pDrumTab[i].size;j++)
 								{
-									*pw++ = ymVolumeTable[(*pw)&15]>>7;
+									*pw = ymVolumeTable[(*pw)&15]>>7;
+									pw++;
 								}
 							}
 							ptr += pDrumTab[i].size;
-						}
-						else
-						{
-							pDrumTab[i].pData = NULL;
+							ptr_size -= pDrumTab[i].size;
 						}
 					}
 					attrib &= (~A_DRUM4BITS);
 				}
-				pSongName = readNtString((char**)&ptr);
-				pSongAuthor = readNtString((char**)&ptr);
-				pSongComment = readNtString((char**)&ptr);
+				pSongName = readNtString((char**)&ptr, &ptr_size);
+				pSongAuthor = readNtString((char**)&ptr, &ptr_size);
+				pSongComment = readNtString((char**)&ptr, &ptr_size);
+				if (ptr_size <= 0)
+				{
+					setLastError("File too small");
+					goto error_out;
+				}
 				songType = YM_V5;
-				if (id=='YM6!')
+				if (id==0x594d3621/*'YM6!'*/)
 				{
 					songType = YM_V6;
 					pSongType = mstrdup("YM 6");
@@ -353,13 +464,28 @@ ymbool	CYmMusic::ymDecode(void)
 				{
 					pSongType = mstrdup("YM 5");
 				}
+				if ((nbFrame >= 0x08000000) || (nbFrame < 0))
+				{
+					setLastError("Too many frames");
+					goto error_out;
+				}
+				if (ptr_size < (ymint)(nbFrame * 16))
+				{
+					setLastError("File too small");
+					goto error_out;
+				}
 				pDataStream = ptr;
 				streamInc = 16;
 				setAttrib(A_STREAMINTERLEAVED|A_TIMECONTROL);
 				pSongPlayer = mstrdup("YM-Chip driver.");
 				break;
 
-			case 'MIX1':		// ATARI Remix digit format.
+			case 0x4d495831 /*'MIX1'*/:		// ATARI Remix digit format.
+				if (ptr_size < 12)
+				{ 
+					setLastError("File too small");
+					return YMFALSE;
+				}
 
 				if (strncmp((const char*)(pBigMalloc+4),"LeOnArD!",8))
 				{
@@ -367,23 +493,50 @@ ymbool	CYmMusic::ymDecode(void)
 					return YMFALSE;
 				}
 				ptr = pBigMalloc+12;
+				ptr_size -= 12;
 				songType = YM_MIX1;
-				tmp = readMotorolaDword(&ptr);
+				tmp = readMotorolaDword(&ptr, &ptr_size);
 				setAttrib(0);
 				if (tmp&1) setAttrib(A_DRUMSIGNED);
-				sampleSize = readMotorolaDword(&ptr);
-				nbMixBlock = readMotorolaDword(&ptr);
+				sampleSize = readMotorolaDword(&ptr, &ptr_size);
+				nbMixBlock = readMotorolaDword(&ptr, &ptr_size);
+				if (ptr_size <= 0)
+				{
+					setLastError("File too small");
+					goto error_out;
+				}
+				if (sampleSize <= 0)
+				{
+					setLastError("Invalid sampleSize");
+					goto error_out;
+				}
+				if (nbMixBlock <= 0)
+				{
+					setLastError("Invalid number of mixblocks");
+					goto error_out;
+				}
 				pMixBlock = (mixBlock_t*)malloc(nbMixBlock*sizeof(mixBlock_t));
 				for (i=0;i<nbMixBlock;i++)
 				{	// Lecture des block-infos.
-					pMixBlock[i].sampleStart = readMotorolaDword(&ptr);
-					pMixBlock[i].sampleLength = readMotorolaDword(&ptr);
-					pMixBlock[i].nbRepeat = readMotorolaWord(&ptr);
-					pMixBlock[i].replayFreq = readMotorolaWord(&ptr);
+					pMixBlock[i].sampleStart = readMotorolaDword(&ptr, &ptr_size);
+					pMixBlock[i].sampleLength = readMotorolaDword(&ptr, &ptr_size);
+					pMixBlock[i].nbRepeat = readMotorolaWord(&ptr, &ptr_size);
+					pMixBlock[i].replayFreq = readMotorolaWord(&ptr, &ptr_size);
+				}
+				pSongName = readNtString((char**)&ptr, &ptr_size);
+				pSongAuthor = readNtString((char**)&ptr, &ptr_size);
+				pSongComment = readNtString((char**)&ptr, &ptr_size);
+
+				if (sampleSize>=0x80000000)
+				{
+					setLastError("Invalid sampleSize");
+					goto error_out;
+				}
+				if (ptr_size < (ymint)sampleSize)
+				{
+					setLastError("File too small");
+					goto error_out;
 				}
-				pSongName = readNtString((char**)&ptr);
-				pSongAuthor = readNtString((char**)&ptr);
-				pSongComment = readNtString((char**)&ptr);
 
 				pBigSampleBuffer = (unsigned char*)malloc(sampleSize);
 				memcpy(pBigSampleBuffer,ptr,sampleSize);
@@ -400,8 +553,8 @@ ymbool	CYmMusic::ymDecode(void)
 
 				break;
 
-			case 'YMT1':		// YM-Tracker
-			case 'YMT2':		// YM-Tracker
+			case 0x594d5431 /*'YMT1'*/:		// YM-Tracker
+			case 0x594d5432 /*'YMT2'*/:		// YM-Tracker
 /*;
 ; Format du YM-Tracker-1
 ;
@@ -418,33 +571,55 @@ ymbool	CYmMusic::ymDecode(void)
 ; NT Music comment
 ; nb digi *
 */
+				if (ptr_size < 12)
+				{ 
+					setLastError("File too small");
+					return YMFALSE;
+				}
+
 				if (strncmp((const char*)(pBigMalloc+4),"LeOnArD!",8))
 				{
 					setLastError("Not a valid YM format !");
 					return YMFALSE;
 				}
 				ptr = pBigMalloc+12;
+				ptr_size -= 12;
 				songType = YM_TRACKER1;
-				nbVoice = readMotorolaWord(&ptr);
-				setPlayerRate(readMotorolaWord(&ptr));
-				nbFrame= readMotorolaDword(&ptr);
-				loopFrame = readMotorolaDword(&ptr);
-				nbDrum = readMotorolaWord(&ptr);
-				attrib = readMotorolaDword(&ptr);
-				pSongName = readNtString((char**)&ptr);
-				pSongAuthor = readNtString((char**)&ptr);
-				pSongComment = readNtString((char**)&ptr);
+				nbVoice = readMotorolaWord(&ptr, &ptr_size);
+				setPlayerRate(readMotorolaWord(&ptr, &ptr_size));
+				nbFrame= readMotorolaDword(&ptr, &ptr_size);
+				loopFrame = readMotorolaDword(&ptr, &ptr_size);
+				nbDrum = readMotorolaWord(&ptr, &ptr_size);
+				attrib = readMotorolaDword(&ptr, &ptr_size);
+				pSongName = readNtString((char**)&ptr, &ptr_size);
+				pSongAuthor = readNtString((char**)&ptr, &ptr_size);
+				pSongComment = readNtString((char**)&ptr, &ptr_size);
+				if (ptr_size < 0)
+				{ 
+					setLastError("File too small");
+					return YMFALSE;
+				}
 				if (nbDrum>0)
 				{
-					pDrumTab=(digiDrum_t*)malloc(nbDrum*sizeof(digiDrum_t));
+					pDrumTab=(digiDrum_t*)calloc(nbDrum, sizeof(digiDrum_t));
 					for (i=0;i<(ymint)nbDrum;i++)
 					{
-						pDrumTab[i].size = readMotorolaWord(&ptr);
+						pDrumTab[i].size = readMotorolaWord(&ptr, &ptr_size);
+						if (ptr_size < 0)
+						{
+							setLastError("File too small");
+							goto error_out;
+						}
 						pDrumTab[i].repLen = pDrumTab[i].size;
-						if ('YMT2' == id)
+						if (0x594d5432/*'YMT2'*/ == id)
 						{
-							pDrumTab[i].repLen = readMotorolaWord(&ptr);	// repLen
-							readMotorolaWord(&ptr);		// flag
+							pDrumTab[i].repLen = readMotorolaWord(&ptr, &ptr_size);	// repLen
+							readMotorolaWord(&ptr, &ptr_size);		// flag
+							if (ptr_size < 0)
+							{
+								setLastError("File too small");
+								goto error_out;
+							}
 						}
 						if (pDrumTab[i].repLen>pDrumTab[i].size)
 						{
@@ -453,19 +628,27 @@ ymbool	CYmMusic::ymDecode(void)
 
 						if (pDrumTab[i].size)
 						{
+							if (pDrumTab[i].size >= 0x80000000)
+							{
+								setLastError("Drumtab to big");
+								goto error_out;
+							}
+							if (ptr_size<(ymint)pDrumTab[i].size)
+							{
+								setLastError("File too small");
+								goto error_out;
+							}
+
 							pDrumTab[i].pData = (ymu8*)malloc(pDrumTab[i].size);
 							memcpy(pDrumTab[i].pData,ptr,pDrumTab[i].size);
 							ptr += pDrumTab[i].size;
-						}
-						else
-						{
-							pDrumTab[i].pData = NULL;
+							ptr_size -= pDrumTab[i].size;
 						}
 					}
 				}
 
 				ymTrackerFreqShift = 0;
-				if ('YMT2' == id)
+				if (0x594d5432/*'YMT2'*/ == id)
 				{
 					ymTrackerFreqShift = (attrib>>28)&15;
 					attrib &= 0x0fffffff;
@@ -476,18 +659,33 @@ ymbool	CYmMusic::ymDecode(void)
 					pSongType = mstrdup("YM-T1");
 				}
 
+				if ((nbVoice > MAX_VOICE) || (nbVoice < 0))
+				{
+					setLastError("Too many voices");
+					goto error_out;
+				}
+				if ((nbFrame >= (ymint)(0x80000000 / (MAX_VOICE * (sizeof(ymTrackerLine_t))))) || (nbFrame < 0)) /* ymTrackerLine_t has a 2^N size */
+				{
+					setLastError("Too many frames");
+					goto error_out;
+				}
+				if (ptr_size < (ymint)(sizeof(ymTrackerLine_t) * nbVoice * nbFrame))
+				{
+					setLastError("File too small");
+					goto error_out;
+				}
 
 				pDataStream = ptr;
 				ymChip.setClock(ATARI_CLOCK);
 
 				ymTrackerInit(100);		// 80% de volume maxi.
-				streamInc = 16;
+				streamInc = 16; /* not needed, since this is only used for YMx formats */
 				setTimeControl(YMTRUE);
 				pSongPlayer = mstrdup("Universal Tracker");
 				break;
 
 			default:
-				setLastError("Unknow YM format !");
+				setLastError("Unknown YM format !");
 				return YMFALSE;
 				break;
 		}
@@ -498,6 +696,25 @@ ymbool	CYmMusic::ymDecode(void)
 		}
 
 		return YMTRUE;
+error_out:
+	for (i=0;i<nbDrum;i++)
+	{
+		if (pDrumTab[i].pData)
+			myFree((void **)&pDrumTab[i].pData);
+	}
+	if (nbDrum>0)
+	{
+		myFree((void **)&pDrumTab);
+		nbDrum=0;
+	}
+	myFree((void **)&pSongName);
+	myFree((void **)&pSongAuthor);
+	myFree((void **)&pSongComment);
+	myFree((void **)&pSongType); /* <- never needed, but we keep it for purity */
+	myFree((void **)&pSongPlayer); /* <- never needed, but we keep it for purity */
+	myFree((void **)&pMixBlock);
+	myFree((void **)&pBigSampleBuffer); /* <- never needed, but we keep it for purity */
+	return YMFALSE;
  }
 
  
@@ -645,12 +862,6 @@ ymbool	CYmMusic::loadMemory(void *pBlock
 		return YMTRUE;
  }
 
-void	myFree(void **pPtr)
-{
-		if (*pPtr) free(*pPtr);
-		*pPtr = NULL;
-}
-
 void	CYmMusic::unLoad(void)
 {
 
