From 7f685b4c77997074ead0c738c17640df4d5174af Mon Sep 17 00:00:00 2001
From: codeimp <codeimp@e0d998f2-2e9b-42fe-843d-47128df60a06>
Date: Sun, 15 Aug 2010 19:43:00 +0000
Subject: [PATCH] Added maximum number of map element checks (now you can't
 corrupt your map when exceeding the format's limits)

---
 Source/Core/Editing/CopyPasteManager.cs       |  20 +++-
 Source/Core/Editing/UndoManager.cs            |   2 +-
 Source/Core/General/MapManager.cs             |  28 +++++
 Source/Core/Geometry/Tools.cs                 |  40 +++++--
 Source/Core/IO/UniversalStreamReader.cs       |  86 ++++++++------
 Source/Core/Map/Linedef.cs                    |  43 ++++---
 Source/Core/Map/MapSet.cs                     | 108 ++++++++++++++----
 Source/Core/Windows/LinedefEditForm.cs        |  76 +++++++-----
 .../ClassicModes/BaseClassicMode.cs           |  30 +++--
 .../ClassicModes/CurveLinedefsMode.cs         |  12 +-
 .../ClassicModes/DrawGeometryMode.cs          |   9 +-
 .../ClassicModes/EditSelectionMode.cs         |   2 +-
 .../BuilderModes/ClassicModes/LinedefsMode.cs |  15 ++-
 .../ClassicModes/MakeSectorMode.cs            |  95 ++++++++-------
 .../BuilderModes/ClassicModes/ThingsMode.cs   |  39 ++++---
 .../BuilderModes/ClassicModes/VerticesMode.cs |  25 +++-
 .../ErrorChecks/ResultLineMissingFront.cs     |   1 +
 .../ErrorChecks/ResultLineMissingSides.cs     |   4 +
 .../ErrorChecks/ResultLineNotDoubleSided.cs   |   1 +
 19 files changed, 434 insertions(+), 202 deletions(-)

diff --git a/Source/Core/Editing/CopyPasteManager.cs b/Source/Core/Editing/CopyPasteManager.cs
index 5270f8d8d..e57003e4f 100644
--- a/Source/Core/Editing/CopyPasteManager.cs
+++ b/Source/Core/Editing/CopyPasteManager.cs
@@ -289,12 +289,22 @@ namespace CodeImp.DoomBuilder.Editing
 						if(options.ChangeTags == PasteOptions.TAGS_RENUMBER) Tools.RenumberMarkedTags();
 						if(options.RemoveActions) Tools.RemoveMarkedActions();
 
-						// Done
+						// Clean up
 						memstream.Dispose();
-						General.Map.Map.UpdateConfiguration();
-						General.Map.ThingsFilter.Update();
-						General.Editing.Mode.OnPasteEnd(options.Copy());
-						General.Plugins.OnPasteEnd(options);
+
+						// Check if anything was pasted
+						int totalpasted = General.Map.Map.GetMarkedThings(true).Count;
+						totalpasted += General.Map.Map.GetMarkedVertices(true).Count;
+						totalpasted += General.Map.Map.GetMarkedLinedefs(true).Count;
+						totalpasted += General.Map.Map.GetMarkedSidedefs(true).Count;
+						totalpasted += General.Map.Map.GetMarkedSectors(true).Count;
+						if(totalpasted > 0)
+						{
+							General.Map.Map.UpdateConfiguration();
+							General.Map.ThingsFilter.Update();
+							General.Editing.Mode.OnPasteEnd(options.Copy());
+							General.Plugins.OnPasteEnd(options);
+						}
 						return true;
 					}
 				}
diff --git a/Source/Core/Editing/UndoManager.cs b/Source/Core/Editing/UndoManager.cs
index b2deb3705..35498d722 100644
--- a/Source/Core/Editing/UndoManager.cs
+++ b/Source/Core/Editing/UndoManager.cs
@@ -571,7 +571,7 @@ namespace CodeImp.DoomBuilder.Editing
 			
 			General.Plugins.OnUndoWithdrawn();
 		}
-
+		
 		// This performs an undo
 		[BeginAction("undo")]
 		public void PerformUndo()
diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs
index ba8a4320d..540599fab 100644
--- a/Source/Core/General/MapManager.cs
+++ b/Source/Core/General/MapManager.cs
@@ -501,6 +501,34 @@ namespace CodeImp.DoomBuilder
 						return false;
 					}
 				}
+
+				// Check things
+				if(map.Things.Count > io.MaxThings)
+				{
+					General.ShowErrorMessage("Unable to save the map: There are too many things!", MessageBoxButtons.OK);
+					return false;
+				}
+
+				// Check sectors
+				if(map.Sectors.Count > io.MaxSectors)
+				{
+					General.ShowErrorMessage("Unable to save the map: There are too many sectors!", MessageBoxButtons.OK);
+					return false;
+				}
+
+				// Check linedefs
+				if(map.Linedefs.Count > io.MaxLinedefs)
+				{
+					General.ShowErrorMessage("Unable to save the map: There are too many linedefs!", MessageBoxButtons.OK);
+					return false;
+				}
+
+				// Check vertices
+				if(map.Vertices.Count > io.MaxVertices)
+				{
+					General.ShowErrorMessage("Unable to save the map: There are too many vertices!", MessageBoxButtons.OK);
+					return false;
+				}
 				
 				// TODO: Check for more limitations
 				
diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs
index 09f971e7f..f991ed48a 100644
--- a/Source/Core/Geometry/Tools.cs
+++ b/Source/Core/Geometry/Tools.cs
@@ -23,6 +23,7 @@ using System.Globalization;
 using System.Text;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Rendering;
+using CodeImp.DoomBuilder.Windows;
 using SlimDX;
 using SlimDX.Direct3D9;
 using System.Drawing;
@@ -453,12 +454,18 @@ namespace CodeImp.DoomBuilder.Geometry
 		// If nearbylines is not null, then this method will find the default
 		// properties from the nearest line in this collection when the
 		// default properties can't be found in the alllines collection.
+		// Return null when no new sector could be made.
 		public static Sector MakeSector(List<LinedefSide> alllines, List<Linedef> nearbylines)
 		{
-			Sector newsector = General.Map.Map.CreateSector();
 			Sector sourcesector = null;
 			SidedefSettings sourceside = new SidedefSettings();
 			bool foundsidedefaults = false;
+
+			if(General.Map.Map.Sectors.Count >= General.Map.FormatInterface.MaxSectors)
+				return null;
+
+			Sector newsector = General.Map.Map.CreateSector();
+			if(newsector == null) return null;
 			
 			// Check if any of the sides already has a sidedef
 			// Then we use information from that sidedef to make the others
@@ -565,6 +572,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				{
 					// Create sidedef is needed and ensure it points to the new sector
 					if(ls.Line.Front == null) General.Map.Map.CreateSidedef(ls.Line, true, newsector);
+					if(ls.Line.Front == null) return null;
 					if(ls.Line.Front.Sector != newsector) ls.Line.Front.SetSector(newsector);
 					ApplyDefaultsToSidedef(ls.Line.Front, sourceside);
 				}
@@ -572,6 +580,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				{
 					// Create sidedef is needed and ensure it points to the new sector
 					if(ls.Line.Back == null) General.Map.Map.CreateSidedef(ls.Line, false, newsector);
+					if(ls.Line.Back == null) return null;
 					if(ls.Line.Back.Sector != newsector) ls.Line.Back.SetSector(newsector);
 					ApplyDefaultsToSidedef(ls.Line.Back, sourceside);
 				}
@@ -591,7 +600,7 @@ namespace CodeImp.DoomBuilder.Geometry
 		}
 
 
-		// This joins a sector with the given lines and sides
+		// This joins a sector with the given lines and sides. Returns null when operation could not be completed.
 		public static Sector JoinSector(List<LinedefSide> alllines, Sidedef original)
 		{
 			SidedefSettings sourceside = new SidedefSettings();
@@ -610,7 +619,8 @@ namespace CodeImp.DoomBuilder.Geometry
 					// Create sidedef if needed
 					if(ls.Line.Front == null)
 					{
-						General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
+						Sidedef sd = General.Map.Map.CreateSidedef(ls.Line, true, original.Sector);
+						if(sd == null) return null;
 						ApplyDefaultsToSidedef(ls.Line.Front, sourceside);
 						ls.Line.ApplySidedFlags();
 						
@@ -629,7 +639,8 @@ namespace CodeImp.DoomBuilder.Geometry
 					// Create sidedef if needed
 					if(ls.Line.Back == null)
 					{
-						General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
+						Sidedef sd = General.Map.Map.CreateSidedef(ls.Line, false, original.Sector);
+						if(sd == null) return null;
 						ApplyDefaultsToSidedef(ls.Line.Back, sourceside);
 						ls.Line.ApplySidedFlags();
 
@@ -821,8 +832,9 @@ namespace CodeImp.DoomBuilder.Geometry
 		/// <summary>
 		/// This draws lines with the given points. Note that this tool removes any existing geometry
 		/// marks and marks the new lines and vertices when done. Also marks the sectors that were added.
+		/// Returns false when the drawing failed.
 		/// </summary>
-		public static void DrawLines(IList<DrawnVertex> points)
+		public static bool DrawLines(IList<DrawnVertex> points)
 		{
 			List<Vertex> newverts = new List<Vertex>();
 			List<Vertex> intersectverts = new List<Vertex>();
@@ -845,6 +857,7 @@ namespace CodeImp.DoomBuilder.Geometry
 
 				// Make first vertex
 				Vertex v1 = map.CreateVertex(points[0].pos);
+				if(v1 == null) return false;
 				v1.Marked = true;
 
 				// Keep references
@@ -856,6 +869,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				{
 					// Create vertex for point
 					Vertex v2 = map.CreateVertex(points[i].pos);
+					if(v2 == null) return false;
 					v2.Marked = true;
 
 					// Keep references
@@ -864,6 +878,7 @@ namespace CodeImp.DoomBuilder.Geometry
 
 					// Create line between point and previous
 					Linedef ld = map.CreateLinedef(v1, v2);
+					if(ld == null) return false;
 					ld.Marked = true;
 					ld.ApplySidedFlags();
 					ld.UpdateCache();
@@ -902,16 +917,18 @@ namespace CodeImp.DoomBuilder.Geometry
 
 							// Make the vertex
 							Vertex splitvertex = map.CreateVertex(splitpoint);
+							if(splitvertex == null) return false;
 							splitvertex.Marked = true;
 							newverts.Add(splitvertex);
 							mergeverts.Add(splitvertex);			// <-- add to merge?
 							intersectverts.Add(splitvertex);
-
+							
 							// The Split method ties the end of the original line to the given
 							// vertex and starts a new line at the given vertex, so continue
 							// splitting with the new line, because the intersections are sorted
 							// from low to high (beginning at the original line start)
 							splitline = splitline.Split(splitvertex);
+							if(splitline == null) return false;
 							splitline.ApplySidedFlags();
 							newlines.Add(splitline);
 						}
@@ -1116,11 +1133,13 @@ namespace CodeImp.DoomBuilder.Geometry
 
 											// Make the new vertex
 											Vertex v2 = map.CreateVertex(v2pos);
+											if(v2 == null) return false;
 											v2.Marked = true;
 											mergeverts.Add(v2);
 
 											// Make the line
 											Linedef ld = map.CreateLinedef(v1, v2);
+											if(ld == null) return false;
 											ld.Marked = true;
 											ld.ApplySidedFlags();
 											ld.UpdateCache();
@@ -1137,6 +1156,8 @@ namespace CodeImp.DoomBuilder.Geometry
 										else
 											lld = map.CreateLinedef(v1, firstline.Start);
 
+										if(lld == null) return false;
+										
 										// Setup line
 										lld.Marked = true;
 										lld.ApplySidedFlags();
@@ -1282,6 +1303,8 @@ namespace CodeImp.DoomBuilder.Geometry
 							{
 								// Make the new sector
 								Sector newsector = Tools.MakeSector(sectorlines, oldlines);
+								if(newsector == null) return false;
+
 								if(istruenewsector) newsector.Marked = true;
 
 								// Go for all sidedefs in this new sector
@@ -1354,7 +1377,8 @@ namespace CodeImp.DoomBuilder.Geometry
 								}
 								
 								// Have our new lines join the existing sector
-								Tools.JoinSector(newsectorlines, joinsidedef);
+								if(Tools.JoinSector(newsectorlines, joinsidedef) == null)
+									return false;
 							}
 						}
 					}
@@ -1384,6 +1408,8 @@ namespace CodeImp.DoomBuilder.Geometry
 				foreach(Vertex v in newverts) v.Marked = true;
 				foreach(Linedef l in newlines) l.Marked = true;
 			}
+
+			return true;
 		}
 		
 		#endregion
diff --git a/Source/Core/IO/UniversalStreamReader.cs b/Source/Core/IO/UniversalStreamReader.cs
index bd867a629..2e54b53c2 100644
--- a/Source/Core/IO/UniversalStreamReader.cs
+++ b/Source/Core/IO/UniversalStreamReader.cs
@@ -196,10 +196,13 @@ namespace CodeImp.DoomBuilder.IO
 
 				// Create new item
 				Thing t = map.CreateThing();
-				t.Update(type, x, y, height, Angle2D.DoomToReal(angledeg), stringflags, tag, special, args);
+				if(t != null)
+				{
+					t.Update(type, x, y, height, Angle2D.DoomToReal(angledeg), stringflags, tag, special, args);
 
-				// Custom fields
-				ReadCustomFields(c, t, "thing");
+					// Custom fields
+					ReadCustomFields(c, t, "thing");
+				}
 			}
 		}
 
@@ -252,27 +255,30 @@ namespace CodeImp.DoomBuilder.IO
 					if(Vector2D.ManhattanDistance(vertexlink[v1].Position, vertexlink[v2].Position) > 0.0001f)
 					{
 						Linedef l = map.CreateLinedef(vertexlink[v1], vertexlink[v2]);
-						l.Update(stringflags, 0, tag, special, args);
-						l.UpdateCache();
-
-						// Custom fields
-						ReadCustomFields(lc, l, "linedef");
-
-						// Read sidedefs and connect them to the line
-						if(s1 > -1)
+						if(l != null)
 						{
-							if(s1 < sidescolls.Count)
-								ReadSidedef(map, sidescolls[s1], l, true, sectorlink, s1);
-							else
-								General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed.");
-						}
-						
-						if(s2 > -1)
-						{
-							if(s2 < sidescolls.Count)
-								ReadSidedef(map, sidescolls[s2], l, false, sectorlink, s2);
-							else
-								General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed.");
+							l.Update(stringflags, 0, tag, special, args);
+							l.UpdateCache();
+
+							// Custom fields
+							ReadCustomFields(lc, l, "linedef");
+
+							// Read sidedefs and connect them to the line
+							if(s1 > -1)
+							{
+								if(s1 < sidescolls.Count)
+									ReadSidedef(map, sidescolls[s1], l, true, sectorlink, s1);
+								else
+									General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed.");
+							}
+
+							if(s2 > -1)
+							{
+								if(s2 < sidescolls.Count)
+									ReadSidedef(map, sidescolls[s2], l, false, sectorlink, s2);
+								else
+									General.ErrorLogger.Add(ErrorType.Warning, "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed.");
+							}
 						}
 					}
 					else
@@ -304,10 +310,13 @@ namespace CodeImp.DoomBuilder.IO
 			if(sectorlink.ContainsKey(sector))
 			{
 				Sidedef s = map.CreateSidedef(ld, front, sectorlink[sector]);
-				s.Update(offsetx, offsety, thigh, tmid, tlow);
+				if(s != null)
+				{
+					s.Update(offsetx, offsety, thigh, tmid, tlow);
 
-				// Custom fields
-				ReadCustomFields(sc, s, "sidedef");
+					// Custom fields
+					ReadCustomFields(sc, s, "sidedef");
+				}
 			}
 			else
 			{
@@ -343,13 +352,16 @@ namespace CodeImp.DoomBuilder.IO
 
 				// Create new item
 				Sector s = map.CreateSector();
-				s.Update(hfloor, hceil, tfloor, tceil, special, tag, bright);
+				if(s != null)
+				{
+					s.Update(hfloor, hceil, tfloor, tceil, special, tag, bright);
 
-				// Custom fields
-				ReadCustomFields(c, s, "sector");
+					// Custom fields
+					ReadCustomFields(c, s, "sector");
 
-				// Add it to the lookup table
-				link.Add(i, s);
+					// Add it to the lookup table
+					link.Add(i, s);
+				}
 			}
 
 			// Return lookup table
@@ -379,12 +391,14 @@ namespace CodeImp.DoomBuilder.IO
 
 				// Create new item
 				Vertex v = map.CreateVertex(new Vector2D(x, y));
+				if(v != null)
+				{
+					// Custom fields
+					ReadCustomFields(c, v, "vertex");
 
-				// Custom fields
-				ReadCustomFields(c, v, "vertex");
-
-				// Add it to the lookup table
-				link.Add(i, v);
+					// Add it to the lookup table
+					link.Add(i, v);
+				}
 			}
 
 			// Return lookup table
diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs
index dde69756a..b1c2259a0 100644
--- a/Source/Core/Map/Linedef.cs
+++ b/Source/Core/Map/Linedef.cs
@@ -774,7 +774,7 @@ namespace CodeImp.DoomBuilder.Map
 		}
 
 		// This splits this line by vertex v
-		// Returns the new line resulting from the split
+		// Returns the new line resulting from the split, or null when it failed
 		public Linedef Split(Vertex v)
 		{
 			Linedef nl;
@@ -782,6 +782,7 @@ namespace CodeImp.DoomBuilder.Map
 
 			// Copy linedef and change vertices
 			nl = map.CreateLinedef(v, end);
+			if(nl == null) return null;
 			CopyPropertiesTo(nl);
 			SetEndVertex(v);
 			nl.Selected = this.Selected;
@@ -791,6 +792,7 @@ namespace CodeImp.DoomBuilder.Map
 			if(front != null)
 			{
 				nsd = map.CreateSidedef(nl, true, front.Sector);
+				if(nsd == null) return null;
 				front.CopyPropertiesTo(nsd);
 				nsd.Marked = front.Marked;
 
@@ -802,6 +804,7 @@ namespace CodeImp.DoomBuilder.Map
 			if(back != null)
 			{
 				nsd = map.CreateSidedef(nl, false, back.Sector);
+				if(nsd == null) return null;
 				back.CopyPropertiesTo(nsd);
 				nsd.Marked = back.Marked;
 				
@@ -816,7 +819,8 @@ namespace CodeImp.DoomBuilder.Map
 		
 		// This joins the line with another line
 		// This line will be disposed
-		public void Join(Linedef other)
+		// Returns false when the operation could not be completed
+		public bool Join(Linedef other)
 		{
 			Sector l1fs, l1bs, l2fs, l2bs;
 			bool l1was2s, l2was2s;
@@ -844,13 +848,13 @@ namespace CodeImp.DoomBuilder.Map
 				// Copy my sidedefs to the other
 				if(this.Start == other.Start)
 				{
-					JoinChangeSidedefs(other, true, front);
-					JoinChangeSidedefs(other, false, back);
+					if(!JoinChangeSidedefs(other, true, front)) return false;
+					if(!JoinChangeSidedefs(other, false, back)) return false;
 				}
 				else
 				{
-					JoinChangeSidedefs(other, false, front);
-					JoinChangeSidedefs(other, true, back);
+					if(!JoinChangeSidedefs(other, false, front)) return false;
+					if(!JoinChangeSidedefs(other, true, back)) return false;
 				}
 
 				// Copy my properties to the other
@@ -866,7 +870,7 @@ namespace CodeImp.DoomBuilder.Map
 					if(this.front != null) this.front.AddTexturesTo(other.back);
 
 					// Change sidedefs
-					JoinChangeSidedefs(other, true, back);
+					if(!JoinChangeSidedefs(other, true, back)) return false;
 				}
 				// Compare back sectors
 				else if((l1bs != null) && (l1bs == l2bs))
@@ -876,7 +880,7 @@ namespace CodeImp.DoomBuilder.Map
 					if(this.back != null) this.back.AddTexturesTo(other.front);
 
 					// Change sidedefs
-					JoinChangeSidedefs(other, false, front);
+					if(!JoinChangeSidedefs(other, false, front)) return false;
 				}
 				// Compare front and back
 				else if((l1fs != null) && (l1fs == l2bs))
@@ -886,7 +890,7 @@ namespace CodeImp.DoomBuilder.Map
 					if(this.back != null) this.back.AddTexturesTo(other.back);
 
 					// Change sidedefs
-					JoinChangeSidedefs(other, true, front);
+					if(!JoinChangeSidedefs(other, true, front)) return false;
 				}
 				// Compare back and front
 				else if((l1bs != null) && (l1bs == l2fs))
@@ -896,7 +900,7 @@ namespace CodeImp.DoomBuilder.Map
 					if(this.front != null) this.front.AddTexturesTo(other.front);
 
 					// Change sidedefs
-					JoinChangeSidedefs(other, false, back);
+					if(!JoinChangeSidedefs(other, false, back)) return false;
 				}
 				else
 				{
@@ -911,7 +915,7 @@ namespace CodeImp.DoomBuilder.Map
 							if(this.back != null) this.back.AddTexturesTo(other.front);
 
 							// Change sidedefs
-							JoinChangeSidedefs(other, false, front);
+							if(!JoinChangeSidedefs(other, false, front)) return false;
 						}
 						else
 						{
@@ -920,7 +924,7 @@ namespace CodeImp.DoomBuilder.Map
 							if(this.front != null) this.front.AddTexturesTo(other.front);
 
 							// Change sidedefs
-							JoinChangeSidedefs(other, false, back);
+							if(!JoinChangeSidedefs(other, false, back)) return false;
 						}
 					}
 					// This line single sided?
@@ -934,7 +938,7 @@ namespace CodeImp.DoomBuilder.Map
 							if(this.back != null) this.back.AddTexturesTo(other.front);
 
 							// Change sidedefs
-							JoinChangeSidedefs(other, false, front);
+							if(!JoinChangeSidedefs(other, false, front)) return false;
 						}
 						else
 						{
@@ -943,7 +947,7 @@ namespace CodeImp.DoomBuilder.Map
 							if(this.back != null) this.back.AddTexturesTo(other.back);
 
 							// Change sidedefs
-							JoinChangeSidedefs(other, true, front);
+							if(!JoinChangeSidedefs(other, true, front)) return false;
 						}
 					}
 					else
@@ -956,7 +960,7 @@ namespace CodeImp.DoomBuilder.Map
 							if(this.back != null) this.back.AddTexturesTo(other.front);
 
 							// Change sidedefs
-							JoinChangeSidedefs(other, false, front);
+							if(!JoinChangeSidedefs(other, false, front)) return false;
 						}
 						else
 						{
@@ -965,7 +969,7 @@ namespace CodeImp.DoomBuilder.Map
 							if(this.front != null) this.front.AddTexturesTo(other.front);
 
 							// Change sidedefs
-							JoinChangeSidedefs(other, false, back);
+							if(!JoinChangeSidedefs(other, false, back)) return false;
 						}
 					}
 				}
@@ -987,6 +991,7 @@ namespace CodeImp.DoomBuilder.Map
 			// I got killed by the other.
 			this.Dispose();
 			General.Map.IsChanged = true;
+			return true;
 		}
 		
 		// This changes sidedefs (used for joining lines)
@@ -994,7 +999,8 @@ namespace CodeImp.DoomBuilder.Map
 		// front:		Side on which to remove or create the sidedef (true for front side)
 		// newside:		The side from which to copy the properties to the new sidedef.
 		//				If this is null, no sidedef will be created (only removed)
-		private void JoinChangeSidedefs(Linedef target, bool front, Sidedef newside)
+		// Returns false when the operation could not be completed.
+		private bool JoinChangeSidedefs(Linedef target, bool front, Sidedef newside)
 		{
 			Sidedef sd;
 			
@@ -1011,9 +1017,12 @@ namespace CodeImp.DoomBuilder.Map
 			if(newside != null)
 			{
 				sd = map.CreateSidedef(target, front, newside.Sector);
+				if(sd == null) return false;
 				newside.CopyPropertiesTo(sd);
 				sd.Marked = newside.Marked;
 			}
+
+			return true;
 		}
 
 		// String representation
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index 7cee2a802..920ecb74f 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -22,6 +22,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Text;
 using CodeImp.DoomBuilder.Geometry;
+using CodeImp.DoomBuilder.Windows;
 using SlimDX.Direct3D9;
 using CodeImp.DoomBuilder.Rendering;
 using SlimDX;
@@ -513,6 +514,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new vertex and returns it.</summary>
 		public Vertex CreateVertex(Vector2D pos)
 		{
+			if(numvertices == General.Map.FormatInterface.MaxVertices)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of vertices reached.");
+				return null;
+			}
+			
 			// Make the vertex
 			Vertex v = new Vertex(this, numvertices, pos);
 			AddItem(v, ref vertices, numvertices, ref numvertices);
@@ -522,6 +529,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new vertex and returns it.</summary>
 		public Vertex CreateVertex(int index, Vector2D pos)
 		{
+			if(numvertices == General.Map.FormatInterface.MaxVertices)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of vertices reached.");
+				return null;
+			}
+
 			// Make the vertex
 			Vertex v = new Vertex(this, index, pos);
 			AddItem(v, ref vertices, index, ref numvertices);
@@ -531,6 +544,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new linedef and returns it.</summary>
 		public Linedef CreateLinedef(Vertex start, Vertex end)
 		{
+			if(numlinedefs == General.Map.FormatInterface.MaxLinedefs)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of linedefs reached.");
+				return null;
+			}
+
 			// Make the linedef
 			Linedef l = new Linedef(this, numlinedefs, start, end);
 			AddItem(l, ref linedefs, numlinedefs, ref numlinedefs);
@@ -540,6 +559,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new linedef and returns it.</summary>
 		public Linedef CreateLinedef(int index, Vertex start, Vertex end)
 		{
+			if(numlinedefs == General.Map.FormatInterface.MaxLinedefs)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of linedefs reached.");
+				return null;
+			}
+
 			// Make the linedef
 			Linedef l = new Linedef(this, index, start, end);
 			AddItem(l, ref linedefs, index, ref numlinedefs);
@@ -549,6 +574,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new sidedef and returns it.</summary>
 		public Sidedef CreateSidedef(Linedef l, bool front, Sector s)
 		{
+			if(numsidedefs == int.MaxValue)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sidedefs reached.");
+				return null;
+			}
+			
 			// Make the sidedef
 			Sidedef sd = new Sidedef(this, numsidedefs, l, front, s);
 			AddItem(sd, ref sidedefs, numsidedefs, ref numsidedefs);
@@ -558,6 +589,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new sidedef and returns it.</summary>
 		public Sidedef CreateSidedef(int index, Linedef l, bool front, Sector s)
 		{
+			if(numsidedefs == int.MaxValue)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sidedefs reached.");
+				return null;
+			}
+
 			// Make the sidedef
 			Sidedef sd = new Sidedef(this, index, l, front, s);
 			AddItem(sd, ref sidedefs, index, ref numsidedefs);
@@ -575,7 +612,13 @@ namespace CodeImp.DoomBuilder.Map
 		public Sector CreateSector(int index)
 		{
 			int fixedindex;
-			
+
+			if(numsectors == General.Map.FormatInterface.MaxSectors)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sectors reached.");
+				return null;
+			}
+
 			// Do we have any index holes we can use?
 			if(indexholes.Count > 0)
 			{
@@ -596,6 +639,12 @@ namespace CodeImp.DoomBuilder.Map
 		// This creates a new sector with a specific fixed index
 		private Sector CreateSectorEx(int fixedindex, int index)
 		{
+			if(numsectors == General.Map.FormatInterface.MaxSectors)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of sectors reached.");
+				return null;
+			}
+
 			// Make the sector
 			Sector s = new Sector(this, index, fixedindex);
 			AddItem(s, ref sectors, index, ref numsectors);
@@ -605,6 +654,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new thing and returns it.</summary>
 		public Thing CreateThing()
 		{
+			if(numthings == General.Map.FormatInterface.MaxThings)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached.");
+				return null;
+			}
+
 			// Make the thing
 			Thing t = new Thing(this, numthings);
 			AddItem(t, ref things, numthings, ref numthings);
@@ -614,6 +669,12 @@ namespace CodeImp.DoomBuilder.Map
 		/// <summary>This creates a new thing and returns it.</summary>
 		public Thing CreateThing(int index)
 		{
+			if(numthings == General.Map.FormatInterface.MaxThings)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached.");
+				return null;
+			}
+
 			// Make the thing
 			Thing t = new Thing(this, index);
 			AddItem(t, ref things, index, ref numthings);
@@ -1841,9 +1902,9 @@ namespace CodeImp.DoomBuilder.Map
 		#region ================== Stitching
 
 		/// <summary>
-		/// Stitches marked geometry with non-marked geometry. Returns the number of stitches made.
+		/// Stitches marked geometry with non-marked geometry. Returns false when the operation failed.
 		/// </summary>
-		public int StitchGeometry()
+		public bool StitchGeometry()
 		{
 			ICollection<Linedef> movinglines;
 			ICollection<Linedef> fixedlines;
@@ -1851,7 +1912,6 @@ namespace CodeImp.DoomBuilder.Map
 			ICollection<Vertex> movingverts;
 			ICollection<Vertex> fixedverts;
 			RectangleF editarea;
-			int stitches = 0;
 			int stitchundo;
 
 			// Find vertices
@@ -1871,7 +1931,7 @@ namespace CodeImp.DoomBuilder.Map
 			
 			// Join nearby vertices
 			BeginAddRemove();
-			stitches += MapSet.JoinVertices(fixedverts, movingverts, true, MapSet.STITCH_DISTANCE);
+			MapSet.JoinVertices(fixedverts, movingverts, true, MapSet.STITCH_DISTANCE);
 			EndAddRemove();
 			
 			// Update cached values of lines because we need their length/angle
@@ -1881,21 +1941,24 @@ namespace CodeImp.DoomBuilder.Map
 			
 			// Split moving lines with unselected vertices
 			nearbyfixedverts = MapSet.FilterByArea(fixedverts, ref editarea);
-			stitches += MapSet.SplitLinesByVertices(movinglines, nearbyfixedverts, MapSet.STITCH_DISTANCE, movinglines);
+			if(!MapSet.SplitLinesByVertices(movinglines, nearbyfixedverts, MapSet.STITCH_DISTANCE, movinglines))
+				return false;
 			
 			// Split non-moving lines with selected vertices
 			fixedlines = MapSet.FilterByArea(fixedlines, ref editarea);
-			stitches += MapSet.SplitLinesByVertices(fixedlines, movingverts, MapSet.STITCH_DISTANCE, movinglines);
+			if(!MapSet.SplitLinesByVertices(fixedlines, movingverts, MapSet.STITCH_DISTANCE, movinglines))
+				return false;
 			
 			// Remove looped linedefs
-			stitches += MapSet.RemoveLoopedLinedefs(movinglines);
+			MapSet.RemoveLoopedLinedefs(movinglines);
 			
 			// Join overlapping lines
-			stitches += MapSet.JoinOverlappingLines(movinglines);
+			if(!MapSet.JoinOverlappingLines(movinglines))
+				return false;
 			
 			EndAddRemove();
 			
-			return stitches;
+			return true;
 		}
 		
 		#endregion
@@ -1951,10 +2014,9 @@ namespace CodeImp.DoomBuilder.Map
 			return count;
 		}
 
-		/// <summary>This joins overlapping lines together and returns the number of joins made.</summary>
-		public static int JoinOverlappingLines(ICollection<Linedef> lines)
+		/// <summary>This joins overlapping lines together. Returns false when the operation failed.</summary>
+		public static bool JoinOverlappingLines(ICollection<Linedef> lines)
 		{
-			int joinsdone = 0;
 			bool joined;
 			
 			do
@@ -1980,7 +2042,7 @@ namespace CodeImp.DoomBuilder.Map
 								
 								// Merge these two linedefs
 								while(lines.Remove(l2)) ;
-								l2.Join(l1);
+								if(!l2.Join(l1)) return false;
 								
 								// If l2 was marked as new geometry, we have to make sure
 								// that l1's FrontInterior is correct for the drawing procedure
@@ -1999,7 +2061,6 @@ namespace CodeImp.DoomBuilder.Map
 									}
 								}
 								
-								joinsdone++;
 								joined = true;
 								break;
 							}
@@ -2024,7 +2085,7 @@ namespace CodeImp.DoomBuilder.Map
 								
 								// Merge these two linedefs
 								while(lines.Remove(l2)) ;
-								l2.Join(l1);
+								if(!l2.Join(l1)) return false;
 
 								// If l2 was marked as new geometry, we have to make sure
 								// that l1's FrontInterior is correct for the drawing procedure
@@ -2043,7 +2104,6 @@ namespace CodeImp.DoomBuilder.Map
 									}
 								}
 
-								joinsdone++;
 								joined = true;
 								break;
 							}
@@ -2057,7 +2117,7 @@ namespace CodeImp.DoomBuilder.Map
 			while(joined);
 
 			// Return result
-			return joinsdone;
+			return true;
 		}
 
 		/// <summary>This removes looped linedefs (linedefs which reference the same vertex for
@@ -2184,11 +2244,10 @@ namespace CodeImp.DoomBuilder.Map
 		}
 
 		/// <summary>This splits the given lines with the given vertices. All affected lines
-		/// will be added to changedlines. Returns the number of splits made</summary>
-		public static int SplitLinesByVertices(ICollection<Linedef> lines, ICollection<Vertex> verts, float splitdist, ICollection<Linedef> changedlines)
+		/// will be added to changedlines. Returns false when the operation failed.</summary>
+		public static bool SplitLinesByVertices(ICollection<Linedef> lines, ICollection<Vertex> verts, float splitdist, ICollection<Linedef> changedlines)
 		{
 			float splitdist2 = splitdist * splitdist;
-			int splitsdone = 0;
 			bool splitted;
 
 			do
@@ -2215,6 +2274,7 @@ namespace CodeImp.DoomBuilder.Map
 							{
 								// Split line l with vertex v
 								Linedef nl = l.Split(v);
+								if(nl == null) return false;
 
 								// Add the new line to the list
 								lines.Add(nl);
@@ -2232,7 +2292,6 @@ namespace CodeImp.DoomBuilder.Map
 								}
 
 								// Count the split
-								splitsdone++;
 								splitted = true;
 								break;
 							}
@@ -2246,9 +2305,8 @@ namespace CodeImp.DoomBuilder.Map
 				}
 			}
 			while(splitted);
-
-			// Return result
-			return splitsdone;
+			
+			return true;
 		}
 
 		/// <summary>This finds the side closest to the specified position.</summary>
diff --git a/Source/Core/Windows/LinedefEditForm.cs b/Source/Core/Windows/LinedefEditForm.cs
index 4cc1e0435..6b4ad2064 100644
--- a/Source/Core/Windows/LinedefEditForm.cs
+++ b/Source/Core/Windows/LinedefEditForm.cs
@@ -397,21 +397,29 @@ namespace CodeImp.DoomBuilder.Windows
 				{
 					// Make sure we have a valid sector (make a new one if needed)
 					if(l.Front != null) index = l.Front.Sector.Index; else index = -1;
-					s = General.Map.Map.GetSectorByIndex(frontsector.GetResult(index));
-					if(s == null) s = General.Map.Map.CreateSector();
-					
-					// Create new sidedef?
-					if(l.Front == null) General.Map.Map.CreateSidedef(l, true, s);
-
-					// Change sector?
-					if(l.Front.Sector != s) l.Front.SetSector(s);
-
-					// Apply settings
-					l.Front.OffsetX = General.Clamp(frontoffsetx.GetResult(l.Front.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
-					l.Front.OffsetY = General.Clamp(frontoffsety.GetResult(l.Front.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
-					l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
-					l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
-					l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+					index = frontsector.GetResult(index);
+					if((index > -1) && (index < General.Map.Map.Sectors.Count))
+					{
+						s = General.Map.Map.GetSectorByIndex(index);
+						if(s == null) s = General.Map.Map.CreateSector();
+						if(s != null)
+						{
+							// Create new sidedef?
+							if(l.Front == null) General.Map.Map.CreateSidedef(l, true, s);
+							if(l.Front != null)
+							{
+								// Change sector?
+								if(l.Front.Sector != s) l.Front.SetSector(s);
+
+								// Apply settings
+								l.Front.OffsetX = General.Clamp(frontoffsetx.GetResult(l.Front.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
+								l.Front.OffsetY = General.Clamp(frontoffsety.GetResult(l.Front.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
+								l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+								l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+								l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+							}
+						}
+					}
 				}
 
 				// Remove back side?
@@ -424,21 +432,29 @@ namespace CodeImp.DoomBuilder.Windows
 				{
 					// Make sure we have a valid sector (make a new one if needed)
 					if(l.Back != null) index = l.Back.Sector.Index; else index = -1;
-					s = General.Map.Map.GetSectorByIndex(backsector.GetResult(index));
-					if(s == null) s = General.Map.Map.CreateSector();
-
-					// Create new sidedef?
-					if(l.Back == null) General.Map.Map.CreateSidedef(l, false, s);
-
-					// Change sector?
-					if(l.Back.Sector != s) l.Back.SetSector(s);
-
-					// Apply settings
-					l.Back.OffsetX = General.Clamp(backoffsetx.GetResult(l.Back.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
-					l.Back.OffsetY = General.Clamp(backoffsety.GetResult(l.Back.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
-					l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
-					l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
-					l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+					index = backsector.GetResult(index);
+					if((index > -1) && (index < General.Map.Map.Sectors.Count))
+					{
+						s = General.Map.Map.GetSectorByIndex(index);
+						if(s == null) s = General.Map.Map.CreateSector();
+						if(s != null)
+						{
+							// Create new sidedef?
+							if(l.Back == null) General.Map.Map.CreateSidedef(l, false, s);
+							if(l.Back != null)
+							{
+								// Change sector?
+								if(l.Back.Sector != s) l.Back.SetSector(s);
+
+								// Apply settings
+								l.Back.OffsetX = General.Clamp(backoffsetx.GetResult(l.Back.OffsetX), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
+								l.Back.OffsetY = General.Clamp(backoffsety.GetResult(l.Back.OffsetY), General.Map.FormatInterface.MinTextureOffset, General.Map.FormatInterface.MaxTextureOffset);
+								l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+								l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+								l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+							}
+						}
+					}
 				}
 
 				// Custom fields
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
index 4e6467c32..bb0c690ee 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
@@ -174,21 +174,27 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				// Make a new one
 				Thing t = General.Map.Map.CreateThing();
-				t.Type = General.Map.Config.Start3DModeThingType;
-				t.Move(mousemappos);
-				t.UpdateConfiguration();
-				General.Map.ThingsFilter.Update();
-				thingfound = t;
+				if(t != null)
+				{
+					t.Type = General.Map.Config.Start3DModeThingType;
+					t.Move(mousemappos);
+					t.UpdateConfiguration();
+					General.Map.ThingsFilter.Update();
+					thingfound = t;
+				}
 			}
 
-			// Make sure that the found thing is between ceiling and floor
-			thingfound.DetermineSector();
-			if(thingfound.Position.z < 0.0f) thingfound.Move(thingfound.Position.x, thingfound.Position.y, 0.0f);
-			if(thingfound.Sector != null)
+			if(thingfound != null)
 			{
-				if((thingfound.Position.z + 50.0f) > (thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight))
-					thingfound.Move(thingfound.Position.x, thingfound.Position.y,
-						thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight - 50.0f);
+				// Make sure that the found thing is between ceiling and floor
+				thingfound.DetermineSector();
+				if(thingfound.Position.z < 0.0f) thingfound.Move(thingfound.Position.x, thingfound.Position.y, 0.0f);
+				if(thingfound.Sector != null)
+				{
+					if((thingfound.Position.z + 50.0f) > (thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight))
+						thingfound.Move(thingfound.Position.x, thingfound.Position.y,
+							thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight - 50.0f);
+				}
 			}
 			
 			// Update Visual Mode camera
diff --git a/Source/Plugins/BuilderModes/ClassicModes/CurveLinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/CurveLinedefsMode.cs
index b3588c1b3..1bdde18f7 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/CurveLinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/CurveLinedefsMode.cs
@@ -211,9 +211,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					{
 						// Make vertex
 						Vertex v = General.Map.Map.CreateVertex(points[i]);
-
+						if(v == null)
+						{
+							General.Map.UndoRedo.WithdrawUndo();
+							return;
+						}
+						
 						// Split the line and move on with this line
 						splitline = splitline.Split(v);
+						if(splitline == null)
+						{
+							General.Map.UndoRedo.WithdrawUndo();
+							return;
+						}
 					}
 				}
 			}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index 0ba819b46..e81cd199c 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -460,7 +460,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " drawing.");
 				
 				// Make the drawing
-				Tools.DrawLines(points);
+				if(!Tools.DrawLines(points))
+				{
+					// Drawing failed
+					// NOTE: I have to call this twice, because the first time only cancels this volatile mode
+					General.Map.UndoRedo.WithdrawUndo();
+					General.Map.UndoRedo.WithdrawUndo();
+					return;
+				}
 
 				// Snap to map format accuracy
 				General.Map.Map.SnapAllToAccuracy();
diff --git a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
index ec8bb34fa..9121f1d4f 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
@@ -894,7 +894,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			}
 			else
 			{
-				General.Interface.DisplayStatus(StatusType.Warning, "Please make a selection first!");
+				General.Interface.MessageBeep(MessageBeepType.Default);
 				
 				// Cancel now
 				General.Editing.CancelMode();
diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
index 7004e5716..66a29718d 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
@@ -743,12 +743,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						// Split in middle of line
 						splitvertex = General.Map.Map.CreateVertex(ld.GetCenterPoint());
 					}
+
+					if(splitvertex == null)
+					{
+						General.Map.UndoRedo.WithdrawUndo();
+						break;
+					}
 					
 					// Snap to map format accuracy
 					splitvertex.SnapToAccuracy();
-					
+
 					// Split the line
-					ld.Split(splitvertex);
+					Linedef sld = ld.Split(splitvertex);
+					if(sld == null)
+					{
+						General.Map.UndoRedo.WithdrawUndo();
+						break;
+					}
 				}
 
 				// Update cache values
diff --git a/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs b/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs
index 9e8444768..aa766efab 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs
@@ -242,23 +242,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			// Make the sector
 			Sector s = Tools.MakeSector(allsides, oldlines);
-			
-			// Now we go for all the lines along the sector to
-			// see if they only have a back side. In that case we want
-			// to flip the linedef to that it only has a front side.
-			foreach(Sidedef sd in s.Sidedefs)
+			if(s != null)
 			{
-				if((sd.Line.Front == null) && (sd.Line.Back != null))
+				// Now we go for all the lines along the sector to
+				// see if they only have a back side. In that case we want
+				// to flip the linedef to that it only has a front side.
+				foreach(Sidedef sd in s.Sidedefs)
 				{
-					// Flip linedef
-					sd.Line.FlipVertices();
-					sd.Line.FlipSidedefs();
+					if((sd.Line.Front == null) && (sd.Line.Back != null))
+					{
+						// Flip linedef
+						sd.Line.FlipVertices();
+						sd.Line.FlipSidedefs();
+					}
 				}
+
+				General.Map.Data.UpdateUsedTextures();
+				General.Interface.SetCursor(Cursors.Default);
+				return s;
+			}
+			else
+			{
+				General.Map.UndoRedo.WithdrawUndo();
+				return null;
 			}
-			
-			General.Map.Data.UpdateUsedTextures();
-			General.Interface.SetCursor(Cursors.Default);
-			return s;
 		}
 		
 		#endregion
@@ -376,17 +383,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					// Make the sector
 					Sector s = MakeSector();
+					if(s != null)
+					{
+						// Quickly flash this sector to indicate it was created
+						General.Map.IsChanged = true;
+						General.Map.Map.Update();
+						General.Interface.RedrawDisplay();
+						flashpolygon = new FlatVertex[s.FlatVertices.Length];
+						s.FlatVertices.CopyTo(flashpolygon, 0);
+						flashintensity = 1.0f;
+						flashstarttime = (double)General.Clock.GetCurrentTime();
+						General.Interface.EnableProcessing();
+					}
 					
-					// Quickly flash this sector to indicate it was created
-					General.Map.IsChanged = true;
-					General.Map.Map.Update();
-					General.Interface.RedrawDisplay();
-					flashpolygon = new FlatVertex[s.FlatVertices.Length];
-					s.FlatVertices.CopyTo(flashpolygon, 0);
-					flashintensity = 1.0f;
-					flashstarttime = (double)General.Clock.GetCurrentTime();
-					General.Interface.EnableProcessing();
-
 					// Redraw overlay
 					DrawGeometry();
 					DrawOverlay();
@@ -418,28 +427,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					// Make the sector
 					Sector s = MakeSector();
-					General.Map.Map.Update();
-					
-					// Edit the sector
-					List<Sector> secs = new List<Sector>(); secs.Add(s);
-					if(General.Interface.ShowEditSectors(secs) == DialogResult.OK)
+					if(s != null)
 					{
-						// Quickly flash this sector to indicate it was created
-						General.Map.IsChanged = true;
 						General.Map.Map.Update();
-						flashpolygon = new FlatVertex[s.FlatVertices.Length];
-						s.FlatVertices.CopyTo(flashpolygon, 0);
-						flashintensity = 1.0f;
-						flashstarttime = (double)General.Clock.GetCurrentTime();
-						General.Interface.EnableProcessing();
-					}
-					else
-					{
-						// Undo
-						General.Map.UndoRedo.PerformUndo();
-						General.Map.UndoRedo.ClearAllRedos();
-					}
 
+						// Edit the sector
+						List<Sector> secs = new List<Sector>(); secs.Add(s);
+						if(General.Interface.ShowEditSectors(secs) == DialogResult.OK)
+						{
+							// Quickly flash this sector to indicate it was created
+							General.Map.IsChanged = true;
+							General.Map.Map.Update();
+							flashpolygon = new FlatVertex[s.FlatVertices.Length];
+							s.FlatVertices.CopyTo(flashpolygon, 0);
+							flashintensity = 1.0f;
+							flashstarttime = (double)General.Clock.GetCurrentTime();
+							General.Interface.EnableProcessing();
+						}
+						else
+						{
+							// Undo
+							General.Map.UndoRedo.WithdrawUndo();
+						}
+					}
+					
 					// Redraw overlay
 					DrawGeometry();
 					DrawOverlay();
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index 3cab16565..4b2a0d333 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -649,27 +649,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				return null;
 			}
 
-			// Create things at mouse position
+			// Create thing
 			Thing t = General.Map.Map.CreateThing();
-			General.Settings.ApplyDefaultThingSettings(t);
-			t.Move(pos);
-			t.UpdateConfiguration();
+			if(t != null)
+			{
+				General.Settings.ApplyDefaultThingSettings(t);
+				
+				t.Move(pos);
+				
+				t.UpdateConfiguration();
 
-			// Update things filter so that it includes this thing
-			General.Map.ThingsFilter.Update();
+				// Update things filter so that it includes this thing
+				General.Map.ThingsFilter.Update();
 
-			// Snap to grid enabled?
-			if(General.Interface.SnapToGrid)
-			{
-				// Snap to grid
-				t.SnapToGrid();
-			}
-			else
-			{
-				// Snap to map format accuracy
-				t.SnapToAccuracy();
+				// Snap to grid enabled?
+				if(General.Interface.SnapToGrid)
+				{
+					// Snap to grid
+					t.SnapToGrid();
+				}
+				else
+				{
+					// Snap to map format accuracy
+					t.SnapToAccuracy();
+				}
 			}
-
+			
 			return t;
 		}
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
index 45b98bbe8..cb10aae0c 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
@@ -309,16 +309,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 					// Make the vertex
 					Vertex v = General.Map.Map.CreateVertex(insertpos);
-
+					if(v == null)
+					{
+						General.Map.UndoRedo.WithdrawUndo();
+						return;
+					}
+					
 					// Snap to map format accuracy
 					v.SnapToAccuracy();
 
 					// Split the line with this vertex
-					l.Split(v);
+					Linedef sld = l.Split(v);
+					if(sld == null)
+					{
+						General.Map.UndoRedo.WithdrawUndo();
+						return;
+					}
 					
 					// Update
 					General.Map.Map.Update();
-					
+
 					// Highlight it
 					Highlight(v);
 
@@ -616,9 +626,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Just insert here, don't snap to anything
 					insertpos = mousemappos;
 				}
-				
+
 				// Make the vertex
 				Vertex v = General.Map.Map.CreateVertex(insertpos);
+				if(v == null)
+				{
+					General.Map.UndoRedo.WithdrawUndo();
+					return;
+				}
 
 				// Snap to map format accuracy
 				v.SnapToAccuracy();
@@ -636,7 +651,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				// Update
 				General.Map.Map.Update();
-				
+
 				// Redraw screen
 				General.Interface.RedrawDisplay();
 			}
diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingFront.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingFront.cs
index fbe27d662..50535e98b 100644
--- a/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingFront.cs
+++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingFront.cs
@@ -134,6 +134,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			General.Map.UndoRedo.CreateUndo("Create front sidedef");
 			Sidedef newside = General.Map.Map.CreateSidedef(line, true, copysidedef.Sector);
+			if(newside == null) return false;
 			copysidedef.CopyPropertiesTo(newside);
 			line.ApplySidedFlags();
 			General.Map.Map.Update();
diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingSides.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingSides.cs
index 8b356ec91..8499cc551 100644
--- a/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingSides.cs
+++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultLineMissingSides.cs
@@ -163,6 +163,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Front
 				General.Map.UndoRedo.CreateUndo("Create front sidedef");
 				Sidedef newside = General.Map.Map.CreateSidedef(line, true, copysidedeffront.Sector);
+				if(newside == null) return false;
 				copysidedeffront.CopyPropertiesTo(newside);
 			}
 			else if(copysidedefback != null)
@@ -172,6 +173,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// We will then flip it to make sure to ends up in the right position.
 				General.Map.UndoRedo.CreateUndo("Create front sidedef");
 				Sidedef newside = General.Map.Map.CreateSidedef(line, true, copysidedefback.Sector);
+				if(newside == null) return false;
 				copysidedefback.CopyPropertiesTo(newside);
 				line.FlipVertices();
 			}
@@ -189,10 +191,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			// Front
 			newside = General.Map.Map.CreateSidedef(line, true, copysidedeffront.Sector);
+			if(newside == null) return false;
 			copysidedeffront.CopyPropertiesTo(newside);
 			
 			// Back
 			newside = General.Map.Map.CreateSidedef(line, false, copysidedefback.Sector);
+			if(newside == null) return false;
 			copysidedefback.CopyPropertiesTo(newside);
 			
 			line.ApplySidedFlags();
diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultLineNotDoubleSided.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultLineNotDoubleSided.cs
index 910dfb58d..3f719a571 100644
--- a/Source/Plugins/BuilderModes/ErrorChecks/ResultLineNotDoubleSided.cs
+++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultLineNotDoubleSided.cs
@@ -133,6 +133,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			General.Map.UndoRedo.CreateUndo("Create back sidedef");
 			Sidedef newside = General.Map.Map.CreateSidedef(line, false, copysidedef.Sector);
+			if(newside == null) return false;
 			copysidedef.CopyPropertiesTo(newside);
 			line.ApplySidedFlags();
 			General.Map.Map.Update();
-- 
GitLab