SAFE mode for FPC lazarus / 64-FPC development ---------------------------------------------------------------------- serbod · 2017-01-13 08:27 Do FPC have possibility to enable "SAFE" mode, where all runtime checks enabled and any potentially risky syntax and features is disabled (produce error instead of warning)? So, compiled code will be not most efficient, but most failproof. For example, disabled and forbidden: - unsafe typecasting - untyped variables, parameters, pointers and pointer arithmetics - low-level memory manipulation routines - unwrapped shared library functions calls - uninitialized variables - undefined function result - calling constructor from variables (obj := obj.Create) - usage of some classes in library initialization/finalization sections (TThread, TCriticalSection, ..) - write to inherited properties in constructor - write to global variables in class methods Also, some features is forced: - range, I/O, stack overflow, memory checking - variables initialization to default - smart pointers (with refcounting) - unspecified modifier (const/var/val) warning for string, array, record parameters ---------------------------------------------------------------------- marcov · 2017-01-13 09:22 ppcjvm ? :-) ---------------------------------------------------------------------- serbod · 2017-01-13 10:59 Quote from: marcov on January 13, 2017, 10:22:00 amppcjvm ? :-) yes, something like that, but for native compilation ---------------------------------------------------------------------- marcov · 2017-01-13 13:11 No there is no such thing. For starters, the native compilation is not a safe language to begin with. Your list is also a mix of runtime and compiletime checks. For compiletimechecks, there is a setting to halt on any warning. One could argue though if FPC's warning/hint algorithms are foolproof enough for that. For runtime checks, you can enable several parts of those (unsafe typecasting of classes, seeding uninitialized variables with random data etc) I think things like  usage of some classes in library initialization/finalization sections (TThread, TCriticalSection, ..) are more something for static code inspectors, not for the compiler. There are several products and services for Delphi, maybe check that out. ---------------------------------------------------------------------- serbod · 2017-01-13 14:59 It useful not only for starters, but for anyone, who need extra reliability and don't want to shoot in the foot occasionaly. I think, it can be done with preprocessor directives, like that: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$IF MODE SAFE}  {$RANGECHECKS ON}  {$OBJECTCHECKS ON}  {$IOCHECKS ON}  {$CHECKPOINTER ON}  {$GOTO OFF}  ....{$ENDIF} and mark some exported routines as @unsafe ---------------------------------------------------------------------- skalogryz · 2017-01-13 15:55 Quote from: serbod on January 13, 2017, 03:59:19 pmIt useful not only for starters, but for anyone, who need extra reliability and don't want to shoot in the foot occasionaly. FPC RTL shoot my foot with {$rangechecks on} Here's the story: On fpc 2.6.4 socket function htonl is declared (/rtl/inc/socketsh.inc) like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function htonl( host : longint):longint; inline; On fpc 3.0.0 socket function htonl is declared (packages/rtl-extra/src/inc/socketsh.inc) like that: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function htonl( host : cardinal):cardinal; inline; (the later use of unsigned integer makes more sense, if you ask me). However, compiling the project with {$rangechecks on} caused me a range check error on 2.6.4 I'm storing address as unsigned 32 integer. I saw the type declaration of "longint" and added the type casting to longint. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   htonl ( longint(myaddr));After that i compiled the same code on 3.0.0. and it started throwing range checks at me. The worse thing, is that not every ip address would cause the range check error. Eventually I ended up adding Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$rangechecks off}at the begging of the unit. Yeah, I could probably write my own htonl() wrapper, that would do a proper casting, depending on compiler (RTL) version... but... this is my target practice experience ---------------------------------------------------------------------- Thaddy · 2017-01-13 16:03 Seems rather SAFE to me,when a compiler finds an obvious error..... ---------------------------------------------------------------------- serbod · 2017-01-16 07:13 Quote from: Thaddy on January 13, 2017, 05:03:20 pmSeems rather SAFE to me,when a compiler finds an obvious error..... Some errors can't be autodetected from sources - array bounds, invalid pointers, access to destroyed objects, wrong typecast, wrong record alignment.. It's shame, that for 15-20 years of language developmant and usage, it still don't have any protection from routines, that can cause random critical runtime errors. Smart pointers for objects by default can solve most casual troubles. In 90'th with limited computing resources, extra runtime checks was burdening, but now it's not a problem even for pocket devices. Difference in performance between debug and release builds is unnoticable. ---------------------------------------------------------------------- Thaddy · 2017-01-16 07:35 That's apples and pears and looks like you spend too much comparing with Java (definitely not with C++, that's worse). BTW one really SAFE option that I do not see here yet, is compiling with -Sew . Treat warnings as errors. Or even -Sewhn and solve everything. ---------------------------------------------------------------------- serbod · 2017-01-16 08:21 Quote from: Thaddy on January 16, 2017, 08:35:38 amThat's apples and pears and looks like you spend too much comparing with Java I don't like Java and don't use it. I don't care, if C++ still shoot in legs and loving it. I just tired to alweys keep in mind, that some casual things in Pascal is surprisingly dangerous, and better not use them or use with extra cautions. ---------------------------------------------------------------------- marcov · 2017-01-16 08:39 Sounds like you simply want a preconfigured build mode in Lazarus. There is no need to do this in compiler, making managing large sets of settings and switching easily between them is a job for either the IDE, or requires the ability to write cmdline scripts yourself. But as said, the main problems is that you heap too many different (runtime and compiletime) things together, moreover some of the compiletime checks (like variable not initialized etc) must be magnitudes more reliable to make it practical. ---------------------------------------------------------------------- serbod · 2017-01-16 09:13 Quote from: marcov on January 16, 2017, 09:39:51 amSounds like you simply want a preconfigured build mode in Lazarus. Yes, something obviously simple, like predefined DEBUG mode. But it also need some support from compiler and standard library. ---------------------------------------------------------------------- Handoko · 2017-01-16 09:16 Hello serbod, I don't mean to discourage you. Actually I like the idea of safe mode. But some may not agree with the things listed in your example. untyped variables Did you also mean untyped parameters? It can be useful sometimes. For example, I write module to write and load block data without fixed size from/to files and TMemoryStream. Using untyped parameters seems good and easier for me as long as I understand how to safely use untyped parameters. uninitialized variables I know uninitialized variables can be dangerous. But if we initialized all variables it will be decrease the performance, I know nowadays computers are fast. But I follow my style: initialized the variables only when it is going to be used. range check I always disable range check, I enable it only when for testing certain things. The last time I remember, enabling range check will slow the performance significantly. I don't say my codes are free from range check errors, but I always choose the data type properly before I use it and I always manually make sure the variable size is large enough to store the calculation values. io check Now I never enable it, the last time I use it was learning programming many years ago. I think it will be good if the error is caught by programmer rather than the software/compiler/computer? I mean will it better if the programmer write better code by using ioresult, isn't it? stack overflow check Do we still need it? Maybe. But I remember I used it when programming on 8-bit machine for DOS using Turbo Pascal 5.5. Now we're using 32 even 64 bit, do we now still have stack overflow issue? I believe we usually learn a lot from errors. If we are overprotected, not much we will learn. By making the compiler do a lot of things to protect and to limit programmer to do certain things, it won't be good. I don't mean to against your idea, but from experienced programmers' view point, it doesn't sound too good. It maybe good for novice programmers but I doubt it, because overprotected will make them learn less, in the future they won't know how to manipulate low-level memory, they can't prevent io and range problem manually. Last words, safe mode is a nice feature to put on FPC (or Lazarus). But the problems are what items should put into the list and who will write this feature. It's only my 2 cents, some may agree or not with me. ---------------------------------------------------------------------- serbod · 2017-01-16 10:02 Quote from: Handoko on January 16, 2017, 10:16:00 amHello serbod, I don't mean to discourage you. Actually I like the idea of safe mode. But some may not agree with the things listed in your example. I agree with all that arguments. But if you notice, I don't propose disable inline assembler in safe mode. I just forgot, when I uses it, and doubt, that will sometime use again. =) Same i can say for untyped variables and parameters. They can be useful for deep optimizations, but not needed in casual work. Stack/range/io checks is unnoticable for GUI and database application, where most runtime code is optimized pre-built libraries. But runtime crash errors is very noticable and very hard to find in sources. ---------------------------------------------------------------------- Thaddy · 2017-01-16 10:12 Quote from: Handoko on January 16, 2017, 10:16:00 amHello serbod, I don't mean to discourage you. Actually I like the idea of safe mode. But some may not agree with the things listed in your example. untyped variables Did you also mean untyped parameters? It can be useful sometimes. For example, I write module to write and load block data without fixed size from/to files and TMemoryStream. Using untyped parameters seems good and easier for me as long as I understand how to safely use untyped parameters. Yes, pointer casts, variants and array of consts are very useful when you know what you are doing.... Quoteuninitialized variables I know uninitialized variables can be dangerous. But if we initialized all variables it will be decrease the performance, I know nowadays computers are fast. But I follow my style: initialized the variables only when it is going to be used. initializing a variable does not cost too much performance. Note global variables are ALWAYS initialized. Just stack based variables need initialization. There's the Default() intrinsic for that, nowadays. Quoterange check I always disable range check, I enable it only when for testing certain things. The last time I remember, enabling range check will slow the performance significantly. I don't say my codes are free from range check errors, but I always choose the data type properly before I use it and I always manually make sure the variable size is large enough to store the calculation values. I ALWAYS have rangechecks on during debugging. I ALWAYS resolve all related warnings and hints. It is of off in release mode Quoteio check Now I never enable it, the last time I use it was learning programming many years ago. I think it will be good if the error is caught by programmer rather than the software/compiler/computer? I mean will it better if the programmer write better code by using ioresult, isn't it? I personally use  {$I-} a lot and process the IOResult error codes. Especially if I can avoid pulling in exception handling. Much faster and just as safe. Quotestack overflow check Do we still need it? Maybe. But I remember I used it when programming on 8-bit machine for DOS using Turbo Pascal 5.5. Now we're using 32 even 64 bit, do we now still have stack overflow issue? Yes, we still need it, because cocky programmers like recursion And multi-threading QuoteI believe we usually learn a lot from errors. If we are overprotected, not much we will learn. By making the compiler do a lot of things to protect and to limit programmer to do certain things, it won't be good. I don't mean to against your idea, but from experienced programmers' view point, it doesn't sound too good. It maybe good for novice programmers but I doubt it, because overprotected will make them learn less, in the future they won't know how to manipulate low-level memory, they can't prevent io and range problem manually. Last words, safe mode is a nice feature to put on FPC (or Lazarus). But the problems are what items should put into the list and who will write this feature. It's only my 2 cents, some may agree or not with me. I more or less agree. What Marco wrote makes sense. Personally I like a very strict debug mode for very sensitive code. And it is definitely possible to create such a debug mode already. If programmers, especially beginners, would solve all hints and warnings their code would be 90% better. There's a reason that the compiler itself is compiled with -Sew ---------------------------------------------------------------------- Handoko · 2017-01-16 11:21 Quoteinitializing a variable does not cost too much performance. Yes, I know. I don't against it, but in this code below (which I wrote many years ago) all the variables even the "Result" aren't initialized at the beginning. They will be assigned with proper values when they're going to be used. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetATmpFileName(const Name: string): string;var  FileNameOnly: string;  FileExt: string;  S: string;  i: SmallInt;begin   // Using name's path  if FileExists(Name) then begin    S := ChangeFileExt(Name, '.bak');    if not(FileExists(S)) then begin      Result := S;      Exit;      end;    S := ChangeFileExt(Name, '.tmp');    if not(FileExists(S)) then begin      Result := S;      Exit;      end;    FileExt := ExtractFileExt(Name);    FileNameOnly := StrRemoveRight(Name, Length(FileExt));    for i := 1 to 999 do begin    S := StrWithNumber(FileNameOnly, i, 3) + FileExt;      if not(FileExists(S)) then begin        Result := S;        Exit;        end;      end;    end;   // Using system's temporary path  S := ExtractFileNameOnly(Name);  Result := SysUtils.GetTempFileName('', ExtractFileNameOnly(S)); end; QuoteI ALWAYS have rangechecks on during debugging. I ALWAYS resolve all related warnings and hints. Yes, it is a good practice, although I often skip the range check. I fell shame  But it's okay, I know what I'm doing. QuoteQuotestack overflow check Do we still need it? Maybe. But I remember I used it when programming on 8-bit machine for DOS using Turbo Pascal 5.5. Now we're using 32 even 64 bit, do we now still have stack overflow issue? Yes, we still need it, because cocky programmers like recursion And multi-threading Oh yes, I almost forget recursion. Thanks for reminding me. If I need recursion I will find the different way to write the code. I simply don't like recursion. serbod, can you (or other) please make this thread a survey so we can vote for "Do you want safe (or a better debug) mode?" I see this topic is interesting. I believe a good safe or better debug mode can be a very useful feature. But of course we have to think properly what things needed to put in the list. ---------------------------------------------------------------------- Thaddy · 2017-01-16 11:24 Quote from: serbod on January 16, 2017, 08:13:06 amSome errors can't be autodetected from sources - array bounds, invalid pointers, access to destroyed objects, wrong typecast, wrong record alignment.. It's shame, that for 15-20 years of language developmant and usage, it still don't have any protection from routines, that can cause random critical runtime errors. Smart pointers for objects by default can solve most casual troubles. In 90'th with limited computing resources, extra runtime checks was burdening, but now it's not a problem even for pocket devices. Difference in performance between debug and release builds is unnoticable. Well, how about: - Using Low() and High() and Length() for arrays. If you don't, you are the cause of your problems - Testing Assigned(), Assert() and nil for pointers will help - Hard - wrong - type casts can never be made safe. That is a programmer instruction by definition. - Smart pointers should not be on by default, they are possible though, in trunk. - Record alignment is a programmers task. If writing to/from a storage medium is required a record should be packed and the programmer should take care of the optimum layout, otherwise it should be CPU/FPU/OS  alignment dependent. Simple. If you have indeed 15-20 years of experience.... well, use the language features that are already there.. Some runtime checks are possible, but for e.g. a hard cast that is not possible. ---------------------------------------------------------------------- Handoko · 2017-01-16 11:30 +1 Thaddy Good suggestions. ---------------------------------------------------------------------- serbod · 2017-01-16 12:49 Quote from: Thaddy on January 16, 2017, 12:24:10 pmWell, how about: - Using Low() and High() and Length() for arrays. If you don't, you are the cause of your problems - Testing Assigned(), Assert() and nil for pointers will help - Hard - wrong - type casts can never be made safe. That is a programmer instruction by definition. - Smart pointers should not be on by default, they are possible though, in trunk. - Record alignment is a programmers task. If writing to/from a storage medium is required a record should be packed and the programmer It's very bad practice, put all troubles on programmer's shoulders, when it's not necessary. For example, strings (LongString, AnsiString) have runtime size/position checking, refcounting, type conversion, and some other features out-of-box, and it make Pascal outstanding over many other languages, without performance penalties. Who now use PChar as string in Pascal? Standad library have many functions for PChar, almost all shared libraries and API's use PChar for strings. Why not make PChar as default string type? =) Smart pointers and refcounting is already implemented for Interface, but not implemented for Object. I don't uderstand, why. Every TObject have refcounted strings and iterfaces table, but can't have refcounting itself. So, Assigned() is just comparsion with nil, not checking, that object was destroyed. FreeAndNil() also can't help, if there another pointers to object.