Decoupling an expression removes the crash (?)

Just starting out? Need help? Post your questions and find answers here.
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Decoupling an expression removes the crash (?)

Post by Joubarbe »

UPDATE: Reproducible crash: viewtopic.php?p=630156#p630156

Sorry for the silly title, it's hard to explain, and I cannot make a runnable code for you to experience the same thing. So please bear with me, I'm not asking for a magic solution, but just for a bit of light.

Code: Select all

If \x > 0
  ProcedureReturn *table\items(\x - 1, \y)
ElseIf \y > 0
  ProcedureReturn *table\items(ArraySize(*table\items(), 1), \y - 1) ; Crashes here 10/10, invalid memory access.
EndIf
This code is a snippet from a procedure where I use With *table\selected_item\pos, where selected_item is a pointer. I've tried without the With : EndWith, same result (someone mentioned that as a potential problem in a previous post).

Code: Select all

If \x > 0
  ProcedureReturn *table\items(\x - 1, \y)
ElseIf \y > 0
  Define debug_x = ArraySize(*table\items(), 1) ; DEBUG
  Define debug_y = \y - 1                       ; DEBUG
  ProcedureReturn *table\items(debug_x, debug_y) ; Does not crash 0/10.
EndIf
Would anyone have any idea why I have no invalid memory access in the second situation? What is the difference?

Also, what extra information is the Purifier supposed to give? From all the errors I had, the Purifier never ever gave me something else than the standard debugger would give. Is there extra info somewhere else that I need to look?
Last edited by Joubarbe on Fri Nov 01, 2024 2:08 pm, edited 2 times in total.
SMaag
Enthusiast
Enthusiast
Posts: 327
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Decoupling an expression removes the crash (?)

Post by SMaag »

PureBasic Version
ASM or C-Backend

Did you check ASM or C output?

Try

Code: Select all

define ret = *table\items(ArraySize(*table\items(), 1), \y - 1)
ProcedureReturn ret
User avatar
spikey
Enthusiast
Enthusiast
Posts: 778
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: Decoupling an expression removes the crash (?)

Post by spikey »

You'd have to examine the resultant assembler code to know the actual differences. In the first example I would expect the entire expression to be calculated via the stack whereas in the second the variable locations will be referenced as well in the calculation stages. This means that the compiler will emit slightly different assembler code in each case, even though the end result should be the same.

The purifier looks for overruns for various storages by tagging the ends of the storage allocation with a 'magic number'. If the storage's allocation is then subsequently overrun by some other action this will corrupt the 'magic number' and the purifier will notice this when it checks. For example, if a 'byte' size variable erroneously has a 'long' value written to its location, this would corrupt the variable and the 'magic number' following it.

What the purifier won't do is detect the modification of a pointer with a correct size but invalid semantic value because the 'magic number' will remain intact. I'm guessing that's what you are experiencing because a bad pointer value can lead to an IMA but, of course, I can't say for certain because I don't have a runnable case to test.

(However, please don't go away with the impression I'm saying you've a pointer problem in your source code - more or less everything is a pointer sooner or later at the assembly level).

As SMaag said - it would be useful to know if it's the calculation that causes the fault or the return.
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Decoupling an expression removes the crash (?)

Post by Joubarbe »

Thanks to both of you.

Code: Select all

Define ret = *table\items(ArraySize(*table\items(), 1), \y - 1) ; Crashes here.
ProcedureReturn ret
Doesn't crash with C backend.
PureBasic 6.12

I don't know ASM, so I couldn't really analyse the output, unfortunately. I had problems for a few weeks now, and my game is on Steam, so it's really frustrating. Maybe I should put a C version out, but I'm fairly certain that other errors will show at other places.

I don't do any manual memory allocation.

EDIT: I think I should ask: what are the things you can do wrong in PB with pointers? I mean something that can cause an IMA quite randomly. Empty pointers are detected, pointers with a wrong type are detected by PB (at least you have an error on the line when you call a property of a structure that don't belong to the pointer), I don't Peek/Poke, and I don't do arithmetic with them either. At this point, I don't really know where to look really.
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Decoupling an expression removes the crash (?)

Post by #NULL »

I don't have answers to your questions, but what happens if you leave the expression as is and use any/some/all of the following:

Code: Select all

; Debug \y
; Debug *table
; Debug *table\items()
; Debug ArraySize(*table\items(), 1)
; Debug \y - 1
; Debug ArraySize(*table\items(), 2)
ProcedureReturn *table\items(ArraySize(*table\items(), 1), \y - 1) ; Crashes here 10/10, invalid memory access.
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Decoupling an expression removes the crash (?)

Post by Joubarbe »

All debug lines pass, only the ProcedureReturn line crashes.
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Decoupling an expression removes the crash (?)

Post by #NULL »

And all the values are all right?
You don't use any threads?
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Decoupling an expression removes the crash (?)

Post by Joubarbe »

Code: Select all

7
2742047289200
2742042756752
1
6
7
I see no problem, the array is indeed 1, 7 of size.
I don't use any thread.
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Decoupling an expression removes the crash (?)

Post by #NULL »

Joubarbe wrote: Thu Oct 31, 2024 9:31 pm pointers with a wrong type are detected by PB (at least you have an error on the line when you call a property of a structure that don't belong to the pointer)
It checks the property for the type/structure you are using syntactically, but the underlying data could be of a different (wrong) type:

Code: Select all

Structure s1
  b1.b
  b2.b
  b3.b
  b4.b
EndStructure

a.s1
a\b2 = 1

Structure s2
  l.l
EndStructure

*l.s2 = @a
Debug *l\l ; 256
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Decoupling an expression removes the crash (?)

Post by #NULL »

Did you put PurifierGranularity(1, 1, 1, 1) before any other code?
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Decoupling an expression removes the crash (?)

Post by Joubarbe »

#NULL wrote: Thu Oct 31, 2024 11:06 pm Did you put PurifierGranularity(1, 1, 1, 1) before any other code?
No, I don't even know this command :|
Quin
Addict
Addict
Posts: 1135
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Decoupling an expression removes the crash (?)

Post by Quin »

Joubarbe wrote: Thu Oct 31, 2024 11:37 pm
#NULL wrote: Thu Oct 31, 2024 11:06 pm Did you put PurifierGranularity(1, 1, 1, 1) before any other code?
No, I don't even know this command :|
Whoa...me neither... :shock:
Type it in the PB IDE and press F1 and you'll get help for it, but I can't figure out where the main documentation actually links to it...


Edit: it's under the Debugger section. :D
SMaag
Enthusiast
Enthusiast
Posts: 327
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Decoupling an expression removes the crash (?)

Post by SMaag »

Define ret = *table\items(ArraySize(*table\items(), 1), \y - 1) ; Crashes here.
ProcedureReturn ret

PureBasic
Doesn't crash with C backend.
PureBasic 6.12
Now it seems more clear:
1. might be a problem of implicit type conversion, maybe one of the Array index isn't an Integer!
This would explain why your Debug code works.
2. possible bug in PB ASM

You didn't tell your defintitions:
how items() is defined?
Whats the type of \y?

Can you provide a demo code with all the definitions what shows the error?
Can you proivde the ASM Output code from that?
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Decoupling an expression removes the crash (?)

Post by #NULL »

SMaag wrote: Fri Nov 01, 2024 10:58 am You didn't tell your defintitions:
how items() is defined?
Whats the type of \y?
Also, besides the type of \items(), does the procedure have a return type defined? And what's the expression where the function call and return value is used?

Another thing to try:

Code: Select all

Procedure pass(i.i)
  ; Debug i
  ProcedureReturn i
EndProcedure

;...

  ProcedureReturn pass(*table\items(ArraySize(*table\items(), 1), \y - 1))
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Decoupling an expression removes the crash (?)

Post by Joubarbe »

Ok, thanks a lot guys.

@SMaag:

This is the main structures involved in that function: (the table is at the bottom)

Code: Select all

Structure _XY
  x.i
  y.i
EndStructure
  
Structure _Item
  text$
  text_without_tags$
  *callback_submit.__Item
  *callback_select.__Item
  *callback_color.__Generic
  *callback_text.__GenericText
  custom_value_submit.i
  custom_value_select.i
  custom_value_color.i
  custom_value_text.i
  disabled.b
  *page
  color.i
  background_color.i
  align_x.i
  no_process.b
  underlined.b
  List formatted_words._FormattedWord()
EndStructure

Structure _Control
  type.i
  origin_pos._XY
  processed.b
EndStructure
  
Structure _TableItem Extends _Item
  pos._XY
  header.b
  separator._Separator
  no_truncation.b                          ; If #False, then the part of text$ that is beyond column width will be truncated with a "." character.
EndStructure

Structure _Table Extends _Control
  centered.b
  unselectable.b
  cols.i
  rows.i
  separator$
  vertical_layout.b
  *selected_item._TableItem
  Array col_sizes.i(0)
  Array items._TableItem(0, 0)
  items_background_color.i
  ; List "key browsing" purposes: (see FindNextTableItemFromHotkey())
  char_pressed$    
  char_pressed_time_ms.i
  char_pressed_index.i
  char_pressed_item_index.i
  char_pressed_same.b
EndStructure
So the items() array is defined as: Array items._TableItem(0, 0) that I "Dim" dynamically when needed. And \pos\y is an integer.

The function that crashes returns a pointer to a _TableItem. Here is the full function:

Code: Select all

Procedure.i GetPreviousTableItem(*table._Table) : With *table\selected_item\pos
  If *table\selected_item = #Null : DebuggerError("The table has no selected element.") : EndIf
  
  If *table\vertical_layout = #True
    If \y > 0
      ProcedureReturn *table\items(\x, \y - 1)
    ElseIf \x > 0
      ProcedureReturn *table\items(\x - 1, ArraySize(*table\items(), 2))
    EndIf
  Else
    If \x > 0
      ProcedureReturn *table\items(\x - 1, \y)
    ElseIf \y > 0
      ProcedureReturn *table\items(ArraySize(*table\items(), 1), \y - 1)
    EndIf
  EndIf
  
  ProcedureReturn #Null
EndWith : EndProcedure
Please remind me how to get the ASM output? And how to isolate this piece of code particularly?

@#NULL
I think the above answers your first question.
The program crashes exactly at the same line, ie. at "ProcedureReturn pass(......)"

I'm going to try to make a runnable code that imitates the same structure. I don't think it will crash, but hopefully it will...
Post Reply