Compare commits

...
Author SHA1 Message Date
t3hn3rd f53afc1d2d feature: Tracer O(1) ring buffer refactor
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
- Replaced O(n) shift loop + StringCopy/kalloc/kfree with O(1) ring
  buffer storing PChar pointers directly (zero allocation).
- Eliminated mod operator (causes int64 promotion + broken RTL helpers
  on i386 bare-metal); uses pure uint32 branch arithmetic.
- Removed dead code: PTracerEntry/TTracerEntry linked list types,
  head/tail PTracerEntry vars, c_lock boolean
- Dropped lmemorymanager and serial from uses clause
- pop_trace remains as no-op stub for ABI compat
- get_trace_N uses underflow-safe index: if head >= idx then
  head - idx else MAX_TRACE - (idx - head)
- Added print_traces debug helper
2026-03-01 21:26:35 +00:00
admin afdc83eaf6 Merge pull request 'Merge feature/hardening into develop' (#11) from feature/hardening into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #11
2026-03-01 02:57:23 +00:00
t3hn3rd 2239d9c848 Rebase: Fixed console -> syslog interface
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-01 02:46:13 +00:00
t3hn3rd beb4b253ab fix: guard against uint32 underflow in memset/memcpy and strings unit
When size=0 was passed to memset() or memcpy(), the loop bound
`0 to size-1` underflowed to $FFFFFFFF, iterating ~4 billion times
and causing an immediate page fault.

Added `if size = 0 then exit` guards to both memset() and memcpy()
in util.pas.

Also guarded all `for i:=0 to X-1` loops in strings.pas where X
could be 0 on empty string inputs:
- stringToUpper: wrap loop in `if stringSize > 0`
- stringToLower: wrap loop in `if stringSize > 0`
- stringEquals: early exit when both sizes are 0
- stringToInt: early exit when string is empty

Additionally fixed all previously identified bugs in strings.pas:
- hexStringToInt: guard against empty string underflow
- stringConcat: cache stringSize calls to avoid redundant O(n) scans
- stringTrim: clamp length to source string size
- stringSub: bounds check start/size against source length
- stringReplace: complete rewrite - was using stringEquals() for
  substring matching (only matched at string end), dropped prefix
  chars, had dangling assignment overwriting valid result with
  uninitialized pointer, and had unused variable
- stringIndexOf: rewritten to use new stringMatchAt() helper for
  correct substring matching
- stringContains: simplified to delegate to fixed stringIndexOf(),
  also fixing uint32 underflow when sub was empty
- stringToInt: removed always-true `v >= 0` check on uint32
- intToString: implemented (was a stub returning ' ')
- Added stringMatchAt() helper for prefix comparison
- Added comprehensive UnitTest procedure with 77 assertions
  including adversarial empty/nil/boundary inputs
2026-03-01 02:33:28 +00:00
admin 084130da80 Merge pull request 'feat: VESA rendering implementation & LVGL for graphics drawing' (#10) from feature/lvgl into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #10
2026-03-01 02:25:47 +00:00
admin 924305a1ab Merge pull request 'Migration from FPC 2.6.4 to FPC 3.2.2' (#9) from feature/fpc-3.2.2 into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #9
2026-02-26 12:51:09 +00:00
4 changed files with 453 additions and 139 deletions
+397 -106
View File
File diff suppressed because it is too large Load Diff
+11 -2
View File
@@ -414,6 +414,7 @@ var
begin
//push_trace('util.memset');
if size = 0 then exit;
for i:=0 to size-1 do begin
loc:= puint8(location + i);
loc^:= value;
@@ -428,6 +429,7 @@ var
begin
//push_trace('util.memcpy');
if size = 0 then exit;
for i:=0 to size-1 do begin
src:= puint8(source + i);
dst:= puint8(dest + i);
@@ -579,12 +581,13 @@ begin
syslog.writestring(' EIP: '); syslog.writehex(IntSpec^.EIP); syslog.writestring(' CS: '); syslog.writehex(IntSpec^.CS); syslog.writestring(' EFLAGS: '); syslog.writehexln(IntSpec^.EFLAGS);
syslog.writestringln(' ');
end;
syslog.writestring('Call Stack: ');
tracer.freeze;
syslog.writestring('Call Stack: ');
trace:= tracer.get_last_trace;
if trace <> nil then begin
syslog.writestring('[-0] ');
syslog.writestringln(trace);
for i:=1 to tracer.get_trace_count-7 do begin
for i:=1 to tracer.get_trace_count-1 do begin
trace:= tracer.get_trace_N(i);
if trace <> nil then begin
syslog.writestring(' [');
@@ -592,6 +595,12 @@ begin
syslog.writeint(i);
syslog.writestring('] ');
syslog.writestringln(trace);
end else begin
syslog.writestring(' [');
syslog.writestring('-');
syslog.writeint(i);
syslog.writestring('] ');
syslog.writestringln('?????????');
end;
end;
end else begin
+3
View File
@@ -251,6 +251,9 @@ begin
{ Initialize visual terminal (registers with desktop search) }
vterminal.init;
{ Run unit tests }
strings.UnitTest;
{ Main render loop }
syslog.logln('KERNEL', 'Entering main render loop.');
tracer.push_trace('kmain.MAINLOOP');
+42 -31
View File
@@ -13,8 +13,12 @@
// limitations under the License.
{
Tracer - Trace stack for debugging method calls.
Tracer - Ring buffer trace log for debugging method calls.
IMPORTANT: push_trace MUST only be called with pointers to
static/persistent data (e.g. string literals). The pointer is
stored directly - no copy is made.
@author(Kieron Morris <[email protected]>)
}
unit tracer;
@@ -28,19 +32,12 @@ function get_last_trace : pchar;
procedure freeze;
function get_trace_count : uint32;
function get_trace_N(idx : uint32) : pchar;
procedure print_traces;
implementation
uses
lmemorymanager, util, strings, serial, stdio;
type
PTracerEntry = ^TTracerEntry;
TTracerEntry = record
Next : PTracerEntry;
Data : pchar;
Previous : PTracerEntry;
end;
util, strings, stdio, syslog;
const
MAX_TRACE = 40;
@@ -48,16 +45,12 @@ const
var
t_ready : Boolean;
Locked : Boolean;
head : uint32;
Traces : Array[0..MAX_TRACE-1] of PChar;
c_lock : Boolean = false;
var
head : PTracerEntry;
tail : PTracerEntry;
procedure terminal_command_tracer(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
var
p1, p2 : PChar;
p1 : PChar;
count : uint32;
i : uint32;
t : PChar;
@@ -113,22 +106,15 @@ begin
end;
procedure push_trace(t_name : pchar);
var
i : uint32;
begin
if TRACER_ENABLE then begin
if t_ready then begin
if not Locked then begin
if not c_lock then begin
Locked:= true;
if Traces[MAX_TRACE-1] <> nil then kfree(void(Traces[MAX_TRACE-1]));
for i:=MAX_TRACE-1 downto 1 do begin
Traces[i]:= Traces[i-1];
end;
Traces[0]:= StringCopy(t_name);
Locked:= false;
end;
Locked:= true;
head:= head + 1;
if head >= MAX_TRACE then head:= 0;
Traces[head]:= t_name;
Locked:= false;
end;
end;
end;
@@ -141,7 +127,7 @@ end;
function get_last_trace : pchar;
begin
get_last_trace:= Traces[0];
get_last_trace:= Traces[head];
end;
procedure init;
@@ -151,8 +137,10 @@ var
begin
if TRACER_ENABLE then begin
for i:=0 to MAX_TRACE-1 do begin
traces[i]:= nil;
Traces[i]:= nil;
end;
Locked:= false;
head:= MAX_TRACE - 1;
t_ready:= true;
push_trace('kmain');
end;
@@ -166,11 +154,34 @@ begin
end;
end;
procedure print_traces;
var
i : uint32;
begin
for i:=0 to MAX_TRACE-1 do begin
syslog.log('TRACER', '[');
syslog.writeint(i);
syslog.writestring('] ');
if Traces[i] <> nil then begin
syslog.writestringln(Traces[i]);
end else begin
syslog.writestringln('?????????');
end;
end;
end;
function get_trace_N(idx : uint32) : pchar;
var
slot : uint32;
begin
if idx > MAX_TRACE-1 then exit;
if TRACER_ENABLE then begin
get_trace_N:= traces[idx];
if head >= idx then
slot:= head - idx
else
slot:= MAX_TRACE - (idx - head);
get_trace_N:= Traces[slot];
end;
end;