From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 471DA3857C70; Sat, 28 Nov 2020 13:58:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 471DA3857C70 From: "keyid.w at qq dot com" To: glibc-bugs@sourceware.org Subject: [Bug malloc/26969] New: A common malloc pattern can make memory not given back to OS Date: Sat, 28 Nov 2020 13:58:35 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: glibc X-Bugzilla-Component: malloc X-Bugzilla-Version: 2.27 X-Bugzilla-Keywords: X-Bugzilla-Severity: enhancement X-Bugzilla-Who: keyid.w at qq dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P2 X-Bugzilla-Assigned-To: unassigned at sourceware dot org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://sourceware.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: glibc-bugs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Glibc-bugs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 28 Nov 2020 13:58:35 -0000 https://sourceware.org/bugzilla/show_bug.cgi?id=3D26969 Bug ID: 26969 Summary: A common malloc pattern can make memory not given back to OS Product: glibc Version: 2.27 Status: UNCONFIRMED Severity: enhancement Priority: P2 Component: malloc Assignee: unassigned at sourceware dot org Reporter: keyid.w at qq dot com Target Milestone: --- Some malloc patterns can easily make almost all freed memory not given back= to OS before program exits. An example is alternatively malloc-ing small-sized memory(67th line of the following codes) and large-sized memory(71st line of the following codes) and then free-ing them. You can try to run the program with arguments "1000 30 3 20" or "1000 30 0 20". The third number stands for thread number. You can also run with others arguments if you read the detai= l of program and know the meaning of other arguments. I used gdb to check the heap's state, and I believe this is caused by tcache/fast bins since free chunks in these bins are still considered "in u= se". Some tcache/fase bins stayed close to the heap's top so nearly all chunks couldn't be released. Though I know this is closer to a "corner case" of de= sign than a bug, I think this malloc pattern is very common(alternatively small = and large pieces) so programs' memory can easily be not released. Jemalloc perf= orms much better in this case. Would you consider to improve this? #include #include #include #include #include #define MAX_TICK_NUM 4800 #define MAX_FIELD_NUM 30 #define MAX_IID_NUM 4000 #define MAX_FIELD_NAME_LEN 20 #define MAX_THREAD_NUM 32 typedef struct tick_data_s { char *names[MAX_FIELD_NUM]; double *values[MAX_FIELD_NUM]; int size; } tick_data_t; typedef struct thread_args_s { int n_ticks; int n_fields; int field_name_len; tick_data_t *ticks; } thread_args_t; void init_thread_args(thread_args_t *t, int n_ticks, int n_fields, int field_name_len) { t->n_ticks =3D n_ticks; t->n_fields =3D n_fields; t->field_name_len =3D field_name_len; t->ticks =3D NULL; } void _free_tick_data(thread_args_t *t) { for (int i =3D 0; i < t->n_ticks; ++i) { for (int j =3D 0; j < t->ticks[i].size; ++j) { free(t->ticks[i].names[j]); free(t->ticks[i].values[j]); } } } void free_thread_args(thread_args_t *t) { if (t->ticks) { _free_tick_data(t); free(t->ticks); t->ticks =3D NULL; } } void _fill_tick_data(thread_args_t *t) { for (int i =3D 0; i < t->n_ticks; ++i) { for (int j =3D 0; j < t->n_fields; ++j) { if (t->field_name_len > 0) { char *name =3D (char *)malloc(t->field_name= _len); name[0] =3D (char)j; t->ticks[i].names[j] =3D name; } double *value =3D (double *)malloc(t->n_ticks * sizeof(double)); for (int k =3D 0; k < t->n_ticks; ++k) { value[k] =3D 1.0 * (i * k + j) / t->n_ticks; } t->ticks[i].values[j] =3D value; } t->ticks[i].size =3D t->n_fields; } } void *thread_main_func(void *args) { int thread_id =3D (int)pthread_self(); printf("thread created 0x%x\n", thread_id); thread_args_t *t =3D (thread_args_t *)args; t->ticks =3D (tick_data_t *)malloc(t->n_ticks * sizeof(tick_data_t)= ); _fill_tick_data(t); printf("thread done 0x%x\n", thread_id); return NULL; } int main(int argc, char *argv[]) { if (argc !=3D 5) { printf("Usage: glibc_tcache_exploit \n"); return 0; } //mallopt(M_MXFAST, 0); //mallopt(M_MMAP_THRESHOLD, 4096); int i =3D 0; int tick_num =3D atoi(argv[++i]); int field_num =3D atoi(argv[++i]); int thread_num =3D atoi(argv[++i]); int field_name_len =3D atoi(argv[++i]); printf("tick_num:%d field_num:%d thread_num:%d\n", tick_num, field_= num, thread_num); printf("field_name_len:%d\n", field_name_len); if (thread_num > 0) { pthread_t threads[MAX_THREAD_NUM]; thread_args_t thread_args[MAX_THREAD_NUM]; for (int i =3D 0; i < thread_num; ++i) { init_thread_args(&thread_args[i], tick_num, field_n= um, field_name_len); pthread_create(&threads[i], NULL, thread_main_func, &thread_args[i]); } printf("before join "); getchar(); for (int i =3D 0; i < thread_num; ++i) { pthread_join(threads[i], NULL); free_thread_args(&thread_args[i]); } } else { thread_args_t thread_arg; init_thread_args(&thread_arg, tick_num, field_num, field_name_len); thread_main_func(&thread_arg); free_thread_args(&thread_arg); } printf("before return "); getchar(); return 0; } --=20 You are receiving this mail because: You are on the CC list for the bug.=