Skip to content

Commit b83a6ac

Browse files
Siddhesh2377claude
andcommitted
fix(lora): address CodeRabbit OOM and cancellation issues
- LoraViewModel: add ensureActive() in download loop so coroutine cancellation is respected during blocking stream reads - lora_registry: check all rac_strdup results in deep_copy_lora_entry to prevent silent partial copies on OOM; use calloc for compatible_model_ids array and set count before fill loop so free_lora_entry can safely clean up on partial failure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9ccc748 commit b83a6ac

2 files changed

Lines changed: 16 additions & 4 deletions

File tree

  • examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/lora
  • sdk/runanywhere-commons/src/infrastructure/model_management

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/lora/LoraViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
2222
import kotlinx.coroutines.flow.StateFlow
2323
import kotlinx.coroutines.flow.asStateFlow
2424
import kotlinx.coroutines.flow.update
25+
import kotlinx.coroutines.ensureActive
2526
import kotlinx.coroutines.launch
2627
import kotlinx.coroutines.withContext
2728
import java.io.File
@@ -211,6 +212,7 @@ class LoraViewModel(application: Application) : AndroidViewModel(application) {
211212
val buffer = ByteArray(8192)
212213
var bytesRead: Int
213214
while (input.read(buffer).also { bytesRead = it } != -1) {
215+
ensureActive()
214216
output.write(buffer, 0, bytesRead)
215217
downloaded += bytesRead
216218
if (totalSize > 0) {

sdk/runanywhere-commons/src/infrastructure/model_management/lora_registry.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,32 @@ static rac_lora_entry_t* deep_copy_lora_entry(const rac_lora_entry_t* src) {
3131
copy->download_url = rac_strdup(src->download_url);
3232
copy->filename = rac_strdup(src->filename);
3333

34-
// id is required — if it failed to copy, the entry is unusable
35-
if (src->id && !copy->id) {
34+
// Any non-null source string that failed to copy means OOM — entry is unusable
35+
if ((src->id && !copy->id) ||
36+
(src->name && !copy->name) ||
37+
(src->description && !copy->description) ||
38+
(src->download_url && !copy->download_url) ||
39+
(src->filename && !copy->filename)) {
3640
free_lora_entry(copy);
3741
return nullptr;
3842
}
3943

4044
if (src->compatible_model_ids && src->compatible_model_count > 0) {
41-
copy->compatible_model_ids = static_cast<char**>(malloc(sizeof(char*) * src->compatible_model_count));
45+
// Use calloc so unwritten slots are null-safe for free_lora_entry on partial failure
46+
copy->compatible_model_ids = static_cast<char**>(calloc(src->compatible_model_count, sizeof(char*)));
4247
if (!copy->compatible_model_ids) {
4348
free_lora_entry(copy);
4449
return nullptr;
4550
}
51+
// Set count before filling so free_lora_entry can clean up on partial failure
52+
copy->compatible_model_count = src->compatible_model_count;
4653
for (size_t i = 0; i < src->compatible_model_count; ++i) {
4754
copy->compatible_model_ids[i] = rac_strdup(src->compatible_model_ids[i]);
55+
if (src->compatible_model_ids[i] && !copy->compatible_model_ids[i]) {
56+
free_lora_entry(copy);
57+
return nullptr;
58+
}
4859
}
49-
copy->compatible_model_count = src->compatible_model_count;
5060
}
5161
copy->file_size = src->file_size;
5262
copy->default_scale = src->default_scale;

0 commit comments

Comments
 (0)