Program crashes on string manipulation

BlitzMax Forums/Brucey's Modules/Program crashes on string manipulation

seriouslee(Posted 2016) [#1]
I have a routine that is parsing a bitmapfont definition file with lots of strings such as:

char id=33 x=2 y=2 width=3 height=12 xoffset=1 yoffset=3 xadvance=5 page=0 chnl=15


using

local sections:String[] = lines[i].Split(" ")
local parms:String[] = sections[0].Split("=")


I have if statements checking to see if sections and parms are populated (Length > 0) before accessing elements.

The program crashes with an exception_access_violation error IF I use sdl.gl2sdlmax2d, brl.d3d9max2d, or srs.d3d11max2d. It will execute cleanly if I use brl.glmax2d.

I'm using bcc v. 0.84, bmk v. 3.16; compiling 64 bit on Windows 10.

Any thoughts?


seriouslee(Posted 2016) [#2]
Additional info: Occasionally it will give me debugging information. When it does, the sections variable shows as null in the debugger and the program line highlighted is passed 2 different checks to see if sections is populated with elements.

Here is the full loop for review:
Local contents:String
Try
	contents = LoadText("res/fonts/" + name + ".fnt")
Catch err:TStreamReadException
	RuntimeError("Read Exception: " + err.ToString())
End Try
Local lines:String[] = contents.Split("~n")
contents = Null
Local numGlyphs:Int, index:Int = 0
Local txWidth:Float, txHeight:Float

For Local i:Int = 0 Until lines.Length
	lines[i] = lines[i].Trim()
	lines[i] = lines[i].Replace("~r", "")
	Local sections:String[] = lines[i].Split(" ")
	If (sections.Length < 1)
		DebugStop()
	EndIf
	Select sections[0]
	Case "common"
	       Local parms:String[] = sections[1].Split("=")
		lineHeight = Float(parms[1])
	Case "page"
		Local parms:String[] = sections[2].Split("=")
		Local texFileName:String = parms[1].Replace("~q", "")
		texture = LoadImage("res/fonts/" + texFileName)
		If (texture = Null)
			RuntimeError("Error loading font texture file " + texFileName)
		EndIf
	Case "chars"
		Local parms:String[] = sections[1].Split("=")
		numGlyphs = Int(parms[1])
		glyphs = New Glyph[numGlyphs]
	Case "char"
		If (sections.Length < 9)
			DebugLog("Error parsing line " + sections[0])
			Continue
		EndIf
		Local id:Int = Int(GetValue(sections[1]))
		If (id < 32)
			Continue
		EndIf
		If (id < minId)
			minId = id
		ElseIf (id > maxId)
			maxId = id
		EndIf
		If (index = glyphs.length)
			RuntimeError("BitmapFont New: more glyphs than " + numGlyphs)
		EndIf
		glyphs[index] = New Glyph
		glyphs[index].id = id
		glyphs[index].x = Int(GetValue(sections[2])) <-- typically where the debugger might kick in
		glyphs[index].y = Int(GetValue(sections[3]))
		glyphs[index].width = Int(GetValue(sections[4]))
		glyphs[index].height = Int(GetValue(sections[5]))
		glyphs[index].xOffset = Float(GetValue(sections[6]))
		glyphs[index].yOffset = Float(GetValue(sections[7]))
		glyphs[index].advance = Float(GetValue(sections[8]))
		index :+ 1
	End Select
Next



seriouslee(Posted 2016) [#3]
FYI: Glyph is a Type with the following definition:

Type Glyph
	Field id:Int
	Field x:Float, y:Float
	Field width:Float, height:Float
	Field xOffset:Float, yOffset:Float
	Field advance:Float
End Type


And unfortunately the error is now consistent no matter which graphics driver I select. :\


col(Posted 2016) [#4]
Unfortunately the error is now consistent no matter which graphics driver I select. :\

I'd actually class that as fortunate :-)
Intermittent bugs are the worse to find, consistent bugs are much 'easier' by comparison.

Have you tried the same code with the legacy 'Max compiler?


seriouslee(Posted 2016) [#5]
Thanks, Col. Putting the code in legacy yielded more debug info. The last line of the file was not being processed correctly making the last array element null. So there you go. Now it runs in NG without issue.

Thanks!!

But that raises a question about the NG debugger: it doesn't seem to catch what it should. Too bad, I have been programming for NG and some of my code doesn't run in legacy. Is that something that is planned on being fixed / updated?


col(Posted 2016) [#6]
Cool that you got it fixed.

If you have raised an issue within the repo itself then Brucey is pretty hot on fixing things up so, at a guess, I'd say yes it will be fixed.


seriouslee(Posted 2016) [#7]
I've tested the max legacy code in NG and it runs without issues no matter what graphics driver and I've applied NG method overloading back to the classes (Types) without issue as well.

I think where I get into trouble is with Structs. I originally created Structs for small classes like 2D Vectors, and Color class and a Glyph class for bitmap font definitions. When I use Structs, I get odd errors that are hard to pin down. If I stick with Types only I can run the code without issues. So how / when do you use them correctly?


Brucey(Posted 2016) [#8]
Hallo, is it possible to provide a small working example which shows the issue you were having?

Things to note about Struct - since it is not a "pointer" to data, a test for Null-ness is invalid - because a Struct can never be Null. On initialisation, all the fields of a Struct will be zeroed (unless you have a constructor which does otherwise).

An array of Structs is basically a single block of memory where every x bytes represents the content of the next Struct - whereas an array of Types, is just a list of Object references/pointers.

Used in the right context, small Structs are far more efficient than creating/collecting similar amounts of Types/Objects.