view runtime/indent/cobol.vim @ 33776:9503dc55b5ed v9.0.2108

patch 9.0.2108: [security]: overflow with count for :s command Commit: https://github.com/vim/vim/commit/ac63787734fda2e294e477af52b3bd601517fa78 Author: Christian Brabandt <cb@256bit.org> Date: Tue Nov 14 20:45:48 2023 +0100 patch 9.0.2108: [security]: overflow with count for :s command Problem: [security]: overflow with count for :s command Solution: Abort the :s command if the count is too large If the count after the :s command is larger than what fits into a (signed) long variable, abort with e_value_too_large. Adds a test with INT_MAX as count and verify it correctly fails. It seems the return value on Windows using mingw compiler wraps around, so the initial test using :s/./b/9999999999999999999999999990 doesn't fail there, since the count is wrapping around several times and finally is no longer larger than 2147483647. So let's just use 2147483647 in the test, which hopefully will always cause a failure Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 16 Nov 2023 22:15:10 +0100
parents 9c221ad9634a
children
line wrap: on
line source

" Vim indent file
" Language:	cobol
" Maintainer: Ankit Jain <ajatkj@yahoo.co.in>
"     (formerly Tim Pope <vimNOSPAM@tpope.info>)
" $Id: cobol.vim,v 1.1 2007/05/05 18:08:19 vimboss Exp $
" Last Update:	By Ankit Jain on 22.03.2019
" Ankit Jain      22.03.2019     Changes & fixes:
"                                Allow chars in 1st 6 columns
"                                #C22032019
" Ankit Jain      24.09.2021     add b:undo_indent (request by tpope)

if exists("b:did_indent")
    finish
endif
let b:did_indent = 1

setlocal expandtab
setlocal indentexpr=GetCobolIndent(v:lnum)
setlocal indentkeys&
setlocal indentkeys+=0<*>,0/,0$,0=01,=~division,=~section,0=~end,0=~then,0=~else,0=~when,*<Return>,.

let b:undo_indent = "setlocal expandtab< indentexpr< indentkeys<"

" Only define the function once.
if exists("*GetCobolIndent")
    finish
endif

let s:skip = 'getline(".") =~ "^.\\{6\\}[*/$-]\\|\"[^\"]*\""'

function! s:prevgood(lnum)
    " Find a non-blank line above the current line.
    " Skip over comments.
    let lnum = a:lnum
    while lnum > 0
        let lnum = prevnonblank(lnum - 1)
        let line = getline(lnum)
        if line !~? '^\s*[*/$-]' && line !~? '^.\{6\}[*/$CD-]'
            break
        endif
    endwhile
    return lnum
endfunction

function! s:stripped(lnum)
    return substitute(strpart(getline(a:lnum),0,72),'^\s*','','')
endfunction

function! s:optionalblock(lnum,ind,blocks,clauses)
    let ind = a:ind
    let clauses = '\c\<\%(\<NOT\s\+\)\@<!\%(NOT\s\+\)\=\%('.a:clauses.'\)'
    let begin = '\c-\@<!\<\%('.a:blocks.'\)\>'
    let beginfull = begin.'\ze.*\%(\n\%(\s*\%([*/$-].*\)\=\n\)*\)\=\s*\%('.clauses.'\)'
    let end   = '\c\<end-\%('.a:blocks.'\)\>\|\%(\.\%( \|$\)\)\@='
    let cline = s:stripped(a:lnum)
    let line  = s:stripped(s:prevgood(a:lnum))
    if cline =~? clauses "&& line !~? '^search\>'
        call cursor(a:lnum,1)
        let lastclause = searchpair(beginfull,clauses,end,'bWr',s:skip)
        if getline(lastclause) =~? clauses && s:stripped(lastclause) !~? '^'.begin
            let ind = indent(lastclause)
        elseif lastclause > 0
            let ind = indent(lastclause) + shiftwidth()
            "let ind = ind + shiftwidth()
        endif
    elseif line =~? clauses && cline !~? end
        let ind = ind + shiftwidth()
    endif
    return ind
endfunction

function! GetCobolIndent(lnum) abort
    let minshft = 6
    let ashft = minshft + 1
    let bshft = ashft + 4
    " (Obsolete) numbered lines
    " #C22032019: Columns 1-6 could have alphabets as well as numbers
    "if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)'
    if getline(a:lnum) =~? '^\s*[a-zA-Z0-9]\{6\}\%($\|[ */$CD-]\)'
        return 0
    endif
    let cline = s:stripped(a:lnum)
    " Comments, etc. must start in the 7th column
    if cline =~? '^[*/$-]'
        return minshft
    elseif cline =~# '^[CD]' && indent(a:lnum) == minshft
        return minshft
    endif
    " Divisions, sections, and file descriptions start in area A
    if cline =~? '\<\(DIVISION\|SECTION\)\%($\|\.\)' || cline =~? '^[FS]D\>'
        return ashft
    endif
    " Fields
    if cline =~? '^0*\(1\|77\)\>'
        return ashft
    endif
    if cline =~? '^\d\+\>'
        let cnum = matchstr(cline,'^\d\+\>')
        let default = 0
        let step = -1
        while step < 2
        let lnum = a:lnum
        while lnum > 0 && lnum < line('$') && lnum > a:lnum - 500 && lnum < a:lnum + 500
            let lnum = step > 0 ? nextnonblank(lnum + step) : prevnonblank(lnum + step)
            let line = getline(lnum)
            let lindent = indent(lnum)
            if line =~? '^\s*\d\+\>'
                let num = matchstr(line,'^\s*\zs\d\+\>')
                if 0+cnum == num
                    return lindent
                elseif 0+cnum > num && default < lindent + shiftwidth()
                    let default = lindent + shiftwidth()
                endif
            elseif lindent < bshft && lindent >= ashft
                break
            endif
        endwhile
        let step = step + 2
        endwhile
        return default ? default : bshft
    endif
    let lnum = s:prevgood(a:lnum)
    " Hit the start of the file, use "zero" indent.
    if lnum == 0
        return ashft
    endif
    " Initial spaces are ignored
    let line = s:stripped(lnum)
    let ind = indent(lnum)
    " Paragraphs.  There may be some false positives.
    if cline =~? '^\(\a[A-Z0-9-]*[A-Z0-9]\|\d[A-Z0-9-]*\a\)\.' "\s*$'
        if cline !~? '^EXIT\s*\.' && line =~? '\.\s*$'
            return ashft
        endif
    endif
    " Paragraphs in the identification division.
    "if cline =~? '^\(PROGRAM-ID\|AUTHOR\|INSTALLATION\|' .
                "\ 'DATE-WRITTEN\|DATE-COMPILED\|SECURITY\)\>'
        "return ashft
    "endif
    if line =~? '\.$'
        " XXX
        return bshft
    endif
    if line =~? '^PERFORM\>'
        let perfline = substitute(line, '\c^PERFORM\s*', "", "")
        if perfline =~? '^\%(\k\+\s\+TIMES\)\=\s*$'
            let ind = ind + shiftwidth()
        elseif perfline =~? '^\%(WITH\s\+TEST\|VARYING\|UNTIL\)\>.*[^.]$'
            let ind = ind + shiftwidth()
        endif
    endif
    if line =~? '^\%(IF\|THEN\|ELSE\|READ\|EVALUATE\|SEARCH\|SELECT\)\>'
        let ind = ind + shiftwidth()
    endif
    let ind = s:optionalblock(a:lnum,ind,'ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT','ON\s\+SIZE\s\+ERROR')
    let ind = s:optionalblock(a:lnum,ind,'STRING\|UNSTRING\|ACCEPT\|DISPLAY\|CALL','ON\s\+OVERFLOW\|ON\s\+EXCEPTION')
    if cline !~? '^AT\s\+END\>' || line !~? '^SEARCH\>'
        let ind = s:optionalblock(a:lnum,ind,'DELETE\|REWRITE\|START\|WRITE\|READ','INVALID\s\+KEY\|AT\s\+END\|NO\s\+DATA\|AT\s\+END-OF-PAGE')
    endif
    if cline =~? '^WHEN\>'
        call cursor(a:lnum,1)
        " We also search for READ so that contained AT ENDs are skipped
        let lastclause = searchpair('\c-\@<!\<\%(SEARCH\|EVALUATE\|READ\)\>','\c\<\%(WHEN\|AT\s\+END\)\>','\c\<END-\%(SEARCH\|EVALUATE\|READ\)\>','bW',s:skip)
        let g:foo = s:stripped(lastclause)
        if s:stripped(lastclause) =~? '\c\<\%(WHEN\|AT\s\+END\)\>'
            "&& s:stripped(lastclause) !~? '^\%(SEARCH\|EVALUATE\|READ\)\>'
            let ind = indent(lastclause)
        elseif lastclause > 0
            let ind = indent(lastclause) + shiftwidth()
        endif
    elseif line =~? '^WHEN\>'
        let ind = ind + shiftwidth()
    endif
    "I'm not sure why I had this
    "if line =~? '^ELSE\>-\@!' && line !~? '\.$'
        "let ind = indent(s:prevgood(lnum))
    "endif
    if cline =~? '^\(END\)\>-\@!'
        " On lines with just END, 'guess' a simple shift left
        let ind = ind - shiftwidth()
    elseif cline =~? '^\(END-IF\|THEN\|ELSE\)\>-\@!'
        call cursor(a:lnum,indent(a:lnum))
        let match = searchpair('\c-\@<!\<IF\>','\c-\@<!\%(THEN\|ELSE\)\>','\c-\@<!\<END-IF\>\zs','bnW',s:skip)
        if match > 0
            let ind = indent(match)
        endif
    elseif cline =~? '^END-[A-Z]'
        let beginword = matchstr(cline,'\c\<END-\zs[A-Z0-9-]\+')
        let endword = 'END-'.beginword
        let first = 0
        let suffix = '.*\%(\n\%(\%(\s*\|.\{6\}\)[*/].*\n\)*\)\=\s*'
        if beginword =~? '^\%(ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT\)$'
            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+SIZE\s\+ERROR'
            let g:beginword = beginword
            let first = 1
        elseif beginword =~? '^\%(STRING\|UNSTRING\)$'
            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+OVERFLOW'
            let first = 1
        elseif beginword =~? '^\%(ACCEPT\|DISPLAY\)$'
            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+EXCEPTION'
            let first = 1
        elseif beginword ==? 'CALL'
            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+\%(EXCEPTION\|OVERFLOW\)'
            let first = 1
        elseif beginword =~? '^\%(DELETE\|REWRITE\|START\|READ\|WRITE\)$'
            let first = 1
            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=\(INVALID\s\+KEY'
            if beginword =~? '^READ'
                let first = 0
                let beginword = beginword . '\|AT\s\+END\|NO\s\+DATA'
            elseif beginword =~? '^WRITE'
                let beginword = beginword . '\|AT\s\+END-OF-PAGE'
            endif
            let beginword = beginword . '\)'
        endif
        call cursor(a:lnum,indent(a:lnum))
        let match = searchpair('\c-\@<!\<'.beginword.'\>','','\c\<'.endword.'\>\zs','bnW'.(first? 'r' : ''),s:skip)
        if match > 0
            let ind = indent(match)
        elseif cline =~? '^\(END-\(READ\|EVALUATE\|SEARCH\|PERFORM\)\)\>'
            let ind = ind - shiftwidth()
        endif
    endif
    return ind < bshft ? bshft : ind
endfunction