Golang分段错误(核心已转储)

5
我是一个新手,刚开始学习golang和编程。
我写了一个小程序,用于将与正则表达式匹配的文件从一个目录移动到另一个目录。
这个程序在Ubuntu 16.04和Centos 6.8(Final)上成功运行。
但在某个Centos机器上(我不知道确切的版本号,只知道它是6.?且低于6.8),我遇到了以下错误:
"Segmentation fault (core dumped)"
我查了一下,发现这个错误出现时,操作系统不允许我访问内存。
请问有人能告诉我代码哪里出错了吗?如果您看到了任何不良实践,请指出。
package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "regexp"
    "strings"
)

func main() {

    batch := flag.Int("batch", 0, "the amount of files to be processed")
    pattern := flag.String("pattern", "", "string pattern to be matched")
    dir := flag.Int("dir", 0, "key from strings.Split(pattern, '')")
    confirm := flag.String("move", "no", "flags if program should move files")

    flag.Parse()

    d, err := os.Open(".")
    if err != nil {
        log.Fatal("Could not open directory. ", err)
    }

    files, err := d.Readdir(*batch)
    if err != nil {
        log.Fatal("Could not read directory. ", err)
    }

    for _, file := range files {
        fname := file.Name()
        match, err := regexp.Match(*pattern, []byte(fname))
        if err != nil {
            log.Fatal(err)
        }
        if match == true {

            s := strings.Split(fname, "_")
            dest := s[*dir]

            switch *confirm {
            case "no":
                fmt.Printf(" %s  matches  %s\n Dir name =  %s\n -----------------------\n", fname, *pattern, dest)

            case "yes":
                //all directories are expected to be a number.
                //terminate execution if directory doesn't match regex
                if match, err := regexp.Match("[0-9]", []byte(dest)); match == false {
                    log.Fatalf("Expected directory name does not match prepared directory.\n Expected dir name must be a number (regex [0-9]) | Current dir name is: %s\n", dest)
                    if err != nil {
                        log.Fatal(err)
                    }
                }

                //check if direcotry exists. create it if it doesn't
                if _, err := os.Stat(dest); os.IsNotExist(err) {
                    err = os.Mkdir(dest, 0777)
                    if err != nil {
                        log.Fatal("Could not create directory. ", err)
                    }
                }
                err = os.Rename(fname, fmt.Sprintf("%s/%s", dest, fname))
                if err != nil {
                    log.Fatal("Could not move file. ", err)
                }
                fmt.Printf("Moved %s to %s\n", fname, dest)
            }
        }
    }
    fmt.Println("Exit")
}

1
曾经遇到过一个有点类似的情况,但从未找出原因。一个假设是交叉编译是根本原因(因为我在 MacOS 上构建)。 - Michael Hausenblas
1
请使用选项-ldflags“-w”编译程序(例如go build -ldflags“-w” prog.go),并尝试在gdb中进行调试(gdb prog)并运行它(run)。如果出现问题,请在那时显示回溯信息(bt)。 - lofcek
1
我在有问题的机器上构建了程序,现在它可以正常工作了。 - user3017869
1个回答

2

我的第一个猜测是您超出了“s”数组的边界:

dest := s[*dir]

我增加了一些安全检查(请见[Added]):
package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "regexp"
    "strings"
)

func main() {
    batch := flag.Int("batch", 0, "the amount of files to be processed")
    pattern := flag.String("pattern", "", "string pattern to be matched")
    dir := flag.Int("dir", 0, "key from strings.Split(pattern, '')")
    confirm := flag.String("move", "no", "flags if program should move files")

    flag.Parse()

    d, err := os.Open(".")
    if err != nil {
        log.Fatal("Could not open directory. ", err)
    }
    defer d.Close() // [Added] probably not needed if a directory but doesn't hurt

    files, err := d.Readdir(*batch)
    if err != nil {
        log.Fatal("Could not read directory. ", err)
    }

    for _, file := range files {
        fname := file.Name()
        match, err := regexp.Match(*pattern, []byte(fname))
        if err != nil {
            log.Fatal(err)
        }
        if match == true {
            s := strings.Split(fname, "_")

            // [Added] Sanity check *dir index before using
            if *dir >= len(s) {
                log.Fatalf("dir is out of range: dir=%d len(s)=%d\n", *dir, len(s))
            }

            dest := s[*dir]

            switch *confirm {
            case "no":
                fmt.Printf(" %s  matches  %s\n Dir name =  %s\n -----------------------\n", fname, *pattern, dest)

            case "yes":
                //all directories are expected to be a number.
                //terminate execution if directory doesn't match regex
                if match, err := regexp.Match("[0-9]", []byte(dest)); match == false {
                    log.Fatalf("Expected directory name does not match prepared directory.\n Expected dir name must be a number (regex [0-9]) | Current dir name is: %s\n", dest)
                    if err != nil {
                        log.Fatal(err)
                    }
                }

                //check if direcotry exists. create it if it doesn't
                if _, err := os.Stat(dest); os.IsNotExist(err) {
                    err = os.Mkdir(dest, 0777)
                    if err != nil {
                        log.Fatal("Could not create directory. ", err)
                    }
                }
                err = os.Rename(fname, fmt.Sprintf("%s/%s", dest, fname))
                if err != nil {
                    log.Fatal("Could not move file. ", err)
                }
                fmt.Printf("Moved %s to %s\n", fname, dest)

                // [Added]: Make sure to handle non 'yes/no' answers
            default:
                log.Fatalf("confirm is invalid '%s'\n", *confirm)
            }
        }
    }
    fmt.Println("Exit")
}

我不确定您输入到程序中的内容,但我没有看到其他任何可能导致分段错误的因素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接