Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r.terraflow: Handle memory reallocation errors gracefully #3970

Merged
merged 15 commits into from
Aug 15, 2024
74 changes: 53 additions & 21 deletions raster/r.terraflow/unionFind.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
#ifndef __UNION_FIND
#define __UNION_FIND

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <cstdlib>
ShubhamDesai marked this conversation as resolved.
Show resolved Hide resolved
#include <cstring>
#include <iostream>

extern "C" {
#include <grass/glocale.h>
}

/* initial range guesstimate */
#define UNION_INITIAL_SIZE 2000

Expand Down Expand Up @@ -68,11 +71,15 @@ unionFind<T>::unionFind()
{
maxsize = UNION_INITIAL_SIZE;
/* parent = new (long)[maxsize]; */
parent = (T *)calloc(maxsize, sizeof(T));
assert(parent);
parent = static_cast<T *>(calloc(maxsize, sizeof(T)));
if (!parent) {
G_fatal_error(_("Not enough memory for %s"), "parent");
}
ShubhamDesai marked this conversation as resolved.
Show resolved Hide resolved
/* rank = new (long)[maxsize]; */
rank = (T *)calloc(maxsize, sizeof(T));
assert(rank);
rank = static_cast<T *>(calloc(maxsize, sizeof(T)));
if (!rank) {
G_fatal_error(_("Not enough memory for %s"), "rank");
}
ShubhamDesai marked this conversation as resolved.
Show resolved Hide resolved
}

/************************************************************/
Expand Down Expand Up @@ -122,23 +129,35 @@ template <class T>
inline void unionFind<T>::makeSet(T x)
{
/* cout << "makeSet " << x << "\n"; print(); */
assert(x > 0);
if (x <= 0) {
G_fatal_error(_("Invalid set element: %d"), x);
}
if (x >= maxsize) {
/* reallocate parent */
cout << "UnionFind::makeSet: reallocate double " << maxsize << "\n";
parent = (T *)realloc(parent, 2 * maxsize * sizeof(T));
assert(parent);
memset(parent + maxsize, 0, maxsize * sizeof(T));
/*reallocate rank */
rank = (T *)realloc(rank, 2 * maxsize * sizeof(T));
assert(rank);
memset(rank + maxsize, 0, maxsize * sizeof(T));
if (void *new_parent = std::realloc(parent, 2 * maxsize * sizeof(T))) {
parent = static_cast<T *>(new_parent);
std::memset(parent + maxsize, 0, maxsize * sizeof(T));
}
else {
G_fatal_error(_("Not enough memory for %s"), "parent");
}
/* reallocate rank */
if (void *new_rank = std::realloc(rank, 2 * maxsize * sizeof(T))) {
rank = static_cast<T *>(new_rank);
std::memset(rank + maxsize, 0, maxsize * sizeof(T));
}
else {
G_fatal_error(_("Not enough memory for %s"), "rank");
}
/*update maxsize */
maxsize *= 2;
}
/*since x is disjoint we require x not be already in the set; should
relax this..*/
assert(!inSet(x));
if (inSet(x)) {
nilason marked this conversation as resolved.
Show resolved Hide resolved
G_fatal_error(_("Element %d is already in the set"), x);
}
parent[x] = x;
rank[x] = 0;
}
Expand All @@ -149,13 +168,17 @@ template <class T>
inline T unionFind<T>::findSet(T x)
{
/* valid entry */
assert(inSet(x));
if (!inSet(x)) {
G_fatal_error(_("Element %d is not in the set"), x);
}
if (parent[x] != x) {
/* path compression heuristic */
parent[x] = findSet(parent[x]);
}
/* parent[x] must be a root */
assert(parent[parent[x]] == parent[x]);
if (parent[parent[x]] != parent[x]) {
G_fatal_error(_("Parent of element %d is not a root"), x);
}
return parent[x];
}

Expand All @@ -164,14 +187,20 @@ inline T unionFind<T>::findSet(T x)
template <class T>
inline void unionFind<T>::makeUnion(T x, T y)
{
assert(inSet(x) && inSet(y));
if (!inSet(x) || !inSet(y)) {
G_fatal_error(_("One or both elements (%d, %d) are not in the set"), x,
y);
}
T setx = findSet(x);
T sety = findSet(y);
if (setx == sety)
return;

/* union by rank heuristic */
assert(inSet(x) && inSet(y));
if (!inSet(x) || !inSet(y)) {
G_fatal_error(_("One or both elements (%d, %d) are not in the set"), x,
y);
}
if (rank[setx] > rank[sety]) {
/* hook sety onto setx */
parent[sety] = setx;
Expand All @@ -185,7 +214,10 @@ inline void unionFind<T>::makeUnion(T x, T y)
}
}
/* this does not have side effects.. */
assert(findSet(x) == findSet(y));
if (findSet(x) != findSet(y)) {
G_fatal_error(
_("Elements %d and %d are not in the same set after union"), x, y);
}
}

/************************************************************/
Expand Down
Loading