News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Instring

Started by guga, August 04, 2023, 02:30:50 AM

Previous topic - Next topic

jj2007

Quote from: Biterider on August 06, 2023, 08:52:20 PMAs it stands now, I strongly recommend not using these implementations for general purposes, as this will lead to unexplained and random crashes in customer code, resulting in a sh*storm.

I've used them for over a year in all my code, no crashes. HeapAlloc'ed strings and buffers are not a problem, in contrast to this:
  invoke VirtualAlloc, 0, 4096, MEM_COMMIT, PAGE_READWRITE
  xchg eax, edi
  Let esi=FileRead$("\Masm32\include\Windows.inc")
  invoke lstrcpyn, edi, esi, 4096 ; esi is a pointer e.g. to contents of Windows.inc
  Let sub2$="ACMFILTERCHOOSEHOOKPROC     typ" ; "typ" is ok, "type" fails with an exception
  Print Str$("The pos is %i\n", Instr_(edi, sub2$))

The solution is SEH.

Biterider

Hi JJ
It is only a matter of time before this code bites you.  :badgrin:

If the SEH handler has to catch this situation, what should it do? Fall back on the regular implementation?
Thinking about that, you have to protect every single call to these new procedures...
A higher level handler is also possible, but the complexity does not justify it.

Another side effect is that thousands and thousands of CPU cycles are wasted when triggering the SEH mechanism.

Still not a good solution for production code...

Biterider

jj2007

Quote from: Biterider on August 06, 2023, 10:29:37 PMIf the SEH handler has to catch this situation, what should it do? Fall back on the regular implementation?

Return zero = not found.

QuoteThinking about that, you have to protect every single call to these new procedures...

Once, at program start.

QuoteAnother side effect is that thousands and thousands of CPU cycles are wasted when triggering the SEH mechanism.

Nope, the timings are exactly the same if a match is found. If no match is found and the SEH is triggered, then you have a design problem.

  invoke VirtualAlloc, 0, 4096, MEM_COMMIT, PAGE_READWRITE
  xchg eax, edi
  Let esi=FileRead$("\Masm32\include\Windows.inc")
  invoke lstrcpyn, edi, esi, 4096 ; esi is a pointer e.g. to contents of Windows.inc
  Let sub32$="ACMFILTERCHOOSEHOOKPROC     type" ; type fails with an exception, "typ" is ok
  Let sub31$=Left$(sub32$, 31)
  Print Str$("For 31 chars, the pos is %i\n", Instr_(edi, sub31$))
  Print Str$("For 32 chars, the pos is %i\n", Instr_(edi, sub32$))
  Inkey "That was fun with SEH"

Output:
For 31 chars, the pos is 4058
Caught at pos:  $esi            def DW
For 32 chars, the pos is 0
That was fun with SEH

Biterider

#18
Quote from: jj2007 on August 06, 2023, 11:27:25 PM
QuoteIf the SEH handler has to catch this situation, what should it do? Fall back on the regular implementation?

Return zero = not found.

It is obviously wrong to always return 0 when you have a match, which leads to wrong results.

Quote from: jj2007 on August 06, 2023, 11:27:25 PM
QuoteThinking about that, you have to protect every single call to these new procedures...

Once, at program start.

You are talking about a TL-handler that has to deal with all kinds of exceptions coming from somewhere in your application.
This means that you have to analyse exactly where the exception occurred and what went wrong, and then unwind the whole thing to the offending procedure, which is a leaf procedure.

Quote from: jj2007 on August 06, 2023, 11:27:25 PM
QuoteAnother side effect is that thousands and thousands of CPU cycles are wasted when triggering the SEH mechanism.

Nope, the timings are exactly the same if a match is found. If no match is found and the SEH is triggered, then you have a design problem.

You misinterpreted my comment, I said when an exception is triggered. That comes from the transitions from user-land to ring 0 and vice-versa.

The whole thing is not about SEH, it is about code quality degradation.  :nie:
It is expected that when a proc that works perfectly fine is replaced by a better/faster version that it returns exactly the same results.
It makes no sense to replace it with a faster version that may work 99.9% but fails under some conditions the user has no control over.  :eusa_naughty:

For sure there are cases where a wrong result can be tolerated, but imagine you use this code in a critical process and this super fast routine fails 1/1000 times crashing a machine/car/rocket.
No one in their right mind would use it as a general purpose routine for a few microseconds that don't matter in the end.

I don't want to hurt anyone's feelings, but wouldn't it be better to find a better and suitable solution?  :wink2:

Biterider

jj2007

Hi Biterider, it seems I edited your post and made a mess out of it - apologies.


QuoteIt is obviously wrong to always return 0 when you have a match, which leads to wrong results.

Describe a situation where an exception was triggered but there still was a match.

QuoteYou are talking about a TL-handler that has to deal with all kinds of exceptions coming from somewhere in your application.
This means that you have to analyse exactly where the exception occurred and what went wrong, and then unwind the whole thing to the offending procedure, which is a leaf procedure.

You didn't check the attachment posted above.

Quote
Quote from: jj2007 on August 06, 2023, 11:27:25 PM
QuoteAnother side effect is that thousands and thousands of CPU cycles are wasted when triggering the SEH mechanism.

Nope, the timings are exactly the same if a match is found. If no match is found and the SEH is triggered, then you have a design problem.

You misinterpreted my comment, I said when an exception is triggered. That comes from the transitions from user-land to ring 0 and vice-versa.

Yes, we are wasting a millisecond or so in the extremely unlikely event of an exception.

Biterider

Quote from: jj2007 on August 07, 2023, 06:11:13 AMDescribe a situation where an exception was triggered but there still was a match.
Suppose you have an ANSI zero terminated string "abcABC" at the end of a page and the next page is not commited.
Now you start searching for "ABC" at a 16 byte unaligned address. You overshoot the page boundary by 9 bytes raising an exception and you should return a match result.

??? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? abcABC0
XXXXX X X X X X X X X X X X
X X X X X X X X X X X X X X X X

Biterider


jj2007

Well, you have a point there :thumbsup:

It's not so relevant for MasmBasic, because strings and buffers are all HeapAlloc'ed with a little reserve of 24 bytes that helps to avoid this scenario.

See Peter Cordes' very detailed description of pcmpistri & pcmpestri performance at SOF

I have a version that checks the bounds, and it's only a tick slower than the fast version, but I really don't think it's worth the effort. Real life strings and buffers should never end at no man's land.

Btw this logic should be applied to all code. Attached an example that shows the behaviour of the Masm32 SDK len() macro. You might be surprised :cool: