shithub: ft²

Download patch

ref: e5de9210c160bf941b5ac4a94c7be76da77bff47
parent: 84b7cec46bc91343a1a8aa9b13799db5608ee4e8
author: Olav Sørensen <olav.sorensen@live.no>
date: Sun Mar 17 08:23:13 EDT 2024

Fix possible deadlock in loaders/savers

--- a/src/ft2_inst_ed.c
+++ b/src/ft2_inst_ed.c
@@ -2912,11 +2912,12 @@
 {
 	xiHdr_t ih;
 	sample_t *s;
+	FILE *f = NULL;
 
 	if (editor.tmpFilenameU == NULL)
 	{
 		okBoxThreadSafe(0, "System message", "General I/O error during saving! Is the file in use?", NULL);
-		return false;
+		goto saveError;
 	}
 
 	const int32_t numSamples = getUsedSamples(saveInstrNum);
@@ -2923,14 +2924,14 @@
 	if (numSamples == 0 || instr[saveInstrNum] == NULL)
 	{
 		okBoxThreadSafe(0, "System message", "Instrument is empty!", NULL);
-		return false;
+		goto saveError;
 	}
 
-	FILE *f = UNICHAR_FOPEN(editor.tmpFilenameU, "wb");
+	f = UNICHAR_FOPEN(editor.tmpFilenameU, "wb");
 	if (f == NULL)
 	{
 		okBoxThreadSafe(0, "System message", "General I/O error during saving! Is the file in use?", NULL);
-		return false;
+		goto saveError;
 	}
 
 	memset(&ih, 0, sizeof (ih)); // important, also clears reserved stuff
@@ -3025,9 +3026,8 @@
 	size_t result = fwrite(&ih, INSTR_XI_HEADER_SIZE + (ih.numSamples * sizeof (xmSmpHdr_t)), 1, f);
 	if (result != 1)
 	{
-		fclose(f);
 		okBoxThreadSafe(0, "System message", "Error saving instrument: general I/O error!", NULL);
-		return false;
+		goto saveError;
 	}
 
 	pauseAudio();
@@ -3047,9 +3047,8 @@
 			if (result != (size_t)SAMPLE_LENGTH_BYTES(s)) // write not OK
 			{
 				resumeAudio();
-				fclose(f);
 				okBoxThreadSafe(0, "System message", "Error saving instrument: general I/O error!", NULL);
-				return false;
+				goto saveError;
 			}
 		}
 	}
@@ -3062,6 +3061,15 @@
 
 	return true;
 
+saveError:
+	if (f != NULL)
+		fclose(f);
+
+	editor.diskOpReadDir = true; // force diskop re-read
+	setMouseBusy(false);
+
+	return false;
+
 	(void)ptr;
 }
 
@@ -3102,21 +3110,22 @@
 	xmSmpHdr_t *src;
 	sample_t *s;
 	instr_t *ins;
-
+	FILE *f = NULL;
 	bool stereoWarning = false;
+
 	numLoadedSamples = 0;
 
 	if (editor.tmpInstrFilenameU == NULL)
 	{
 		okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?", NULL);
-		return false;
+		goto loadDone;
 	}
 
-	FILE *f = UNICHAR_FOPEN(editor.tmpInstrFilenameU, "rb");
+	f = UNICHAR_FOPEN(editor.tmpInstrFilenameU, "rb");
 	if (f == NULL)
 	{
 		okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?", NULL);
-		return false;
+		goto loadDone;
 	}
 
 	memset(&xi_h, 0, sizeof (xi_h));
@@ -3435,32 +3444,36 @@
 	}
 
 loadDone:
-	fclose(f);
+	if (f != NULL)
+		fclose(f);
 
-	numLoadedSamples = CLAMP(numLoadedSamples, 1, MAX_SMP_PER_INST);
-
-	ins = instr[editor.curInstr];
-	if (ins != NULL)
+	if (numLoadedSamples > 0)
 	{
-		sanitizeInstrument(ins);
-		for (i = 0; i < numLoadedSamples; i++)
+		numLoadedSamples = CLAMP(numLoadedSamples, 1, MAX_SMP_PER_INST);
+
+		ins = instr[editor.curInstr];
+		if (ins != NULL)
 		{
-			s = &ins->smp[i];
-			sanitizeSample(s);
+			sanitizeInstrument(ins);
+			for (i = 0; i < numLoadedSamples; i++)
+			{
+				s = &ins->smp[i];
+				sanitizeSample(s);
 
-			if (s->dataPtr != NULL)
-				fixSample(s);
+				if (s->dataPtr != NULL)
+					fixSample(s);
+			}
+
+			fixInstrAndSampleNames(editor.curInstr);
 		}
+		editor.updateCurInstr = true; // setMouseBusy(false) is called in the input/video thread when done
 
-		fixInstrAndSampleNames(editor.curInstr);
-	}
-	editor.updateCurInstr = true; // setMouseBusy(false) is called in the input/video thread when done
+		if (numLoadedSamples > MAX_SMP_PER_INST)
+			okBoxThreadSafe(0, "System message", "Warning: The instrument contained >16 samples. The extra samples were discarded!", NULL);
 
-	if (numLoadedSamples > MAX_SMP_PER_INST)
-		okBoxThreadSafe(0, "System message", "Warning: The instrument contained >16 samples. The extra samples were discarded!", NULL);
-
-	if (stereoWarning)
-		okBoxThreadSafe(0, "System message", "Warning: The instrument contained stereo sample(s). They were mixed to mono!", NULL);
+		if (stereoWarning)
+			okBoxThreadSafe(0, "System message", "Warning: The instrument contained stereo sample(s). They were mixed to mono!", NULL);
+	}
 
 	return true;
 	(void)ptr;
--- a/src/ft2_sample_loader.c
+++ b/src/ft2_sample_loader.c
@@ -86,7 +86,7 @@
 	if (editor.tmpFilenameU == NULL)
 	{
 		loaderMsgBox("General I/O error during loading!");
-		return false;
+		goto loadError;
 	}
 
 	FILE *f = UNICHAR_FOPEN(editor.tmpFilenameU, "rb");
@@ -93,7 +93,7 @@
 	if (f == NULL)
 	{
 		loaderMsgBox("General I/O error during loading! Is the file in use?");
-		return false;
+		goto loadError;
 	}
 
 	int8_t format = detectSample(f);
@@ -104,7 +104,7 @@
 	{
 		fclose(f);
 		loaderMsgBox("Error loading sample: The file is empty!");
-		return false;
+		goto loadError;
 	}
 
 	bool sampleLoaded = false;