Skip to content

Commit

Permalink
Fix memory leaks
Browse files Browse the repository at this point in the history
  • Loading branch information
clementetb committed Sep 25, 2023
1 parent fd9f19b commit b8d5944
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 26 deletions.
6 changes: 3 additions & 3 deletions benchmarks/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
// For CI buils, the packages are expected to have
// been built and deployed to a local filesystem
// maven repo.
//if (System.getenv("JENKINS_HOME") == null) {
// includeBuild("../packages")
//}
if (System.getenv("JENKINS_HOME") == null) {
includeBuild("../packages")
}

pluginManagement {
repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ actual object RealmInterop {
val computedCount = properties.count { it.isComputed }

// Class
val cclass = realm_class_info_t().apply {
val cclass = realm_class_info_t_managed().apply {
name = clazz.name
primary_key = clazz.primaryKey
num_properties = (properties.size - computedCount).toLong()
Expand All @@ -102,7 +102,7 @@ actual object RealmInterop {
// Properties
val classProperties = realmc.new_propertyArray(properties.size)
for ((j, property) in properties.withIndex()) {
val cproperty = realm_property_info_t().apply {
val cproperty = realm_property_info_t_managed().apply {
name = property.name
public_name = property.publicName
type = property.type.nativeValue
Expand All @@ -117,7 +117,18 @@ actual object RealmInterop {
realmc.classArray_setitem(cclasses, i, cclass)
realmc.propertyArrayArray_setitem(cproperties, i, classProperties)
}
return LongPointerWrapper(realmc.realm_schema_new(cclasses, count.toLong(), cproperties))
try {
return LongPointerWrapper(realmc.realm_schema_new(cclasses, count.toLong(), cproperties))
} finally {
// Clean up intermediate arrays
for (classIndex in 0 until count) {
val propertyArray = realmc.propertyArrayArray_getitem(cproperties, classIndex)
realmc.delete_propertyArray(propertyArray)
}

realmc.delete_propertyArrayArray(cproperties)
realmc.delete_classArray(cclasses)
}
}

actual fun realm_config_new(): RealmConfigurationPointer {
Expand Down Expand Up @@ -316,23 +327,27 @@ actual object RealmInterop {
val properties = realmc.new_propertyArray(max.toInt())
val outCount = longArrayOf(0)
realmc.realm_get_class_properties(realm.cptr(), classKey.key, properties, max, outCount)
return if (outCount[0] > 0) {
(0 until outCount[0]).map { i ->
with(realmc.propertyArray_getitem(properties, i.toInt())) {
PropertyInfo(
name,
public_name,
PropertyType.from(type),
CollectionType.from(collection_type),
link_target,
link_origin_property_name,
PropertyKey(key),
flags
)
try {
return if (outCount[0] > 0) {
(0 until outCount[0]).map { i ->
with(realmc.propertyArray_getitem(properties, i.toInt())) {
PropertyInfo(
name,
public_name,
PropertyType.from(type),
CollectionType.from(collection_type),
link_target,
link_origin_property_name,
PropertyKey(key),
flags
)
}
}
} else {
emptyList()
}
} else {
emptyList()
} finally {
realmc.delete_propertyArray(properties)
}
}

Expand Down Expand Up @@ -922,6 +937,8 @@ actual object RealmInterop {
builder.initIndicesArray(builder::modificationIndices, modificationIndices)
builder.initIndicesArray(builder::modificationIndicesAfter, modificationIndicesAfter)
builder.movesCount = movesCount[0].toInt()

realmc.delete_collectionMoveArray(moves)
}

actual fun <T, R> realm_collection_changes_get_ranges(
Expand Down Expand Up @@ -969,6 +986,12 @@ actual object RealmInterop {
builder.initRangesArray(builder::insertionRanges, insertionRanges, insertRangesCount[0])
builder.initRangesArray(builder::modificationRanges, modificationRanges, modificationRangesCount[0])
builder.initRangesArray(builder::modificationRangesAfter, modificationRangesAfter, modificationRangesCount[0])

realmc.delete_indexRangeArray(insertionRanges)
realmc.delete_indexRangeArray(modificationRanges)
realmc.delete_indexRangeArray(modificationRangesAfter)
realmc.delete_indexRangeArray(deletionRanges)
realmc.delete_collectionMoveArray(moves)
}

actual fun <R> realm_dictionary_get_changes(
Expand Down Expand Up @@ -1107,6 +1130,8 @@ actual object RealmInterop {
}
} else {
emptyList()
}.also {
realmc.delete_identityArray(keys)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2023 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("ClassNaming")

package io.realm.kotlin.internal.interop

/**
* realm_class_info_t variant that automatically frees any heap allocated resources
*/
class realm_class_info_t_managed : realm_class_info_t() {
@Synchronized
override fun delete() {
if (realm_class_info_t.getCPtr(this) != 0L) {
realmc.realm_class_info_t_cleanup(this)
}
super.delete()
}
}

/**
* realm_property_info_t variant that automatically frees any heap allocated resources
*/
class realm_property_info_t_managed : realm_property_info_t() {
@Synchronized
override fun delete() {
if (realm_property_info_t.getCPtr(this) != 0L) {
realmc.realm_property_info_t_cleanup(this)
}
super.delete()
}
}
24 changes: 19 additions & 5 deletions packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,10 +721,10 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error)
jboolean is_unrecognized_by_client = error.is_unrecognized_by_client;
jboolean is_client_reset_requested = error.is_client_reset_requested;

auto user_info_map = new std::map<std::string, std::string>();
auto user_info_map = std::map<std::string, std::string>();
for (int i = 0; i < error.user_info_length; i++) {
realm_sync_error_user_info_t user_info = error.user_info_map[i];
user_info_map->insert(std::make_pair(user_info.key, user_info.value));
user_info_map.insert(std::make_pair(user_info.key, user_info.value));
}

static JavaMethod core_compensating_write_info_constructor(
Expand Down Expand Up @@ -766,16 +766,16 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error)
// mark the file for deletion. Having 'original path' in the user_info_map is a side effect of
// using the same code for client reset.
if (error.user_info_length > 0) {
auto end_it = user_info_map->end();
auto end_it = user_info_map.end();

auto original_it = user_info_map->find(error.c_original_file_path_key);
auto original_it = user_info_map.find(error.c_original_file_path_key);
if (end_it != original_it) {
auto original_file_path = original_it->second;
joriginal_file_path = to_jstring(jenv, original_file_path);
}

// Sync errors may not have the path to the recovery file unless a Client Reset is requested
auto recovery_it = user_info_map->find(error.c_recovery_file_path_key);
auto recovery_it = user_info_map.find(error.c_recovery_file_path_key);
if (error.is_client_reset_requested && (end_it != recovery_it)) {
auto recovery_file_path = recovery_it->second;
jrecovery_file_path = to_jstring(jenv, recovery_file_path);
Expand Down Expand Up @@ -1053,3 +1053,17 @@ realm_scheduler_t*
realm_create_generic_scheduler() {
return new realm_scheduler_t { realm::util::Scheduler::make_dummy() };
}

void
realm_property_info_t_cleanup(realm_property_info_t* value) {
delete[] value->link_origin_property_name;
delete[] value->link_target;
delete[] value->name;
delete[] value->public_name;
}

void
realm_class_info_t_cleanup(realm_class_info_t * value) {
delete[] value->primary_key;
delete[] value->name;
}
6 changes: 6 additions & 0 deletions packages/jni-swig-stub/src/main/jni/realm_api_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,10 @@ realm_sync_thread_error(realm_userdata_t userdata, const char* error);
realm_scheduler_t*
realm_create_generic_scheduler();

void
realm_property_info_t_cleanup(realm_property_info_t* value);

void
realm_class_info_t_cleanup(realm_class_info_t * value);

#endif //TEST_REALM_API_HELPERS_H

0 comments on commit b8d5944

Please sign in to comment.