Recent

Author Topic: AV during runtime, because Compiler does not check the String-Format by "Format"  (Read 5223 times)

Eugene Loza

  • Hero Member
  • *****
  • Posts: 729
    • My games in Pascal
Quote
Of course, there is always the temptation to code directly
First, that still won't fix the problem if parameters of `ShowError` mismatch the parameters of the Format:

Code: Pascal  [Select][+][-]
  1. procedure ShowError(InClassName: String; InToX, InToY: Single; InSizeX, InSizeY : LongInt);
  2. begin
  3. ShowError('%s is trying to teleport to broken coordinates (%d, %d) on map %dx%d. Teleporting to random point instead.', [InClassName, InToX, ToY, InSizeX, InSizeY]);
  4. end;

Will still crash with exactly the same symptoms at exactly the same conditions. Format parameters are not validated compile-time. Wrapping it inside of a procedure with typed parameters doesn't fix this. Hypothetically it only makes a tiny bit less likely to make a typo at expense of several additional lines of code that reduce the code readability and maintainability.

Second, ShowError is a variant of ShowLog (with simply color of the label being red, and apparently is a wrapper around Format) which are called on multiple different occasions from 40k+ lines of code project scattered over 230+ units... If I'll be writing a specific ShowError procedure for each and every case it's called... And make sure to adequately update it every time I decide to update one of the hundreds of lines of text that are displayed to the Player on different occasions... that would certainly be an unnecessary overcomplication.
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12853
  • FPC developer.
Second, ShowError is a variant of ShowLog (with simply color of the label being red, and apparently is a wrapper around Format) which are called on multiple different occasions from 40k+ lines of code project scattered over 230+ units... If I'll be writing a specific ShowError procedure for each and every case it's called... And make sure to adequately update it every time I decide to update one of the hundreds of lines of text that are displayed to the Player on different occasions... that would certainly be an unnecessary overcomplication.

You don't do that, you simply wrap format  (s:string;x:array of const), parse s and see if the type of x matches the type in the string. If it doesn't match, you do your own errorhandling since you don't like exceptions (here).

Maybe you can even do inline vars with trunks extended RTTI.
« Last Edit: April 08, 2024, 09:41:55 am by marcov »

Eugene Loza

  • Hero Member
  • *****
  • Posts: 729
    • My games in Pascal
Quote
parse s and see if x matches
Indeed, that's exactly what I plan to do :) But as a part of a bigger subsystem (that would allow more flexible "context", rather like a minimalistic scripting language), which I didn't get to implement yet...
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
@440bx:
Code: [Select]
I don't know how they chose to do it but, I think the scanner and parser do a little bit of backtracking to process the pairs of strings with format specs followed by parameter list.  Most likely the scanner has the heaviest burden. A little printf format spec scanner "on the side" talking to the C++ parser.
not directly backtraced, but I think, they could use a string table for all const Strings, or dynamic Strings with data of %d, or %s.
I thinking of, that can be done with regex Libraries.

Then, the compiler check in a pass all Strings, and if you have debug switch on, the second deeper search of the Strings can be parsed with a index. So you have a TStringList only items that contain only of %-marked Texts.

On my conclusion, this is the fastest way that I would implement, when I have stronger compiler skills.
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Thaddy

  • Hero Member
  • *****
  • Posts: 19158
  • Glad to be alive.
Quote
parse s and see if x matches
Indeed, that's exactly what I plan to do :) But as a part of a bigger subsystem (that would allow more flexible "context", rather like a minimalistic scripting language), which I didn't get to implement yet...
In fact, Format and family are strictly speaking embedded schripting languages. Marcov already explained that. They have their own syntax,parser and lexer and are evaluated at runtime.

I think the C# confusion comes from "reflection", like in Java too (or for that matter FPC's RTTI)
But all of that is runtime oriented, not compile time.

This is a good excercise for Lex and Yacc:
1) let Lex tokenize the input from Format syntax()
2) Let Yacc interpret the tokenized stuff and add code templates on how it should be interpreted.
3) Generate code to implement format() from the Yacc output.

Any compiler generator can do that btw, but this is an example that is - probably?, likely? for such sub-questions - also used in FreePascal's format(). And it is a - relatively - simple one since the syntax is strictly linear.
(I prefer GOLD nowadays, but the difference is small)
« Last Edit: April 08, 2024, 09:19:06 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12853
  • FPC developer.
I think the C# confusion comes from "reflection", like in Java too (or for that matter FPC's RTTI)
But all of that is runtime oriented, not compile time.
As those languages are just in time, the source (or a direct representation) is available, so also the identifier names. (which among others makes those languages easy(ier) to reverse engineer).

In compiled languages, normally identifiers are no longer available past compilation. Extended RTTI circumvents that for specific cases, but I would think hard and long before I would use it when not necessary.

It is bulky, and all forms of RTTI relatively slow.

Format line checking can be done, but in C, where interpretive I/O is the norm, this is more common than in FPC/Delphi where it is more a peripheral (library) functionality.  Moreover, in C it yields access violations, while in FPC a mild, recoverable exception

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Might be a valuable extension, though kinda clutter the compiler (scanner I believe) and slow it down. Even in C and C++ compilers it is their own innovation, not part of the standard, as this error is very common in their basic I/O (printf/scanf) and could be quite annoying for starters (and can even still happen to the experienced). WriteStr should be promoted more than Format, it's more inline with the safety of Write(Ln).

 

TinyPortal © 2005-2018