Bram Moolenaar <[email protected]> wrote:

> Christian Brabandt wrote:
>
>> > > On Mo, 13 Jun 2016, Christian Brabandt wrote:
>> > >
>> > > > Something between 7.4.1924 and 7.4.1926 broke the daily binary built:
>> > > >
>> > > > ..\gvim -u dos.vim -U NONE --noplugin --not-a-term "+set ff=dos|f 
>> > > > dostmp\test58.in|wq" test58.in
>> > > >     move test58.in test58.in.bak
>> > > >         1 file(s) moved.
>> > > >     copy dostmp\test58.in test58.in
>> > > >         1 file(s) copied.
>> > > >     copy test58.ok test.ok
>> > > >         1 file(s) copied.
>> > > >     ..\gvim -u dos.vim -U NONE --noplugin --not-a-term -s dotest.in 
>> > > > test58.in
>> > > > NMAKE : fatal error U1077: '..\gvim.EXE' : return code '0xc0000005'
>> > > > Stop.
>> > > >
>> > > > I rebuild that commit 3 times and it always breaks at that step for the
>> > > > 32bit build. Does anybody know, what that means?
>> > >
>> > > I think the crash happens in the quit command of the test58.in file
>> > > (function TestOne(), line 28)
>> > >
>> > > ,----
>> > > |   " list all valid words
>> > > |   spelldump
>> > > |   %yank
>> > > |   quit
>> > > |   $put
>> > > `----
>> > >
>> > >
>> > > I stepped into it using a debugger, and I think the stacktrace shows,
>> > > that the crash happens in:
>> > > win_free(), when calling perl_win_free()
>> > > Stacktrace (sorry, only screenshot):
>> > > http://i.imgur.com/fzmHS9r.png
>> > >
>> > > Sorry, don't know how to further debug this.
>> > >
>> > > If someone wants knows how to debug it,
>> > > you can download a broken Gvim here:
>> > > https://github.com/chrisbra/vim-win32-installer/releases/tag/v7.4.1934_test
>> > > (only happens with the x86 versions).
>> >
>> > Hmm, since the test does not use Perl at all, w_perl_private should not
>> > have been set.  If it's not NULL then perhaps it was corrupted?
>> > Perhaps if you step into perl_win_free() you can see what the value is?
>> >
>> > You could try commenting out the call to perl_win_free() and see if it
>> > finishes properly or then crashe somewhere else (e.g., when using other
>> > pointers next to w_perl_private, e.g. w_python_ref or w_mzscheme_ref).
>> >
>> > If you can set a watch point in this debugger, watching w_perl_private
>> > might also reveal something.
>>
>> It happens in mark.c:
>>
>>    174     /* If jumplist is full: remove oldest entry */
>>    175     if (++curwin->w_jumplistlen > JUMPLISTSIZE)
>>    176     {
>>    177         curwin->w_jumplistlen = JUMPLISTSIZE;
>>    178         vim_free(curwin->w_jumplist[0].fname);
>>    179         for (i = 1; i < JUMPLISTSIZE; ++i)
>>    180             curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
>>    181     }
>>    182     curwin->w_jumplistidx = curwin->w_jumplistlen;
>>    183     fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
>>    184
>>    185     fm->fmark.mark = curwin->w_pcmark;
>>    186     fm->fmark.fnum = curbuf->b_fnum;
>>    187     fm->fname = NULL;
>>    188 # ifdef FEAT_VIMINFO
>>    189     fm->time_set = vim_time();
>>    190 # endif
>>    191 #endif
>>
>> somehow, w_jumplistlen isn't incremented, then fm access 
>> curwin->w_jumplist[-1]
>> this goes on, until w_jumplistlen gets overwritten to a really high value 
>> which
>> later causes curwin->w_perl_private to be set to 1.
>>
>> I don't understand why this happens, I tried adding some check statements, 
>> so that
>> curwin->w_jumplistlen is always positive, but this didn't help for some 
>> reason.
>>
>> Don't know how to further help here.
>
> Have you tried after patch 7.4.1939?  It fixes a problem where
> w_jumplistlen was overwritten with a line number.  Valgrind doesn't
> catch this because it's still within a struct.

Yes, I think that patch 7.4.1939 should fix this.

Below is a simplified version of the memory corruption, unfortunately
not detected by valgrind, asan (address sanitizer), ubsan (undefined
sanitizer) or compiler warnings:

$ cat corrupt.cpp
#include <stdio.h>

struct s_t {
  int a[2];
  int b;
};

int main()
{
  s_t s;

  s.a[0] = 0;
  s.a[1] = 0;
  s.b = 0;

  int *p = &s.a[2]; // Taking end address of the array is OK.
  p[0] = 1;        // ... but this corrupts memory, typically writing into b.

  // Print to make sure compiler does not optimize code out.
  for (int i = 0; i < 2; ++i) {
    printf("s.a[%d]=%d\n", i, s.a[i]);
  }
  printf("s.b=%d\n", s.b);
}

# Bug is not detected by asan...
$ g++ -Wall -fsanitize=address corrupt.cpp
$ ./a.out
s.a[0]=0
s.a[1]=0
s.b=1

# Bug is not detected by ubsan either...
$ g++ -Wall -fsanitize=undefined corrupt.cpp
$ ./a.out
s.a[0]=0
s.a[1]=0
s.b=1

# Bug is not detected by valgrind either...
$ g++ -Wall corrupt.cpp
$ valgrind ./a.out
==16570== Memcheck, a memory error detector
==16570== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==16570== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==16570== Command: ./a.out
==16570==
s.a[0]=0
s.a[1]=0
s.b=1
==16570==
==16570== HEAP SUMMARY:
==16570==     in use at exit: 0 bytes in 0 blocks
==16570==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==16570==
==16570== All heap blocks were freed -- no leaks are possible
==16570==
==16570== For counts of detected and suppressed errors, rerun with: -v
==16570== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)


It would be good if asan knew that p points into array s.a[..]
and so it's only allowed to access addresses between
&s.a[0] (included) .. s.a[2] (excluded) when dereferencing p.
I've asked the author of asan whether this is doable in asan.

Regards
Dominique

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui