Memory leak when using constants initialized with translated resource strings
## Summary Programs that use internationalized resource strings in typed constants leak memory due to improper reference counting when translated at runtime. More specifically, `UpdateResourceStringRefs` calls `fpc_ansistr_assign` **on the result of a cast** to `AnsiString` on `TResStrInitEntry.Addr`, which is declared as `PPointer`. Since there is no corresponding `FinalizeResourceStringRefs` procedure (to be invoked during finalization) and the global table entries holding the references aren't declared as `AnsiString` themselves (only transiently cast from `Pointer`), this results in the string's reference count staying permanently inflated, thus preventing deallocation. ## System Information Found on `3.2.2 - i386-win32`, but should be present on all platforms whose RTL defines `FPC_HAS_RESSTRINITS`. ## Steps to reproduce Compile & run the following example program with `-gh` to show the leak: ## Example Project ```pascal program RS_Leak; {$mode objfpc}{$H+} resourcestring S_FOO = 'BAR'; procedure Print_RC(const S: String); begin WriteLn(PSizeInt(Pointer(S))[-2]); end; function UpdateFoo(Name, Value: String; Hash: Integer; Data: Pointer): String; begin Result := Value + Value; end; procedure Test(); const FOO_X1: String = S_FOO; // This alone is enough to cause a leak var FOO_X5: array[0..4] of String = (S_FOO, S_FOO, S_FOO, S_FOO, S_FOO); begin Print_RC(FOO_X5[0]); // Prints 12 (5 additional local references in FOO_X5) Print_RC(FOO_X1); end; begin Print_RC(S_FOO); // Prints -1 (referring to constant "BAR") SetUnitResourceStrings('RS_Leak', @UpdateFoo, Nil); Print_RC(S_FOO); // Prints 7 (referring to non-constant "BARBAR") Test(); Print_RC(S_FOO); // Prints 7 end. ``` ## What is the current bug behavior? Translated resource strings used to initialize constants are not freed during unit finalization, leading to memory leaks (visible in `heaptrc` output). ## What is the expected (correct) behavior? All strings should be properly freed. ## Relevant logs and/or screenshots ``` -1 7 12 12 7 Heap dump by heaptrc unit of "<redacted>\rsleak.exe" 2 memory blocks allocated : 39/48 1 memory blocks freed : 20/24 1 unfreed memory blocks : 19 True heap size : 163840 (208 used in System startup) True free heap : 163504 Should be : 163512 Call trace for block $01620288 size 19 $00401662 UPDATEFOO, line 15 of RS_Leak.pas $00410962 SETUNITRESOURCESTRINGS, line 457 of ../objpas/objpas.pp $00401733 main, line 31 of RS_Leak.pas ``` ## Possible fixes Because of the fragmentation of table data across units (and the multiple levels of indirection à "pointer to table" thus required), I think the best solution would be to add a `FinalizeResourceStringRefs` procedure that is called during finalization of the `objpas` unit, much like `FinalizeResourceTables`. ```pascal { Following UpdateResourceStringRefs near objpas.pp:404 } procedure FinalizeResourceStringRefs; var i: integer; ptable: PResStrInitEntry; begin for i:=1 to ResStrInitTable^.Count do begin ptable:=ResStrInitTable^.Tables[i]; while Assigned(ptable^.Addr) do begin AnsiString(ptable^.Addr^):=''; Inc(ptable); end; end; end; ``` ```pascal { Preceding FinalizeResourceTables in the finalization section near objpas.pp:527 } {$ifdef FPC_HAS_RESSTRINITS} FinalizeResourceStringRefs; {$endif FPC_HAS_RESSTRINITS} ```
issue