Skip to content

[DRAFT] Append method Regexp.SetJITStackSize #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 49 additions & 17 deletions pcre.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ import (
"unsafe"
)

var flagsReg Regexp

func init() {
flagsReg = MustCompile("^\\(\\?[a-zA-Z]+?\\)", 0)
_ = flagsReg.Study(0)
}

// Config function returns information about libpcre configuration.
// Function pass flag f to C.pcre_config() func, and convert returned
// value to string type.
Expand Down Expand Up @@ -190,11 +197,10 @@ func pcreCaptureNames(ptr *C.pcre) []CaptureName {
// Supported symbols i=CASELESS; m=MULTILINE; s=DOTALL; U=UNGREEDY; J=DUPNAMES;
// x=EXTENDED; X=EXTRA; D=DOLLAR_ENDONLY; u=UTF8|UCP;
func ParseFlags(ptr string) (string, int) {
fReg := MustCompile("^\\(\\?[a-zA-Z]+?\\)", 0)
flags := 0

for fStr := fReg.FindString(ptr, 0); fStr != ""; ptr = ptr[len(fStr):] {
fStr = fReg.FindString(ptr, 0)
for fStr := flagsReg.FindString(ptr, 0); fStr != ""; ptr = ptr[len(fStr):] {
fStr = flagsReg.FindString(ptr, 0)

if strings.Contains(fStr, "i") {
flags |= CASELESS
Expand Down Expand Up @@ -482,11 +488,38 @@ func (re *Regexp) Study(flags int) error {
return errors.New(C.GoString(err))
}

defer C.free(unsafe.Pointer(extra))
defer func() {
if extra != nil {
C.free(unsafe.Pointer(extra))
}
}()

if extra == nil {
re.extra = nil
} else {
var _extra C.struct_pcre_extra
size := unsafe.Sizeof(_extra) // Fixed size
re.extra = C.GoBytes(unsafe.Pointer(extra), C.int(size))
}

return nil
}

// SetJITStackSize used for change JIT stack size.
// The arguments are a starting size for the stack, and a maximum size to which it is
// allowed to grow. See also pcre_assign_jit_stack
func (re *Regexp) SetJITStackSize(startSize int, maxSize int) error {
if len(re.extra) == 0 {
return errors.New("can't set JIT stack size: have no extra data")
}

var _extra C.struct_pcre_extra
size := unsafe.Sizeof(_extra) // Fixed size
re.extra = C.GoBytes(unsafe.Pointer(extra), C.int(size))
stack := C.pcre_jit_stack_alloc(C.int(startSize), C.int(maxSize))
if stack == nil {
return errors.New("can't allocate JIT stack")
}
extra := (*C.pcre_extra)(unsafe.Pointer(&re.extra[0]))
C.pcre_assign_jit_stack(extra, nil, unsafe.Pointer(stack))
// We should later release stack by pcre_jit_stack_free, but do not it yet

return nil
}
Expand Down Expand Up @@ -699,31 +732,30 @@ func (m *Matcher) MatchStringWFlags(subject string, flags int) bool {
}

func checkMatch(rc int) (bool, error) {
pref := "%d, pcre_exec: "

switch {
case rc >= 0 || rc == ERROR_PARTIAL:
return true, nil
case rc == ERROR_NOMATCH:
return false, nil
case rc == ERROR_NULL:
return false, fmt.Errorf(pref+"one or more variables passed to pcre_exec == NULL", ERROR_NULL)
return false, fmt.Errorf("%d, pcre_exec: one or more variables passed to pcre_exec == NULL", int(ERROR_NULL))
case rc == ERROR_BADOPTION:
return false, fmt.Errorf(pref+"An unrecognized bit was set in the options argument", ERROR_BADOPTION)
return false, fmt.Errorf("%d, pcre_exec: An unrecognized bit was set in the options argument", int(ERROR_BADOPTION))
case rc == ERROR_BADMAGIC:
return false, fmt.Errorf(pref+"invalid option flag", ERROR_BADMAGIC)
return false, fmt.Errorf("%d, pcre_exec: invalid option flag", int(ERROR_BADMAGIC))
case rc == ERROR_UNKNOWN_OPCODE:
return false, fmt.Errorf(pref+"an unknown item was encountered in the compiled pattern", ERROR_UNKNOWN_OPCODE)
return false, fmt.Errorf("%d, pcre_exec: an unknown item was encountered in the compiled pattern", int(ERROR_UNKNOWN_OPCODE))
case rc == ERROR_NOMEMORY:
return false, fmt.Errorf(pref+"match limit", ERROR_NOMEMORY)
return false, fmt.Errorf("%d, pcre_exec: match limit", int(ERROR_NOMEMORY))
case rc == ERROR_MATCHLIMIT:
return false, fmt.Errorf(pref+"backtracking (match) limit was reached", ERROR_MATCHLIMIT)
return false, fmt.Errorf("%d, pcre_exec: backtracking (match) limit was reached", int(ERROR_MATCHLIMIT))
case rc == ERROR_BADUTF8:
return false, fmt.Errorf(pref+"string that contains an invalid UTF-8 byte sequence was passed as a subject", ERROR_BADUTF8)
return false, fmt.Errorf("%d, pcre_exec: string that contains an invalid UTF-8 byte sequence was passed as a subject", int(ERROR_BADUTF8))
case rc == ERROR_RECURSIONLIMIT:
return false, fmt.Errorf(pref+"recursion limit", ERROR_RECURSIONLIMIT)
return false, fmt.Errorf("%d, pcre_exec: recursion limit", int(ERROR_RECURSIONLIMIT))
case rc == ERROR_JIT_STACKLIMIT:
return false, fmt.Errorf(pref+"error JIT stack limit", ERROR_JIT_STACKLIMIT)
return false, fmt.Errorf("%d, pcre_exec: error JIT stack limit", int(ERROR_JIT_STACKLIMIT))
case rc == ERROR_INTERNAL:
panic("pcre_exec: INTERNAL ERROR")
case rc == ERROR_BADCOUNT:
Expand Down
13 changes: 13 additions & 0 deletions pcre_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,19 @@ func BenchmarkExecWithoutStudy(b *testing.B) {
}
}

func TestJITStackSize(t *testing.T) {
re := MustCompileJIT(`aaa|bb|cc`, 0, STUDY_JIT_COMPILE)
err := re.SetJITStackSize(64*1024, 1024*1024)
if err != nil {
t.Errorf("Error call of SetJITStackSize: %s", err)
}

m := re.NewMatcherString(`bb`, 0)
if !m.Matches {
t.Error("The match should be matched")
}
}

func TestPartial(t *testing.T) {
re := MustCompile(`^abc`, 0)

Expand Down