Skip to content

Commit d517b7d

Browse files
committed
Fixed crash when trying to call FreeObjectsIfOwned in situations where the buffer filled completely.
1 parent 098247d commit d517b7d

File tree

6 files changed

+86
-79
lines changed

6 files changed

+86
-79
lines changed

Demo/RingbufferDemo.dproj

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
22
<PropertyGroup>
33
<ProjectGuid>{F29D623B-46EB-4798-84C7-04107FF2F72B}</ProjectGuid>
4-
<ProjectVersion>19.3</ProjectVersion>
4+
<ProjectVersion>19.4</ProjectVersion>
55
<FrameworkType>None</FrameworkType>
66
<Base>True</Base>
77
<Config Condition="'$(Config)'==''">Debug</Config>
@@ -168,9 +168,8 @@
168168
</Excluded_Packages>
169169
</Delphi.Personality>
170170
<Deployment Version="3">
171-
<DeployFile LocalName="Win32\Debug\RingbufferDemo.exe" Configuration="Debug" Class="ProjectOutput">
172-
<Platform Name="Win32">
173-
<RemoteName>RingbufferDemo.exe</RemoteName>
171+
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
172+
<Platform Name="iOSSimulator">
174173
<Overwrite>true</Overwrite>
175174
</Platform>
176175
</DeployFile>
@@ -184,8 +183,9 @@
184183
<Overwrite>true</Overwrite>
185184
</Platform>
186185
</DeployFile>
187-
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
188-
<Platform Name="iOSSimulator">
186+
<DeployFile LocalName="Win32\Debug\RingbufferDemo.exe" Configuration="Debug" Class="ProjectOutput">
187+
<Platform Name="Win32">
188+
<RemoteName>RingbufferDemo.exe</RemoteName>
189189
<Overwrite>true</Overwrite>
190190
</Platform>
191191
</DeployFile>
@@ -988,17 +988,17 @@
988988
<Operation>1</Operation>
989989
</Platform>
990990
</DeployClass>
991-
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
992-
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
993-
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
994-
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
995-
<ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/>
996991
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
997-
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
998-
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
992+
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
999993
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
1000994
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
1001995
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
996+
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
997+
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
998+
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
999+
<ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/>
1000+
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
1001+
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
10021002
</Deployment>
10031003
<Platforms>
10041004
<Platform value="Android">False</Platform>

Docs/CircularBuffer.pdf

1.37 KB
Binary file not shown.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Generic circular buffer/ring buffer implementation
55
Most likely at least from XE7 onwards, but most likely earlier versions
66
supporting generics as well. Earlier versions will not work due
77
to the use of some intrinsics added in XE7. Last changes were made
8-
with 11.0 Alexandria.
8+
with 11.1 Alexandria.
99

1010
# Contents
1111
The project contains one unit implementing a generic circular buffer class

Ringpuffer.dproj

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
22
<PropertyGroup>
33
<ProjectGuid>{4E53EA93-9364-43EC-8810-69F9D5996DBC}</ProjectGuid>
4-
<ProjectVersion>19.3</ProjectVersion>
4+
<ProjectVersion>19.4</ProjectVersion>
55
<FrameworkType>None</FrameworkType>
66
<MainSource>Ringpuffer.dpr</MainSource>
77
<Base>True</Base>
@@ -155,29 +155,29 @@
155155
</Source>
156156
</Delphi.Personality>
157157
<Deployment Version="3">
158+
<DeployFile LocalName="$(BDS)\Redist\iossim32\libcgunwind.1.0.dylib" Class="DependencyModule"/>
158159
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
159160
<Platform Name="iOSSimulator">
160161
<Overwrite>true</Overwrite>
161162
</Platform>
162163
</DeployFile>
163-
<DeployFile LocalName="Win32\Debug\Ringpuffer.exe" Configuration="Debug" Class="ProjectOutput"/>
164164
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
165165
<Platform Name="iOSSimulator">
166166
<Overwrite>true</Overwrite>
167167
</Platform>
168168
</DeployFile>
169-
<DeployFile LocalName="Win32\Debug\Ringpuffer.exe" Configuration="Debug" Class="ProjectOutput">
170-
<Platform Name="Win32">
171-
<RemoteName>Ringpuffer.exe</RemoteName>
169+
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
170+
<Platform Name="OSX32">
172171
<Overwrite>true</Overwrite>
173172
</Platform>
174173
</DeployFile>
175-
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
176-
<Platform Name="OSX32">
174+
<DeployFile LocalName="Win32\Debug\Ringpuffer.exe" Configuration="Debug" Class="ProjectOutput"/>
175+
<DeployFile LocalName="Win32\Debug\Ringpuffer.exe" Configuration="Debug" Class="ProjectOutput">
176+
<Platform Name="Win32">
177+
<RemoteName>Ringpuffer.exe</RemoteName>
177178
<Overwrite>true</Overwrite>
178179
</Platform>
179180
</DeployFile>
180-
<DeployFile LocalName="$(BDS)\Redist\iossim32\libcgunwind.1.0.dylib" Class="DependencyModule"/>
181181
<DeployClass Name="AdditionalDebugSymbols">
182182
<Platform Name="iOSSimulator">
183183
<Operation>1</Operation>
@@ -987,17 +987,17 @@
987987
<Operation>1</Operation>
988988
</Platform>
989989
</DeployClass>
990-
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
991-
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
992-
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
993-
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
994990
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
995-
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
996-
<ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/>
991+
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
997992
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
998993
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
999-
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
1000994
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
995+
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
996+
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
997+
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
998+
<ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/>
999+
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
1000+
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
10011001
</Deployment>
10021002
<Platforms>
10031003
<Platform value="Android">False</Platform>

Source/Ringbuffer.pas

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{*****************************************************************************
1+
{*****************************************************************************
22
The CircularBuffer team (see file NOTICE.txt) licenses this file
33
to you under the Apache License, Version 2.0 (the
44
"License"); you may not use this file except in compliance
@@ -198,7 +198,7 @@ TRingbuffer<T> = class(TObject)
198198
/// Appends the given item to the ring buffer
199199
/// </summary>
200200
/// <param name="Item">
201-
/// Anzuhängendes Element
201+
/// Anzuhängendes Element
202202
/// </param>
203203
/// <exception cref="EBufferFullException">
204204
/// not enough capacity
@@ -242,7 +242,7 @@ TRingbuffer<T> = class(TObject)
242242
/// Number of elements to retrieve
243243
/// </param>
244244
/// <returns>
245-
/// Array mit einer maximalen Länge von Count
245+
/// Array mit einer maximalen Länge von Count
246246
/// </returns>
247247
/// <exception cref="EBufferEmptyException">
248248
/// buffer is empty
@@ -378,7 +378,7 @@ implementation
378378

379379
procedure TRingbuffer<T>.Add(Item: T);
380380
begin
381-
// nur hinzufügen wenn entweder noch Platz im Puffer oder wenn Puffer ganz
381+
// nur hinzufügen wenn entweder noch Platz im Puffer oder wenn Puffer ganz
382382
// leer (dann sind Start- und Ende Zeiger gleich, aber das FContaisData Flag
383383
// ist noch false
384384
if (Count < Size) or ((Count = Size) and not FContainsData) then
@@ -403,19 +403,19 @@ procedure TRingbuffer<T>.Add(Items: TRingbufferArray);
403403
// Ende des Arrays
404404
i : UInt32;
405405
begin
406-
assert(length(Items) > 0, 'Hinzufügen eines leeren Arrays ist nicht sinnvoll');
406+
assert(length(Items) > 0, 'Hinzufügen eines leeren Arrays ist nicht sinnvoll');
407407

408-
// ist überhaupt noch soviel Platz im Puffer?
409-
// Typecast nach Int64 um W1023 Warnung zu unterdrücken
408+
// ist überhaupt noch soviel Platz im Puffer?
409+
// Typecast nach Int64 um W1023 Warnung zu unterdrücken
410410
if (length(Items) <= Int64(Size-Count)) then
411411
begin
412412
// leeres Array sollte eigentlich nicht vorkommen, aber falls im Release
413-
// Build Assertions aus sind sollte es auch nicht abstürzen
413+
// Build Assertions aus sind sollte es auch nicht abstürzen
414414
if (length(Items) > 0) then
415415
begin
416-
// Passt das übergebene Array im Stück in den Puffer und der Puffer Inhalt
417-
// geht derzeit auch nicht über die obere Grenze hinaus, oder muss es
418-
// gesplittet werden? Typecast nach Int64 um W1023 Warnung zu unterdrücken
416+
// Passt das übergebene Array im Stück in den Puffer und der Puffer Inhalt
417+
// geht derzeit auch nicht über die obere Grenze hinaus, oder muss es
418+
// gesplittet werden? Typecast nach Int64 um W1023 Warnung zu unterdrücken
419419
if (Int64(Size-FNextFree) >= length(Items)) then
420420
begin
421421
if not IsManagedType(T) then
@@ -447,7 +447,7 @@ procedure TRingbuffer<T>.Add(Items: TRingbufferArray);
447447
end;
448448
end;
449449

450-
// Endeindex erhöhen
450+
// Endeindex erhöhen
451451
AdvanceNextFree(length(Items));
452452
FContainsData := true;
453453

@@ -463,12 +463,12 @@ procedure TRingbuffer<T>.Add(Items: TRingbufferArray);
463463

464464
procedure TRingbuffer<T>.AdvanceNextFree(Increment: UInt32);
465465
var
466-
Remaining : UInt32; // Verbleibende Speicherplätze bis zur oberen Array Grenze
466+
Remaining : UInt32; // Verbleibende Speicherplätze bis zur oberen Array Grenze
467467
begin
468468
Remaining := Size-FNextFree;
469469

470470
inc(FNextFree, Increment);
471-
// Ende Marker über das Array-Ende hinaus erhöht
471+
// Ende Marker über das Array-Ende hinaus erhöht
472472
if (FNextFree > Size-1) then
473473
FNextFree := (Increment-Remaining);
474474
end;
@@ -481,7 +481,8 @@ procedure TRingbuffer<T>.Clear;
481481
FNextFree := 0;
482482
FContainsData := false;
483483

484-
FreeObjectsIfOwned(FStart, Size - 1);
484+
if (Size > 0) then
485+
FreeObjectsIfOwned(FStart, Size - 1);
485486

486487
// We exceet the upper end of the buffer so we need to clear the remaining
487488
// objects from the beginning
@@ -516,21 +517,22 @@ constructor TRingbuffer<T>.Create(Size: UInt32);
516517

517518
procedure TRingbuffer<T>.Delete(Count: UInt32);
518519
var
519-
Remaining : UInt32; // Verbleibende Speicherplätze bis zur oberen Array Grenze
520+
Remaining : UInt32; // Verbleibende Speicherplätze bis zur oberen Array Grenze
520521
i : Integer;
521522
begin
522523
if (Count <= Size) then
523524
begin
524-
// Puffer nur teilweise zu löschen?
525+
// Puffer nur teilweise zu löschen?
525526
if (Count < self.Count) then
526527
begin
527528
Remaining := Size - FStart;
528-
// Pufferinhalt geht nicht über obere Array Grenze hinaus?
529+
// Pufferinhalt geht nicht über obere Array Grenze hinaus?
529530
if (Count < Remaining) then
530531
begin
531532
if (Count > 0) then
532533
begin
533-
FreeObjectsIfOwned(FStart, FStart + Count - 1);
534+
if ((FStart+Count) > 0) then
535+
FreeObjectsIfOwned(FStart, FStart + Count - 1);
534536

535537
if IsManagedType(T) then
536538
for i := FStart to FStart + Count - 1 do
@@ -544,8 +546,11 @@ procedure TRingbuffer<T>.Delete(Count: UInt32);
544546
begin
545547
if (Count > 0) then
546548
begin
547-
FreeObjectsIfOwned(FStart, FStart + Remaining - 1);
548-
FreeObjectsIfOwned(0, Count - Remaining - 1);
549+
if ((FStart+Remaining) > 0) then
550+
FreeObjectsIfOwned(FStart, FStart + Remaining - 1);
551+
552+
if ((Count-Remaining) > 0) then
553+
FreeObjectsIfOwned(0, Count - Remaining - 1);
549554

550555
if IsManagedType(T) then
551556
begin
@@ -564,12 +569,12 @@ procedure TRingbuffer<T>.Delete(Count: UInt32);
564569
end;
565570
end;
566571

567-
// nur benachrichtigen wenn überhaupt was gelöscht werden sollte
572+
// nur benachrichtigen wenn überhaupt was gelöscht werden sollte
568573
if assigned(FNotify) and (Count > 0) then
569574
FNotify(Count, evRemove);
570575
end
571576
else
572-
// alles zu löschen
577+
// alles zu löschen
573578
Clear;
574579
end
575580
else
@@ -580,7 +585,8 @@ procedure TRingbuffer<T>.Delete(Count: UInt32);
580585

581586
destructor TRingbuffer<T>.Destroy;
582587
begin
583-
FreeObjectsIfOwned(0, Size-1);
588+
if (Size > 0) then
589+
FreeObjectsIfOwned(0, Size-1);
584590

585591
SetLength(FItems, 0);
586592

@@ -599,19 +605,19 @@ function TRingbuffer<T>.GetCount: UInt32;
599605
// Puffer ist weder komplett leer noch komplett voll
600606
if (FNextFree <> FStart) then
601607
begin
602-
// Je nach dem ob der Puffer gerade über das Ende hinaus geht und am Anfang
608+
// Je nach dem ob der Puffer gerade über das Ende hinaus geht und am Anfang
603609
// weiter geht
604610
if (FNextFree > FStart) then
605611
result := FNextFree-FStart
606612
else
607613
begin
608-
// Puffer geht über das Ende hinaus und beginnt am Array Anfang wieder
614+
// Puffer geht über das Ende hinaus und beginnt am Array Anfang wieder
609615
l := (length(FItems)-Int64(FStart))+FNextFree;
610616
result := abs(l);
611617
end;
612618
end
613619
else
614-
// Start = Ende aber es sind daten da? Dann ist Puffer maximal gefüllt
620+
// Start = Ende aber es sind daten da? Dann ist Puffer maximal gefüllt
615621
if FContainsData then
616622
result := Size
617623
else
@@ -675,7 +681,7 @@ function TRingbuffer<T>.Peek(Index, Count: UInt32): TRingbufferArray;
675681
// Is the index in the valid range?
676682
if (Count <= Size) and (Index < self.Count) then
677683
begin
678-
// Ist überhaupt was im Puffer?
684+
// Ist überhaupt was im Puffer?
679685
if (self.Count > 0) then
680686
begin
681687
// there are as many items in the buffer as shall be copied
@@ -732,31 +738,31 @@ function TRingbuffer<T>.Remove(RemoveCount: UInt32): TRingbufferArray;
732738
var
733739
RemoveableCount : UInt32; // Anzahl entfernbarer Elemente, meist Count
734740
RemainingCount : UInt32; // Anzahl Elemente von Start bis Pufferende
735-
StillContainsData : Boolean; // Enthält der Puffer nach der Remove Operation
741+
StillContainsData : Boolean; // Enthält der Puffer nach der Remove Operation
736742
// immer noch Daten?
737743
i : UInt32;
738744
begin
739745
if (RemoveCount > 0) then
740746
begin
741-
// wurden mehr Elemente angefordert als überhaupt je in den Puffer passen?
747+
// wurden mehr Elemente angefordert als überhaupt je in den Puffer passen?
742748
if (RemoveCount <= Size) then
743749
begin
744-
// Ist überhaupt was im Puffer?
750+
// Ist überhaupt was im Puffer?
745751
if (Count > 0) then
746752
begin
747753
// es sind soviele Elemente im Puffer wie entfernt werden sollen
748754
if (RemoveCount <= Count) then
749755
RemoveableCount := RemoveCount
750756
else
751-
// Nein, also nur soviele entfernen wie überhaupt möglich
757+
// Nein, also nur soviele entfernen wie überhaupt möglich
752758
RemoveableCount := Count;
753759

754760
SetLength(result, RemoveableCount);
755761
// wenn alle Elemente entfernt werden sollen muss Flag hinterher auf False
756762
// gesetzt werden
757763
StillContainsData := RemoveCount <> Count;
758764

759-
// geht der aktuelle Puffer inhalt über die obere Grenze (d.h. klappt um)?
765+
// geht der aktuelle Puffer inhalt über die obere Grenze (d.h. klappt um)?
760766
if ((FStart + RemoveableCount) <= Size) then
761767
begin
762768
// Nein, also Elemente direkt kopierbar
@@ -775,7 +781,7 @@ function TRingbuffer<T>.Remove(RemoveCount: UInt32): TRingbufferArray;
775781
end
776782
else
777783
begin
778-
// 2 Kopieroperationen nötig
784+
// 2 Kopieroperationen nötig
779785
RemainingCount := (Size-FStart);
780786

781787
// von Startzeiger bis Pufferende
@@ -827,7 +833,7 @@ function TRingbuffer<T>.Remove: T;
827833
var
828834
i : UInt32;
829835
begin
830-
// ist überhaupt was im Puffer?
836+
// ist überhaupt was im Puffer?
831837
if Count > 0 then
832838
begin
833839
result := FItems[FStart];
@@ -838,7 +844,7 @@ function TRingbuffer<T>.Remove: T;
838844

839845
// Anfangsmarker verschieben
840846
inc(FStart);
841-
// obere Grenze überschritten?
847+
// obere Grenze überschritten?
842848
if (FStart = Size) then
843849
FStart := 0;
844850

0 commit comments

Comments
 (0)