Note: "permalinks" may not be as permanent as we would like,
direct links of old sources may well be a few messages off.
On Thu, Jul 12, 2012 at 09:26:30AM +0000, BRESTAN Rainer wrote:
> Using drbdadm with environment variable MALLOC_CHECK_ set to not zero result in segmentation fault.
>
> Reason is the handling of most free operations in drbdadm_main.c, notably in functions free_config, free_host_info and maybe some other more.
>
> Example: function free_host_info
> for_each_volume(vol, hi->volumes)
> free_volume(vol);
>
> Function free_volume call as last libc function free(vol), which
> instructs libc in case of MALLOC_CHECK_ not zero to initialize memory
> with 0xcc. The macro for_each_volume take vol->next (which is now
> 0xcccccccc) as next vol and calls free_volume again which try to free
> the memory and this cause the segmentation fault.
>
> Example of correct behaviour is function free_options, which temporary stores the next element before freeing it.
>
> There is currently no race condition in free before next, because this part is not multi threaded.
>
> Questions:
> Is there a specific reason for doing that (DRBD 8.3.11 works fine with MALLOC_CHECK_) in DRBD 8.4.1 ?
> Is it planned or a bug ?
We certainly do not plan to segfault ;-)
> Patch ?
Won't be necessary.
diff --git a/user/drbdadm.h b/user/drbdadm.h
index 454fcf9..c3554d8 100644
--- a/user/drbdadm.h
+++ b/user/drbdadm.h
@@ -334,6 +334,9 @@ extern void add_setup_option(bool explicit, char *option);
#define for_each_volume(v_,volumes_) \
for (v_ = volumes_; v_; v_ = v_->next)
+#define for_each_volume_safe(v_,tmp_,volumes_) \
+ for (v_ = volumes_; v_ && ({ tmp_ = v_->next; 1; }); v_ = tmp_)
+
#define APPEND(LIST,ITEM) ({ \
typeof((LIST)) _l = (LIST); \
typeof((ITEM)) _i = (ITEM); \
diff --git a/user/drbdadm_main.c b/user/drbdadm_main.c
index 33d9d28..ace37a7 100644
--- a/user/drbdadm_main.c
+++ b/user/drbdadm_main.c
@@ -1235,13 +1235,13 @@ static void free_volume(struct d_volume *vol)
static void free_host_info(struct d_host_info *hi)
{
- struct d_volume *vol;
+ struct d_volume *vol, *tmp;
if (!hi)
return;
free_names(hi->on_hosts);
- for_each_volume(vol, hi->volumes)
+ for_each_volume_safe(vol, tmp, hi->volumes)
free_volume(vol);
free(hi->address);
free(hi->address_family);
Any more segfaults to report?
Thanks,
--
: Lars Ellenberg
: LINBIT | Your Way to High Availability
: DRBD/HA support and consulting http://www.linbit.com