Skip to content

Commit e589bfa

Browse files
authored
Merge pull request #3872 from p12tic/fix-scrollview-double-free (fixes issue #3869)
Fix memory issues in ScrollView::MessageReceiver.
2 parents 02e8340 + 0107687 commit e589bfa

File tree

9 files changed

+33
-56
lines changed

9 files changed

+33
-56
lines changed

src/classify/intproto.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,12 +1163,11 @@ void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
11631163
CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *pretrained_on,
11641164
int *shape_id) {
11651165
tprintf("%s\n", Prompt);
1166-
SVEvent *ev;
11671166
SVEventType ev_type;
11681167
int unichar_id = INVALID_UNICHAR_ID;
11691168
// Wait until a click or popup event.
11701169
do {
1171-
ev = IntMatchWindow->AwaitEvent(SVET_ANY);
1170+
auto ev = IntMatchWindow->AwaitEvent(SVET_ANY);
11721171
ev_type = ev->type;
11731172
if (ev_type == SVET_POPUP) {
11741173
if (ev->command_id == IDA_SHAPE_INDEX) {
@@ -1214,7 +1213,6 @@ CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *
12141213
}
12151214
}
12161215
}
1217-
delete ev;
12181216
} while (ev_type != SVET_CLICK);
12191217
return 0;
12201218
} /* GetClassToDebug */

src/classify/shapeclassifier.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ void ShapeClassifier::DebugDisplay(const TrainingSample &sample, Image page_pix,
115115
std::vector<UnicharRating> results;
116116
// Debug classification until the user quits.
117117
const UNICHARSET &unicharset = GetUnicharset();
118-
SVEvent *ev;
119118
SVEventType ev_type;
120119
do {
121120
std::vector<ScrollView *> windows;
@@ -135,7 +134,7 @@ void ShapeClassifier::DebugDisplay(const TrainingSample &sample, Image page_pix,
135134
UNICHAR_ID old_unichar_id;
136135
do {
137136
old_unichar_id = unichar_id;
138-
ev = debug_win->AwaitEvent(SVET_ANY);
137+
auto ev = debug_win->AwaitEvent(SVET_ANY);
139138
ev_type = ev->type;
140139
if (ev_type == SVET_POPUP) {
141140
if (unicharset.contains_unichar(ev->parameter)) {
@@ -144,7 +143,6 @@ void ShapeClassifier::DebugDisplay(const TrainingSample &sample, Image page_pix,
144143
tprintf("Char class '%s' not found in unicharset", ev->parameter);
145144
}
146145
}
147-
delete ev;
148146
} while (unichar_id == old_unichar_id && ev_type != SVET_CLICK && ev_type != SVET_DESTROY);
149147
for (auto window : windows) {
150148
delete window;

src/textord/ccnontextdetect.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ Image CCNonTextDetect::ComputeNonTextMask(bool debug, Image photo_map, TO_BLOCK
134134
#endif // !GRAPHICS_DISABLED
135135
pixWrite("junkccphotomask.png", pix, IFF_PNG);
136136
#ifndef GRAPHICS_DISABLED
137-
delete win->AwaitEvent(SVET_DESTROY);
137+
win->AwaitEvent(SVET_DESTROY);
138138
delete win;
139139
#endif // !GRAPHICS_DISABLED
140140
}

src/textord/colfind.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ int ColumnFinder::FindBlocks(PageSegMode pageseg_mode, Image scaled_color, int s
440440
DisplayTabVectors(window);
441441
}
442442
if (window != nullptr && textord_tabfind_show_partitions > 1) {
443-
delete window->AwaitEvent(SVET_DESTROY);
443+
window->AwaitEvent(SVET_DESTROY);
444444
}
445445
}
446446
}
@@ -476,7 +476,7 @@ int ColumnFinder::FindBlocks(PageSegMode pageseg_mode, Image scaled_color, int s
476476
bool waiting = false;
477477
do {
478478
waiting = false;
479-
SVEvent *event = blocks_win_->AwaitEvent(SVET_ANY);
479+
auto event = blocks_win_->AwaitEvent(SVET_ANY);
480480
if (event->type == SVET_INPUT && event->parameter != nullptr) {
481481
if (*event->parameter == 'd') {
482482
result = -1;
@@ -488,7 +488,6 @@ int ColumnFinder::FindBlocks(PageSegMode pageseg_mode, Image scaled_color, int s
488488
} else {
489489
waiting = true;
490490
}
491-
delete event;
492491
} while (waiting);
493492
}
494493
#endif // !GRAPHICS_DISABLED

src/textord/strokewidth.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ StrokeWidth::StrokeWidth(int gridsize, const ICOORD &bleft, const ICOORD &tright
123123
StrokeWidth::~StrokeWidth() {
124124
#ifndef GRAPHICS_DISABLED
125125
if (widths_win_ != nullptr) {
126-
delete widths_win_->AwaitEvent(SVET_DESTROY);
126+
widths_win_->AwaitEvent(SVET_DESTROY);
127127
if (textord_tabfind_only_strokewidths) {
128128
exit(0);
129129
}

src/training/common/mastertrainer.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -785,9 +785,8 @@ void MasterTrainer::DisplaySamples(const char *unichar_str1, int cloud_font,
785785
ScrollView *s_window = CreateFeatureSpaceWindow("Samples", 100, 500);
786786
SVEventType ev_type;
787787
do {
788-
SVEvent *ev;
789788
// Wait until a click or popup event.
790-
ev = f_window->AwaitEvent(SVET_ANY);
789+
auto ev = f_window->AwaitEvent(SVET_ANY);
791790
ev_type = ev->type;
792791
if (ev_type == SVET_CLICK) {
793792
int feature_index = feature_space.XYToFeatureIndex(ev->x, ev->y);
@@ -801,7 +800,6 @@ void MasterTrainer::DisplaySamples(const char *unichar_str1, int cloud_font,
801800
s_window->Update();
802801
}
803802
}
804-
delete ev;
805803
} while (ev_type != SVET_DESTROY);
806804
}
807805
#endif // !GRAPHICS_DISABLED

src/training/unicharset/lstmtrainer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ Trainability LSTMTrainer::TrainOnLine(const ImageData *trainingdata,
891891
}
892892
#ifndef GRAPHICS_DISABLED
893893
if (debug_interval_ == 1 && debug_win_ != nullptr) {
894-
delete debug_win_->AwaitEvent(SVET_CLICK);
894+
debug_win_->AwaitEvent(SVET_CLICK);
895895
}
896896
#endif // !GRAPHICS_DISABLED
897897
// Roll the memory of past means.

src/viewer/scrollview.cpp

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ struct SVPolyLineBuffer {
5656
static std::map<int, ScrollView *> svmap;
5757
static std::mutex *svmap_mu;
5858
// A map of all semaphores waiting for a specific event on a specific window.
59-
static std::map<std::pair<ScrollView *, SVEventType>, std::pair<SVSemaphore *, SVEvent *>>
60-
waiting_for_events;
59+
static std::map<std::pair<ScrollView *, SVEventType>,
60+
std::pair<SVSemaphore *, std::unique_ptr<SVEvent>>> waiting_for_events;
6161
static std::mutex *waiting_for_events_mu;
6262

63-
SVEvent *SVEvent::copy() const {
64-
auto *any = new SVEvent;
63+
std::unique_ptr<SVEvent> SVEvent::copy() const {
64+
auto any = std::unique_ptr<SVEvent>(new SVEvent);
6565
any->command_id = command_id;
6666
any->counter = counter;
6767
any->parameter = new char[strlen(parameter) + 1];
@@ -158,13 +158,13 @@ void ScrollView::MessageReceiver() {
158158
SVET_ANY);
159159
waiting_for_events_mu->lock();
160160
if (waiting_for_events.count(awaiting_list) > 0) {
161-
waiting_for_events[awaiting_list].second = cur.get();
161+
waiting_for_events[awaiting_list].second = std::move(cur);
162162
waiting_for_events[awaiting_list].first->Signal();
163163
} else if (waiting_for_events.count(awaiting_list_any) > 0) {
164-
waiting_for_events[awaiting_list_any].second = cur.get();
164+
waiting_for_events[awaiting_list_any].second = std::move(cur);
165165
waiting_for_events[awaiting_list_any].first->Signal();
166166
} else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
167-
waiting_for_events[awaiting_list_any_window].second = cur.get();
167+
waiting_for_events[awaiting_list_any_window].second = std::move(cur);
168168
waiting_for_events[awaiting_list_any_window].first->Signal();
169169
}
170170
waiting_for_events_mu->unlock();
@@ -319,38 +319,32 @@ void ScrollView::Initialize(const char *name, int x_pos, int y_pos, int x_size,
319319

320320
/// Sits and waits for events on this window.
321321
void ScrollView::StartEventHandler() {
322-
SVEvent *new_event;
323-
324322
for (;;) {
325323
stream_->Flush();
326324
semaphore_->Wait();
327-
new_event = nullptr;
328325
int serial = -1;
329326
int k = -1;
330327
mutex_.lock();
331328
// Check every table entry if it is valid and not already processed.
332329

333330
for (int i = 0; i < SVET_COUNT; i++) {
334331
if (event_table_[i] != nullptr && (serial < 0 || event_table_[i]->counter < serial)) {
335-
new_event = event_table_[i];
336332
serial = event_table_[i]->counter;
337333
k = i;
338334
}
339335
}
340336
// If we didn't find anything we had an old alarm and just sleep again.
341-
if (new_event != nullptr) {
342-
event_table_[k] = nullptr;
337+
if (k != -1) {
338+
auto new_event = std::move(event_table_[k]);
343339
mutex_.unlock();
344340
if (event_handler_ != nullptr) {
345-
event_handler_->Notify(new_event);
341+
event_handler_->Notify(new_event.get());
346342
}
347343
if (new_event->type == SVET_DESTROY) {
348344
// Signal the destructor that it is safe to terminate.
349345
event_handler_ended_ = true;
350-
delete new_event; // Delete the pointer after it has been processed.
351346
return;
352347
}
353-
delete new_event; // Delete the pointer after it has been processed.
354348
} else {
355349
mutex_.unlock();
356350
}
@@ -367,8 +361,7 @@ ScrollView::~ScrollView() {
367361
// So the event handling thread can quit.
368362
SendMsg("destroy()");
369363

370-
SVEvent *sve = AwaitEvent(SVET_DESTROY);
371-
delete sve;
364+
AwaitEvent(SVET_DESTROY);
372365
svmap_mu->lock();
373366
svmap[window_id_] = nullptr;
374367
svmap_mu->unlock();
@@ -383,9 +376,6 @@ ScrollView::~ScrollView() {
383376
}
384377
delete semaphore_;
385378
delete points_;
386-
for (auto &i : event_table_) {
387-
delete i;
388-
}
389379
#endif // !GRAPHICS_DISABLED
390380
}
391381

@@ -425,36 +415,33 @@ void ScrollView::Signal() {
425415

426416
void ScrollView::SetEvent(const SVEvent *svevent) {
427417
// Copy event
428-
SVEvent *any = svevent->copy();
429-
SVEvent *specific = svevent->copy();
418+
auto any = svevent->copy();
419+
auto specific = svevent->copy();
430420
any->counter = specific->counter + 1;
431421

432422
// Place both events into the queue.
433423
std::lock_guard<std::mutex> guard(mutex_);
434-
// Delete the old objects..
435-
delete event_table_[specific->type];
436-
delete event_table_[SVET_ANY];
437-
// ...and put the new ones in the table.
438-
event_table_[specific->type] = specific;
439-
event_table_[SVET_ANY] = any;
424+
425+
event_table_[specific->type] = std::move(specific);
426+
event_table_[SVET_ANY] = std::move(any);
440427
}
441428

442429
/// Block until an event of the given type is received.
443430
/// Note: The calling function is responsible for deleting the returned
444431
/// SVEvent afterwards!
445-
SVEvent *ScrollView::AwaitEvent(SVEventType type) {
432+
std::unique_ptr<SVEvent> ScrollView::AwaitEvent(SVEventType type) {
446433
// Initialize the waiting semaphore.
447434
auto *sem = new SVSemaphore();
448435
std::pair<ScrollView *, SVEventType> ea(this, type);
449436
waiting_for_events_mu->lock();
450-
waiting_for_events[ea] = std::pair<SVSemaphore *, SVEvent *>(sem, (SVEvent *)nullptr);
437+
waiting_for_events[ea] = {sem, nullptr};
451438
waiting_for_events_mu->unlock();
452439
// Wait on it, but first flush.
453440
stream_->Flush();
454441
sem->Wait();
455442
// Process the event we got woken up for (its in waiting_for_events pair).
456443
waiting_for_events_mu->lock();
457-
SVEvent *ret = waiting_for_events[ea].second;
444+
auto ret = std::move(waiting_for_events[ea].second);
458445
waiting_for_events.erase(ea);
459446
delete sem;
460447
waiting_for_events_mu->unlock();
@@ -734,23 +721,19 @@ void ScrollView::Brush(Color color) {
734721
// Shows a modal Input Dialog which can return any kind of String
735722
char *ScrollView::ShowInputDialog(const char *msg) {
736723
SendMsg("showInputDialog(\"%s\")", msg);
737-
SVEvent *ev;
738724
// wait till an input event (all others are thrown away)
739-
ev = AwaitEvent(SVET_INPUT);
725+
auto ev = AwaitEvent(SVET_INPUT);
740726
char *p = new char[strlen(ev->parameter) + 1];
741727
strcpy(p, ev->parameter);
742-
delete ev;
743728
return p;
744729
}
745730

746731
// Shows a modal Yes/No Dialog which will return 'y' or 'n'
747732
int ScrollView::ShowYesNoDialog(const char *msg) {
748733
SendMsg("showYesNoDialog(\"%s\")", msg);
749-
SVEvent *ev;
750734
// Wait till an input event (all others are thrown away)
751-
ev = AwaitEvent(SVET_INPUT);
735+
auto ev = AwaitEvent(SVET_INPUT);
752736
int a = ev->parameter[0];
753-
delete ev;
754737
return a;
755738
}
756739

src/viewer/scrollview.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <tesseract/export.h>
3737

3838
#include <cstdio>
39+
#include <memory>
3940
#include <mutex>
4041

4142
namespace tesseract {
@@ -69,7 +70,7 @@ struct SVEvent {
6970
~SVEvent() {
7071
delete[] parameter;
7172
}
72-
SVEvent *copy() const;
73+
std::unique_ptr<SVEvent> copy() const;
7374
SVEventType type = SVET_DESTROY; // What kind of event.
7475
ScrollView *window = nullptr; // Window event relates to.
7576
char *parameter = nullptr; // Any string that might have been passed as argument.
@@ -186,7 +187,7 @@ class TESS_API ScrollView {
186187
void AddEventHandler(SVEventHandler *listener);
187188

188189
// Block until an event of the given type is received.
189-
SVEvent *AwaitEvent(SVEventType type);
190+
std::unique_ptr<SVEvent> AwaitEvent(SVEventType type);
190191

191192
/*******************************************************************************
192193
* Getters and Setters
@@ -413,7 +414,7 @@ class TESS_API ScrollView {
413414
static SVNetwork *stream_;
414415

415416
// Table of all the currently queued events.
416-
SVEvent *event_table_[SVET_COUNT];
417+
std::unique_ptr<SVEvent> event_table_[SVET_COUNT];
417418

418419
// Mutex to access the event_table_ in a synchronized fashion.
419420
std::mutex mutex_;

0 commit comments

Comments
 (0)