2009/5/22 Bram Moolenaar <b...@moolenaar.net>: > > > Dominique Pelle wrote: > >> Nico Weber wrote: >> >> > Hi, >> > >> > On 03.05.2009, at 00:03, Dominique Pellé wrote: >> > >> >> After applying your patch, there are no such errors anymore. >> >> >> >> However, when exiting, I see that those blocks are not being >> >> freed: >> >> >> >> ==16990== 217 bytes in 10 blocks are possibly lost in loss record 36 >> >> of 57 >> >> ==16990== at 0x402603E: malloc (vg_replace_malloc.c:207) >> >> ==16990== by 0x81142FA: lalloc (misc2.c:866) >> >> ==16990== by 0x8114216: alloc (misc2.c:765) >> >> ==16990== by 0x807AD1D: dictitem_alloc (eval.c:6775) >> >> ==16990== by 0x8074FFD: set_var_lval (eval.c:2856) >> >> ==16990== by 0x80742F4: ex_let_one (eval.c:2414) >> >> ==16990== by 0x807329F: ex_let_vars (eval.c:1869) >> >> ==16990== by 0x8073250: ex_let (eval.c:1834) >> >> ==16990== by 0x80A6AA3: do_one_cmd (ex_docmd.c:2622) >> >> ==16990== by 0x80A4323: do_cmdline (ex_docmd.c:1096) >> >> ==16990== by 0x8090328: call_user_func (eval.c:21301) >> >> ==16990== by 0x807C4FE: call_func (eval.c:8079) >> >> ==16990== by 0x807C142: get_func_tv (eval.c:7925) >> >> ==16990== by 0x8075B83: ex_call (eval.c:3333) >> >> ==16990== by 0x80A6AA3: do_one_cmd (ex_docmd.c:2622) >> >> ==16990== by 0x80A4323: do_cmdline (ex_docmd.c:1096) >> >> ==16990== by 0x812A758: nv_colon (normal.c:5227) >> >> ==16990== by 0x8123DA2: normal_cmd (normal.c:1189) >> >> ==16990== by 0x80E6D49: main_loop (main.c:1180) >> >> ==16990== by 0x80E6896: main (main.c:939) >> >> >> >> I built Vim with -DEXITFREE (i.e. uncommented line >> >> PROFILE_CFLAGS = -DEXITFREE in src/Makefile) >> >> so normally all blocks should be freed when exiting. >> > >> > Thanks for checking. >> > >> > I've attached an updated version of the patch that fixes some of the >> > leaks. The copy()d dicts in the script don't get freed, but I don't >> > (yet?) understand why. >> > >> > Nico >> >> >> I tried to fix the leak as well but without success so far. >> It does not seem simple. >> >> In any cases, it's a real leak, running the following leak.vim >> script for example causes Vim memory usage to grow >> continuously: >> >> --- 8< --- cut here --- 8< --- cut here --- 8< --- >> set nocp >> >> " foo.vim is the script attached in the original bug submission >> " at >> http://groups.google.com/group/vim_mac/browse_thread/thread/4e0149ff4f84e3d3 >> so foo.vim >> >> let g:count_loops = 0 >> while 1 >> call foo#Buffer.New() >> q >> let g:count_loops = g:count_loops + 1 >> endwhile >> --- 8< --- cut here --- 8< --- cut here --- 8< --- >> >> I do: >> >> $ vim -u NONE leak.vim >> :so % >> >> Then in another xterm, I can see with "top" that memory usage >> of Vim keeps increasing. >> >> If I run the leak.vim script with Valgrind... >> >> valgrind --leak-resolution=high --leak-check=yes \ >> --num-callers=30 --track-fds=yes 2> vg.log \ >> ./vim -u NONE leak.vim >> >> Then do: >> - :so % >> - let the script execute for some time >> - press CTRL-C to interrupt the infinite loop >> - Look at how many times loop iterated with >> :echo g:count_loops >> (it prints 2774 for example) >> - then quit vim: qa! >> >> Then look for leaks in vg.log, and observe that some leaks >> happen exactly 2774 times (same number as number as >> g:loop_count): >> >> ==22962== 27,740 bytes in 2,774 blocks are possibly lost in loss >> record 113 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x8114C16: vim_strsave (misc2.c:1177) >> ==22962== by 0x808C427: copy_tv (eval.c:19380) >> ==22962== by 0x808AE51: get_var_tv (eval.c:18452) >> ==22962== by 0x80785E7: eval7 (eval.c:5032) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8079667: get_list_tv (eval.c:5675) >> ==22962== by 0x807837D: eval7 (eval.c:4943) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== >> ==22962== >> ==22962== 33,288 bytes in 5,548 blocks are possibly lost in loss >> record 114 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x8114C16: vim_strsave (misc2.c:1177) >> ==22962== by 0x808C427: copy_tv (eval.c:19380) >> ==22962== by 0x807B117: dict_copy (eval.c:6961) >> ==22962== by 0x808C662: item_copy (eval.c:19471) >> ==22962== by 0x807DB82: f_copy (eval.c:9141) >> ==22962== by 0x807C7DF: call_func (eval.c:8188) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x807859A: eval7 (eval.c:5018) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== by 0x80A1F9B: ex_source (ex_cmds2.c:2714) >> ==22962== >> ==22962== >> ==22962== 49,932 bytes in 8,322 blocks are possibly lost in loss >> record 115 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x8114C16: vim_strsave (misc2.c:1177) >> ==22962== by 0x808C427: copy_tv (eval.c:19380) >> ==22962== by 0x807B117: dict_copy (eval.c:6961) >> ==22962== by 0x808C662: item_copy (eval.c:19471) >> ==22962== by 0x807DB82: f_copy (eval.c:9141) >> ==22962== by 0x807C7DF: call_func (eval.c:8188) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x807859A: eval7 (eval.c:5018) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x808AF05: handle_subscript (eval.c:18491) >> ==22962== by 0x8078640: eval7 (eval.c:5046) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== >> ==22962== >> ==22962== 58,254 bytes in 2,774 blocks are possibly lost in loss >> record 116 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AEFC: dictitem_alloc (eval.c:6855) >> ==22962== by 0x807507D: set_var_lval (eval.c:2864) >> ==22962== by 0x8074374: ex_let_one (eval.c:2422) >> ==22962== by 0x807331F: ex_let_vars (eval.c:1877) >> ==22962== by 0x80732D0: ex_let (eval.c:1842) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== by 0x80A1F9B: ex_source (ex_cmds2.c:2714) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x812ACC4: nv_colon (normal.c:5227) >> ==22962== by 0x812430E: normal_cmd (normal.c:1189) >> ==22962== by 0x80E6F3D: main_loop (main.c:1180) >> ==22962== >> ==22962== >> ==22962== 77,672 bytes in 2,774 blocks are possibly lost in loss >> record 117 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AEFC: dictitem_alloc (eval.c:6855) >> ==22962== by 0x807507D: set_var_lval (eval.c:2864) >> ==22962== by 0x8074374: ex_let_one (eval.c:2422) >> ==22962== by 0x807331F: ex_let_vars (eval.c:1877) >> ==22962== by 0x80732D0: ex_let (eval.c:1842) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x808AF05: handle_subscript (eval.c:18491) >> ==22962== by 0x8078640: eval7 (eval.c:5046) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== >> ==22962== >> ==22962== 133,152 bytes in 5,548 blocks are possibly lost in loss >> record 118 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AEFC: dictitem_alloc (eval.c:6855) >> ==22962== by 0x807B0B3: dict_copy (eval.c:6948) >> ==22962== by 0x808C662: item_copy (eval.c:19471) >> ==22962== by 0x807DB82: f_copy (eval.c:9141) >> ==22962== by 0x807C7DF: call_func (eval.c:8188) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x807859A: eval7 (eval.c:5018) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== by 0x80A1F9B: ex_source (ex_cmds2.c:2714) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== >> ==22962== >> ==22962== 160,892 bytes in 5,548 blocks are possibly lost in loss >> record 119 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AEFC: dictitem_alloc (eval.c:6855) >> ==22962== by 0x807507D: set_var_lval (eval.c:2864) >> ==22962== by 0x8074374: ex_let_one (eval.c:2422) >> ==22962== by 0x807331F: ex_let_vars (eval.c:1877) >> ==22962== by 0x80732D0: ex_let (eval.c:1842) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== by 0x80A1F9B: ex_source (ex_cmds2.c:2714) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x812ACC4: nv_colon (normal.c:5227) >> ==22962== by 0x812430E: normal_cmd (normal.c:1189) >> ==22962== by 0x80E6F3D: main_loop (main.c:1180) >> ==22962== by 0x80E6A8A: main (main.c:939) >> ==22962== >> ==22962== >> ==22962== 213,598 bytes in 8,322 blocks are possibly lost in loss >> record 120 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AEFC: dictitem_alloc (eval.c:6855) >> ==22962== by 0x807B0B3: dict_copy (eval.c:6948) >> ==22962== by 0x808C662: item_copy (eval.c:19471) >> ==22962== by 0x807DB82: f_copy (eval.c:9141) >> ==22962== by 0x807C7DF: call_func (eval.c:8188) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x807859A: eval7 (eval.c:5018) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x808AF05: handle_subscript (eval.c:18491) >> ==22962== by 0x8078640: eval7 (eval.c:5046) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== >> ==22962== >> ==22962== 288,496 bytes in 5,548 blocks are possibly lost in loss >> record 121 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114723: alloc_clear (misc2.c:777) >> ==22962== by 0x80797D0: list_alloc (eval.c:5729) >> ==22962== by 0x807961D: get_list_tv (eval.c:5667) >> ==22962== by 0x807837D: eval7 (eval.c:4943) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== >> ==22962== >> ==22962== 399,456 bytes in 16,644 blocks are possibly lost in loss >> record 122 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807994D: listitem_alloc (eval.c:5810) >> ==22962== by 0x807967A: get_list_tv (eval.c:5679) >> ==22962== by 0x807837D: eval7 (eval.c:4943) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== >> ==22962== >> ==22962== 499,320 bytes in 2,774 blocks are possibly lost in loss >> record 123 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AD1E: dict_alloc (eval.c:6770) >> ==22962== by 0x807B6A8: get_dict_tv (eval.c:7216) >> ==22962== by 0x807839E: eval7 (eval.c:4949) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x808AF05: handle_subscript (eval.c:18491) >> ==22962== by 0x8078640: eval7 (eval.c:5046) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== >> ==22962== >> ==22962== 499,320 bytes in 2,774 blocks are possibly lost in loss >> record 124 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AD1E: dict_alloc (eval.c:6770) >> ==22962== by 0x807B040: dict_copy (eval.c:6933) >> ==22962== by 0x808C662: item_copy (eval.c:19471) >> ==22962== by 0x807DB82: f_copy (eval.c:9141) >> ==22962== by 0x807C7DF: call_func (eval.c:8188) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x807859A: eval7 (eval.c:5018) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x808AF05: handle_subscript (eval.c:18491) >> ==22962== by 0x8078640: eval7 (eval.c:5046) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== >> ==22962== >> ==22962== 499,320 bytes in 2,774 blocks are possibly lost in loss >> record 125 of 125 >> ==22962== at 0x402603E: malloc (vg_replace_malloc.c:207) >> ==22962== by 0x81147FD: lalloc (misc2.c:866) >> ==22962== by 0x8114708: alloc (misc2.c:765) >> ==22962== by 0x807AD1E: dict_alloc (eval.c:6770) >> ==22962== by 0x807B040: dict_copy (eval.c:6933) >> ==22962== by 0x808C662: item_copy (eval.c:19471) >> ==22962== by 0x807DB82: f_copy (eval.c:9141) >> ==22962== by 0x807C7DF: call_func (eval.c:8188) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x807859A: eval7 (eval.c:5018) >> ==22962== by 0x8077EA3: eval6 (eval.c:4685) >> ==22962== by 0x8077A8F: eval5 (eval.c:4501) >> ==22962== by 0x8076FE0: eval4 (eval.c:4196) >> ==22962== by 0x8076E38: eval3 (eval.c:4108) >> ==22962== by 0x8076CC4: eval2 (eval.c:4037) >> ==22962== by 0x8076AF4: eval1 (eval.c:3962) >> ==22962== by 0x8076A5B: eval0 (eval.c:3919) >> ==22962== by 0x807326C: ex_let (eval.c:1833) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x8090507: call_user_func (eval.c:21381) >> ==22962== by 0x807C6DD: call_func (eval.c:8159) >> ==22962== by 0x807C321: get_func_tv (eval.c:8005) >> ==22962== by 0x8075C03: ex_call (eval.c:3341) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) >> ==22962== by 0x80A450B: do_cmdline (ex_docmd.c:1096) >> ==22962== by 0x80A2793: do_source (ex_cmds2.c:3119) >> ==22962== by 0x80A2047: cmd_source (ex_cmds2.c:2741) >> ==22962== by 0x80A1F9B: ex_source (ex_cmds2.c:2714) >> ==22962== by 0x80A6C8B: do_one_cmd (ex_docmd.c:2622) > > Here is a new patch that hopefully fixes both the crash and the leaks. > It's a bit tricky, but I think this catches all situations. > Please verify. > > Note that with your script one needs to wait a few moments before > exiting to give the garbage collector a chance. > > > *** ../vim-7.2.185/src/eval.c 2009-05-16 17:29:37.000000000 +0200 > --- src/eval.c 2009-05-22 20:04:22.000000000 +0200 > *************** > *** 129,136 **** > --- 129,139 ---- > /* > * When recursively copying lists and dicts we need to remember which ones we > * have done to avoid endless recursiveness. This unique ID is used for > that. > + * The last bit is used for previous_funccal, ignored when comparing. > */ > static int current_copyID = 0; > + #define COPYID_INC 2 > + #define COPYID_MASK (~0x1) > > /* > * Array to hold the hashtab with variables local to each sourced script. > *************** > *** 439,444 **** > --- 442,448 ---- > static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T > *item2)); > static char_u *list2string __ARGS((typval_T *tv, int copyID)); > static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int > echo, int copyID)); > + static int free_unref_items __ARGS((int copyID)); > static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); > static void set_ref_in_list __ARGS((list_T *l, int copyID)); > static void set_ref_in_item __ARGS((typval_T *tv, int copyID)); > *************** > *** 6494,6507 **** > int > garbage_collect() > { > ! dict_T *dd; > ! list_T *ll; > ! int copyID = ++current_copyID; > buf_T *buf; > win_T *wp; > int i; > funccall_T *fc, **pfc; > ! int did_free = FALSE; > #ifdef FEAT_WINDOWS > tabpage_T *tp; > #endif > --- 6498,6510 ---- > int > garbage_collect() > { > ! int copyID; > buf_T *buf; > win_T *wp; > int i; > funccall_T *fc, **pfc; > ! int did_free; > ! int did_free_funccal = FALSE; > #ifdef FEAT_WINDOWS > tabpage_T *tp; > #endif > *************** > *** 6511,6520 **** > --- 6514,6538 ---- > may_garbage_collect = FALSE; > garbage_collect_at_exit = FALSE; > > + /* We advance by two because we add one for items referenced through > + * previous_funccal. */ > + current_copyID += COPYID_INC; > + copyID = current_copyID; > + > /* > * 1. Go through all accessible variables and mark all lists and dicts > * with copyID. > */ > + > + /* Don't free variables in the previous_funccal list unless they are > only > + * referenced through previous_funccal. This must be first, because if > + * the item is referenced elsewhere it must not be freed. */ > + for (fc = previous_funccal; fc != NULL; fc = fc->caller) > + { > + set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1); > + set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1); > + } > + > /* script-local variables */ > for (i = 1; i <= ga_scripts.ga_len; ++i) > set_ref_in_ht(&SCRIPT_VARS(i), copyID); > *************** > *** 6546,6556 **** > /* v: vars */ > set_ref_in_ht(&vimvarht, copyID); > > /* > ! * 2. Go through the list of dicts and free items without the copyID. > */ > for (dd = first_dict; dd != NULL; ) > ! if (dd->dv_copyID != copyID) > { > /* Free the Dictionary and ordinary items it contains, but don't > * recurse into Lists and Dictionaries, they will be in the list > --- 6564,6610 ---- > /* v: vars */ > set_ref_in_ht(&vimvarht, copyID); > > + /* Free lists and dictionaries that are not referenced. */ > + did_free = free_unref_items(copyID); > + > + /* check if any funccal can be freed now */ > + for (pfc = &previous_funccal; *pfc != NULL; ) > + { > + if (can_free_funccal(*pfc, copyID)) > + { > + fc = *pfc; > + *pfc = fc->caller; > + free_funccal(fc, TRUE); > + did_free = TRUE; > + did_free_funccal = TRUE; > + } > + else > + pfc = &(*pfc)->caller; > + } > + if (did_free_funccal) > + /* When a funccal was freed some more items might be garbage > + * collected, so run again. */ > + (void)garbage_collect(); > + > + return did_free; > + } > + > + /* > + * Free lists and dictionaries that are no longer referenced. > + */ > + static int > + free_unref_items(copyID) > + int copyID; > + { > + dict_T *dd; > + list_T *ll; > + int did_free = FALSE; > + > /* > ! * Go through the list of dicts and free items without the copyID. > */ > for (dd = first_dict; dd != NULL; ) > ! if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) > { > /* Free the Dictionary and ordinary items it contains, but don't > * recurse into Lists and Dictionaries, they will be in the list > *************** > *** 6565,6576 **** > dd = dd->dv_used_next; > > /* > ! * 3. Go through the list of lists and free items without the copyID. > ! * But don't free a list that has a watcher (used in a for loop), > these > ! * are not referenced anywhere. > */ > for (ll = first_list; ll != NULL; ) > ! if (ll->lv_copyID != copyID && ll->lv_watch == NULL) > { > /* Free the List and ordinary items it contains, but don't recurse > * into Lists and Dictionaries, they will be in the list of dicts > --- 6619,6631 ---- > dd = dd->dv_used_next; > > /* > ! * Go through the list of lists and free items without the copyID. > ! * But don't free a list that has a watcher (used in a for loop), these > ! * are not referenced anywhere. > */ > for (ll = first_list; ll != NULL; ) > ! if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) > ! && ll->lv_watch == NULL) > { > /* Free the List and ordinary items it contains, but don't recurse > * into Lists and Dictionaries, they will be in the list of dicts > *************** > *** 6584,6603 **** > else > ll = ll->lv_used_next; > > - /* check if any funccal can be freed now */ > - for (pfc = &previous_funccal; *pfc != NULL; ) > - { > - if (can_free_funccal(*pfc, copyID)) > - { > - fc = *pfc; > - *pfc = fc->caller; > - free_funccal(fc, TRUE); > - did_free = TRUE; > - } > - else > - pfc = &(*pfc)->caller; > - } > - > return did_free; > } > > --- 6639,6644 ---- > *************** > *** 18842,18847 **** > --- 18883,18889 ---- > { > hash_init(&dict->dv_hashtab); > dict->dv_refcount = DO_NOT_FREE_CNT; > + dict->dv_copyID = 0; > dict_var->di_tv.vval.v_dict = dict; > dict_var->di_tv.v_type = VAR_DICT; > dict_var->di_tv.v_lock = VAR_FIXED; > *************** > *** 21294,21301 **** > current_funccal = fc->caller; > --depth; > > ! /* if the a:000 list and the a: dict are not referenced we can free the > ! * funccall_T and what's in it. */ > if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT > && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT > && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) > --- 21336,21343 ---- > current_funccal = fc->caller; > --depth; > > ! /* If the a:000 list and the l: and a: dicts are not referenced we can > ! * free the funccall_T and what's in it. */ > if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT > && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT > && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) > *************** > *** 21334,21340 **** > > /* > * Return TRUE if items in "fc" do not have "copyID". That means they are > not > ! * referenced from anywhere. > */ > static int > can_free_funccal(fc, copyID) > --- 21376,21382 ---- > > /* > * Return TRUE if items in "fc" do not have "copyID". That means they are > not > ! * referenced from anywhere that is in use. > */ > static int > can_free_funccal(fc, copyID) > > > -- > Why I like vim: >> I like VIM because, when I ask a question in this newsgroup, I get a >> one-line answer. With xemacs, I get a 1Kb lisp script with bugs in it ;-) > > /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net \\\ > /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ > \\\ download, build and distribute -- http://www.A-A-P.org /// > \\\ help me help AIDS victims -- http://ICCF-Holland.org /// >
With this patch applied MacVim still crashes for me. Note that it doesn't do that if I instead apply the second Nico's patch. These are details of from gdb: Exception Type: EXC_BAD_ACCESS (SIGBUS) Exception Codes: KERN_PROTECTION_FAILURE at 0x00000000000b7058 Crashed Thread: 0 (gdb) where #0 0x0002afa1 in dict_free (d=0x35a42f0, recurse=1) at eval.c:6772 #1 0x0002b07a in dict_unref (d=0x35a42f0) at eval.c:6752 #2 0x0002a980 in clear_tv (varp=0x3413f60) at eval.c:18600 #3 0x0002c217 in vars_clear_ext (ht=0x8589c0, free_val=1) at eval.c:19037 #4 0x0002c25e in vars_clear (ht=0x34119f0) at eval.c:19009 #5 0x0002c285 in free_funccal (fc=0x858800, free_val=1) at eval.c:21512 #6 0x0002c6ee in garbage_collect () at eval.c:6579 #7 0x00075939 in before_blocking () at getchar.c:1473 #8 0x000dd53d in mch_inchar (buf=0x35a7001 "", maxlen=95, wtime=-1, tb_change_cnt=21118) at os_unix.c:385 #9 0x00136ec5 in ui_inchar (buf=0x35a7001 "", maxlen=95, wtime=-1, tb_change_cnt=21118) at ui.c:193 #10 0x00075c3a in inchar (buf=0x35a7001 "", maxlen=287, wait_time=-1, tb_change_cnt=21118) at getchar.c:2959 #11 0x00078eda in vgetorpeek (advance=1) at getchar.c:2735 #12 0x00079441 in vgetc () at getchar.c:1552 #13 0x00079898 in safe_vgetc () at getchar.c:1757 #14 0x000c09ed in normal_cmd (oap=0xbffff350, toplevel=1) at normal.c:654 #15 0x00082d39 in main_loop (cmdwin=0, noexmode=0) at main.c:1255 #16 0x00086a87 in main (argc=54598128, argv=0x34119f0) at main.c:1002 (gdb) list 6767 6768 /* Remove the dict from the list of dicts for garbage collection. */ 6769 if (d->dv_used_prev == NULL) 6770 first_dict = d->dv_used_next; 6771 else 6772 d->dv_used_prev->dv_used_next = d->dv_used_next; 6773 if (d->dv_used_next != NULL) 6774 d->dv_used_next->dv_used_prev = d->dv_used_prev; 6775 6776 /* Lock the hashtab, we don't want it to resize while freeing items. */ (gdb) p *d $44 = { dv_refcount = -1073741822, dv_hashtab = { ht_mask = 3234897895, ht_used = 11, ht_filled = 18, ht_locked = 1, ht_error = 0, ht_array = 0x85ee00, ht_smallarray = {{ hi_hash = 1680060352, hi_key = 0x34c692d "posStack" }, { hi_hash = 881893521, hi_key = 0x347d13d "functionContainer" }, { hi_hash = 123778642, hi_key = 0x342829d "wrap" }, { hi_hash = 1110333171, hi_key = 0x3415ead "varPriority" }, { hi_hash = 122576644, hi_key = 0x34bf01d "vars" }, { hi_hash = 2430892566, hi_key = 0x34bde9d "wrapStartPos" }, { hi_hash = 1646883926, hi_key = 0x34bd31d "tmplarr" }, { hi_hash = 2145903751, hi_key = 0x34803ed "funcs" }, { hi_hash = 398141396, hi_key = 0x34a1acd "lastPopup" }, { hi_hash = 2409478612, hi_key = 0x34a295d "startColumn" }, { hi_hash = 3497526042, hi_key = 0x341fc5d "stack" }, { hi_hash = 1528633632, hi_key = 0x34a1c4d "wrappedNameTree" }, { hi_hash = 3594528268, hi_key = 0x34bfb9d "tmpls" }, { hi_hash = 3360825129, hi_key = 0x3487c5d "nameTree" }, { hi_hash = 0, hi_key = 0x0 }, { hi_hash = 2739356453, hi_key = 0x3485b6d "keyword" }} }, dv_copyID = 1862, dv_copydict = 0x3231203a, dv_lock = 0 '\0', dv_used_next = 0x34119f0, dv_used_prev = 0xb6fb0 } It looks like d->dv_refcount is invalid and d->dv_used_prev point is suspicious: (gdb) p *d->dv_used_prev $46 = { dv_refcount = 533, dv_hashtab = { ht_mask = 552, ht_used = 552, ht_filled = 552, ht_locked = 540, ht_error = 547, ht_array = 0x1f2, ht_smallarray = {{ hi_hash = 96442, hi_key = 0xba2feb00 <Address 0xba2feb00 out of bounds> }, { hi_hash = 8364, hi_key = 0x60ba28eb <Address 0x60ba28eb out of bounds> }, { hi_hash = 3942645761, hi_key = 0x161ba21 "" }, { hi_hash = 451608576, hi_key = 0x17dba "\v#####" }, { hi_hash = 3121867520, hi_key = 0x17e <Address 0x17e out of bounds> }, { hi_hash = 1387924715, hi_key = 0xeb000001 <Address 0xeb000001 out of bounds> }, { hi_hash = 22264325, hi_key = 0x4d8b0000 <Address 0x4d8b0000 out of bounds> }, { hi_hash = 608995784, hi_key = 0x24148904 <Address 0x24148904 out of bounds> }, { hi_hash = 4293319400, hi_key = 0xc84501ff <Address 0xc84501ff out of bounds> }, { hi_hash = 1003505151, hi_key = 0x850fd075 <Address 0x850fd075 out of bounds> }, { hi_hash = 4294967067, hi_key = 0xc6c87d8b <Address 0xc6c87d8b out of bounds> }, { hi_hash = 2105737223, hi_key = 0x840f0010 <Address 0x840f0010 out of bounds> }, { hi_hash = 1409, hi_key = 0x452bf889 <Address 0x452bf889 out of bounds> }, { hi_hash = 274041760, hi_key = 0x72e90289 <Address 0x72e90289 out of bounds> }, { hi_hash = 2332033029, hi_key = 0x1189144d <Address 0x1189144d out of bounds> }, { hi_hash = 2311355787, hi_key = 0x2ce9ac7d <Address 0x2ce9ac7d out of bounds> }} }, dv_copyID = -1929379838, dv_copydict = 0x4890146, dv_lock = 36 '$', dv_used_next = 0x4589ffff, dv_used_prev = 0xfc085a0 } I assume this is duble dealloc problem, but unfortunately I have no idea how to track it down. Hope it helps. Kent --~--~---------~--~----~------------~-------~--~----~ You received this message from the "vim_dev" maillist. For more information, visit http://www.vim.org/maillist.php -~----------~----~----~----~------~----~------~--~---