blob: ee9bcc06ecc9b67167c1ef22dcd6a22226c088d6 [file] [log] [blame]
commit 87a64cc6f403485641a07152699016c4e9fc2bd2
Author: Fletcher Woodruff <fletcherw@chromium.org>
Date: Mon Oct 12 09:14:35 2020 -0600
test: free memory used for string options
Inside Test_Device, track whether we've already called init_options().
If we have, don't call it again when calling sane_open() again.
Add a function cleanup_options() which frees the memory used for these
options, and call it in sane_exit() if we previously called
init_options().
Change Test_Devices to be initialized with calloc instead of malloc,
so that we can assume that uninitialized fields are NULL, and can safely
call free() on them unconditionally.
This eliminates some larger memory leaks within the test backend.
diff --git a/backend/test.c b/backend/test.c
index a1e186ea3..251e89c26 100644
--- a/backend/test.c
+++ b/backend/test.c
@@ -320,6 +320,36 @@ check_handle (SANE_Handle handle)
return SANE_FALSE;
}
+static void
+cleanup_options (Test_Device * test_device)
+{
+ DBG (2, "cleanup_options: test_device=%p\n", (void *) test_device);
+
+ free(test_device->val[opt_mode].s);
+ test_device->val[opt_mode].s = NULL;
+
+ free(test_device->val[opt_three_pass_order].s);
+ test_device->val[opt_three_pass_order].s = NULL;
+
+ free(test_device->val[opt_scan_source].s);
+ test_device->val[opt_scan_source].s = NULL;
+
+ free(test_device->val[opt_test_picture].s);
+ test_device->val[opt_test_picture].s = NULL;
+
+ free(test_device->val[opt_read_status_code].s);
+ test_device->val[opt_read_status_code].s = NULL;
+
+ free(test_device->val[opt_string].s);
+ test_device->val[opt_string].s = NULL;
+
+ free(test_device->val[opt_string_constraint_string_list].s);
+ test_device->val[opt_string_constraint_string_list].s = NULL;
+
+ free(test_device->val[opt_string_constraint_long_string_list].s);
+ test_device->val[opt_string_constraint_long_string_list].s = NULL;
+}
+
static SANE_Status
init_options (Test_Device * test_device)
{
@@ -368,7 +398,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = mode_list;
test_device->val[opt_mode].s = malloc (od->size);
if (!test_device->val[opt_mode].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_mode].s, init_mode);
/* opt_depth */
@@ -435,7 +465,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = order_list;
test_device->val[opt_three_pass_order].s = malloc (od->size);
if (!test_device->val[opt_three_pass_order].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_three_pass_order].s, init_three_pass_order);
/* opt_resolution */
@@ -464,7 +494,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = source_list;
test_device->val[opt_scan_source].s = malloc (od->size);
if (!test_device->val[opt_scan_source].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_scan_source].s, init_scan_source);
/* opt_special_group */
@@ -500,7 +530,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = test_picture_list;
test_device->val[opt_test_picture].s = malloc (od->size);
if (!test_device->val[opt_test_picture].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_test_picture].s, init_test_picture);
/* opt_invert_endianness */
@@ -595,7 +625,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = read_status_code_list;
test_device->val[opt_read_status_code].s = malloc (od->size);
if (!test_device->val[opt_read_status_code].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_read_status_code].s, init_read_status_code);
/* opt_ppl_loss */
@@ -1129,7 +1159,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = 0;
test_device->val[opt_string].s = malloc (od->size);
if (!test_device->val[opt_string].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_string].s, init_string);
/* opt_string_constraint_string_list */
@@ -1148,7 +1178,7 @@ init_options (Test_Device * test_device)
od->constraint.string_list = string_constraint_string_list;
test_device->val[opt_string_constraint_string_list].s = malloc (od->size);
if (!test_device->val[opt_string_constraint_string_list].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_string_constraint_string_list].s,
init_string_constraint_string_list);
@@ -1169,7 +1199,7 @@ init_options (Test_Device * test_device)
test_device->val[opt_string_constraint_long_string_list].s =
malloc (od->size);
if (!test_device->val[opt_string_constraint_long_string_list].s)
- return SANE_STATUS_NO_MEM;
+ goto fail;
strcpy (test_device->val[opt_string_constraint_long_string_list].s,
init_string_constraint_long_string_list);
@@ -1202,6 +1232,10 @@ init_options (Test_Device * test_device)
test_device->val[opt_button].w = 0;
return SANE_STATUS_GOOD;
+
+fail:
+ cleanup_options (test_device);
+ return SANE_STATUS_NO_MEM;
}
static SANE_Status
@@ -1718,7 +1752,7 @@ sane_init (SANE_Int * __sane_unused__ version_code, SANE_Auth_Callback __sane_un
{
SANE_Char number_string[PATH_MAX];
- test_device = malloc (sizeof (*test_device));
+ test_device = calloc (sizeof (*test_device), 1);
if (!test_device)
return SANE_STATUS_NO_MEM;
test_device->sane.vendor = "Noname";
@@ -1740,6 +1774,7 @@ sane_init (SANE_Int * __sane_unused__ version_code, SANE_Auth_Callback __sane_un
test_device->eof = SANE_FALSE;
test_device->scanning = SANE_FALSE;
test_device->cancelled = SANE_FALSE;
+ test_device->options_initialized = SANE_FALSE;
sanei_thread_initialize (test_device->reader_pid);
test_device->pipe = -1;
DBG (4, "sane_init: new device: `%s' is a %s %s %s\n",
@@ -1772,6 +1807,8 @@ sane_exit (void)
DBG (4, "sane_exit: freeing device %s\n", test_device->name);
previous_device = test_device;
test_device = test_device->next;
+ if (previous_device->options_initialized)
+ cleanup_options (previous_device);
if (previous_device->name)
free (previous_device->name);
free (previous_device);
@@ -1855,9 +1892,12 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
test_device->open = SANE_TRUE;
*handle = test_device;
- status = init_options (test_device);
- if (status != SANE_STATUS_GOOD)
- return status;
+ if (!test_device->options_initialized) {
+ status = init_options (test_device);
+ if (status != SANE_STATUS_GOOD)
+ return status;
+ test_device->options_initialized = SANE_TRUE;
+ }
test_device->open = SANE_TRUE;
test_device->scanning = SANE_FALSE;
diff --git a/backend/test.h b/backend/test.h
index 5b1b82b32..aeaf109a8 100644
--- a/backend/test.h
+++ b/backend/test.h
@@ -143,6 +143,7 @@ typedef struct Test_Device
SANE_Bool scanning;
SANE_Bool cancelled;
SANE_Bool eof;
+ SANE_Bool options_initialized;
SANE_Int number_of_scans;
}
Test_Device;