gitlab.com/cznic/ccir@v1.0.0/all_test.go (about)

     1  // Copyright 2017 The CCIR Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ccir // import "modernc.org/ccir"
     6  
     7  import (
     8  	"bytes"
     9  	"compress/gzip"
    10  	"encoding/gob"
    11  	"encoding/hex"
    12  	"flag"
    13  	"fmt"
    14  	"go/scanner"
    15  	"go/token"
    16  	"io/ioutil"
    17  	"os"
    18  	"path"
    19  	"path/filepath"
    20  	"regexp"
    21  	"runtime"
    22  	"runtime/debug"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"modernc.org/cc"
    28  	"modernc.org/internal/buffer"
    29  	"modernc.org/ir"
    30  	"modernc.org/strutil"
    31  	"modernc.org/virtual"
    32  	"modernc.org/xc"
    33  )
    34  
    35  func caller(s string, va ...interface{}) {
    36  	if s == "" {
    37  		s = strings.Repeat("%v ", len(va))
    38  	}
    39  	_, fn, fl, _ := runtime.Caller(2)
    40  	fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
    41  	fmt.Fprintf(os.Stderr, s, va...)
    42  	fmt.Fprintln(os.Stderr)
    43  	_, fn, fl, _ = runtime.Caller(1)
    44  	fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
    45  	fmt.Fprintln(os.Stderr)
    46  	os.Stderr.Sync()
    47  }
    48  
    49  func dbg(s string, va ...interface{}) {
    50  	if s == "" {
    51  		s = strings.Repeat("%v ", len(va))
    52  	}
    53  	_, fn, fl, _ := runtime.Caller(1)
    54  	fmt.Fprintf(os.Stderr, "# dbg %s:%d ", path.Base(fn), fl)
    55  	fmt.Fprintf(os.Stderr, s, va...)
    56  	fmt.Fprintln(os.Stderr)
    57  	os.Stderr.Sync()
    58  }
    59  
    60  func use(...interface{}) {}
    61  
    62  func init() {
    63  	use(caller, dbg, TODO) //TODOOK
    64  	isTesting = true
    65  	flag.BoolVar(&Testing, "testing", false, "")
    66  	flag.BoolVar(&ir.Testing, "irTesting", false, "")
    67  	flag.BoolVar(&virtual.Testing, "virtualTesting", false, "")
    68  }
    69  
    70  // ============================================================================
    71  
    72  var (
    73  	cpp      = flag.Bool("cpp", false, "")
    74  	errLimit = flag.Int("errlimit", 10, "")
    75  	filter   = flag.String("re", "", "")
    76  	ndebug   = flag.Bool("ndebug", false, "")
    77  	noexec   = flag.Bool("noexec", false, "")
    78  	oLog     = flag.Bool("log", false, "")
    79  	trace    = flag.Bool("trc", false, "")
    80  	yydebug  = flag.Int("yydebug", 0, "")
    81  )
    82  
    83  func errStr(err error) string {
    84  	switch x := err.(type) {
    85  	case scanner.ErrorList:
    86  		if len(x) != 1 {
    87  			x.RemoveMultiples()
    88  		}
    89  		var b bytes.Buffer
    90  		for i, v := range x {
    91  			if i != 0 {
    92  				b.WriteByte('\n')
    93  			}
    94  			b.WriteString(v.Error())
    95  			if i == 9 {
    96  				fmt.Fprintf(&b, "\n\t... and %v more errors", len(x)-10)
    97  				break
    98  			}
    99  		}
   100  		return b.String()
   101  	default:
   102  		return err.Error()
   103  	}
   104  }
   105  
   106  func parse(src []string, opts ...cc.Opt) (_ *cc.TranslationUnit, err error) {
   107  	defer func() {
   108  		if e := recover(); e != nil && err == nil {
   109  			err = fmt.Errorf("cc.Parse: PANIC: %v\n%s", e, debug.Stack())
   110  		}
   111  	}()
   112  
   113  	model, err := NewModel()
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	ast, err := cc.Parse(fmt.Sprintf(`
   119  #define __arch__ %s
   120  #define __os__ %s
   121  #include <builtin.h>
   122  
   123  #define NO_TRAMPOLINES 1
   124  `, runtime.GOARCH, runtime.GOOS),
   125  		src,
   126  		model,
   127  		opts...,
   128  	)
   129  	if err != nil {
   130  		return nil, fmt.Errorf("cc.Parse: %v", errStr(err))
   131  	}
   132  
   133  	return ast, nil
   134  }
   135  
   136  func expect1(wd, match string, hook func(string, string) []string, opts ...cc.Opt) (log buffer.Bytes, exitStatus int, err error) {
   137  	var lpos token.Position
   138  	if *cpp {
   139  		opts = append(opts, cc.Cpp(func(toks []xc.Token) {
   140  			if len(toks) != 0 {
   141  				p := toks[0].Position()
   142  				if p.Filename != lpos.Filename {
   143  					fmt.Fprintf(&log, "# %d %q\n", p.Line, p.Filename)
   144  				}
   145  				lpos = p
   146  			}
   147  			for _, v := range toks {
   148  				log.WriteString(cc.TokSrc(v))
   149  			}
   150  			log.WriteByte('\n')
   151  		}))
   152  	}
   153  	if n := *yydebug; n != 0 {
   154  		opts = append(opts, cc.YyDebug(n))
   155  	}
   156  	ast, err := parse([]string{CRT0Path, match}, opts...)
   157  	if err != nil {
   158  		return log, -1, err
   159  	}
   160  
   161  	objs, err := New(ast)
   162  	if err != nil {
   163  		return log, -1, fmt.Errorf("New: %v", err)
   164  	}
   165  
   166  	fmt.Fprintf(&log, "# ccir.New\n")
   167  	for i, v := range objs {
   168  		switch x := v.(type) {
   169  		case *ir.DataDefinition:
   170  			fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
   171  		case *ir.FunctionDefinition:
   172  			fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
   173  			for i, v := range x.Body {
   174  				fmt.Fprintf(&log, "%#05x\t%v\n", i, v)
   175  			}
   176  		default:
   177  			return log, -1, fmt.Errorf("[%v] %T %v", i, x, x)
   178  		}
   179  	}
   180  	for i, v := range objs {
   181  		if err := v.Verify(); err != nil {
   182  			switch x := v.(type) {
   183  			case *ir.FunctionDefinition:
   184  				fmt.Fprintf(&log, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
   185  				for i, v := range x.Body {
   186  					fmt.Fprintf(&log, "%#05x\t%v\n", i, v)
   187  				}
   188  				return log, -1, fmt.Errorf("# [%v, err]: Verify (A): %v", i, err)
   189  			default:
   190  				return log, -1, fmt.Errorf("[%v, err]: %T %v: %v", i, x, x, err)
   191  			}
   192  		}
   193  	}
   194  
   195  	if objs, err = ir.LinkMain(objs); err != nil {
   196  		return log, -1, fmt.Errorf("ir.LinkMain: %v", err)
   197  	}
   198  
   199  	fmt.Fprintf(&log, "# ir.LinkMain\n")
   200  	for i, v := range objs {
   201  		switch x := v.(type) {
   202  		case *ir.DataDefinition:
   203  			fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
   204  		case *ir.FunctionDefinition:
   205  			fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
   206  			for i, v := range x.Body {
   207  				fmt.Fprintf(&log, "%#05x\t%v\n", i, v)
   208  			}
   209  		default:
   210  			return log, -1, fmt.Errorf("[%v]: %T %v", i, x, x)
   211  		}
   212  	}
   213  	for i, v := range objs {
   214  		if err := v.Verify(); err != nil {
   215  			return log, -1, fmt.Errorf("# [%v, err]: Verify (B): %v", i, err)
   216  		}
   217  	}
   218  
   219  	bin, err := virtual.LoadMain(objs)
   220  	if err != nil {
   221  		return log, -1, fmt.Errorf("virtual.LoadMain: %v", err)
   222  	}
   223  
   224  	var gz bytes.Buffer
   225  	zw := gzip.NewWriter(&gz)
   226  	enc := gob.NewEncoder(zw)
   227  	if err := enc.Encode(bin); err != nil {
   228  		return log, -1, fmt.Errorf("gob encode: %v", err)
   229  	}
   230  
   231  	if err := zw.Close(); err != nil {
   232  		return log, -1, fmt.Errorf("gzip close: %v", err)
   233  	}
   234  
   235  	s := virtual.DumpCodeStr(bin.Code, 0, bin.Functions, bin.Lines)
   236  	fmt.Fprintf(&log, "%s: virtual.LoadMain: code %#05x, text %#05x, data %#05x, bss %#05x, pc2func %v, pc2line %v, gz %v\n%s\n",
   237  		match, len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(gz.Bytes()), s.Bytes(),
   238  	)
   239  	s.Close()
   240  	if len(bin.Text) != 0 {
   241  		fmt.Fprintf(&log, "Text segment\n%s\n", hex.Dump(bin.Text))
   242  	}
   243  	if len(bin.Data) != 0 {
   244  		fmt.Fprintf(&log, "Data segment\n%s\n", hex.Dump(bin.Data))
   245  	}
   246  	if len(bin.TSRelative) != 0 {
   247  		fmt.Fprintf(&log, "TS relative bitvector\n%s\n", hex.Dump(bin.TSRelative))
   248  	}
   249  	if len(bin.DSRelative) != 0 {
   250  		fmt.Fprintf(&log, "DS relative bitvector\n%s\n", hex.Dump(bin.DSRelative))
   251  	}
   252  
   253  	if *noexec {
   254  		return log, 0, nil
   255  	}
   256  
   257  	var stdin bytes.Buffer
   258  	var stdout, stderr buffer.Bytes
   259  
   260  	defer func() {
   261  		stdout.Close()
   262  		stderr.Close()
   263  	}()
   264  
   265  	if err := func() (err error) {
   266  		defer func() {
   267  			if e := recover(); e != nil && err == nil {
   268  				err = fmt.Errorf("virtual.Exec: PANIC: %v\n%s", e, debug.Stack())
   269  			}
   270  		}()
   271  
   272  		vwd, err := ioutil.TempDir("", "ccir-test-")
   273  		if err != nil {
   274  			return err
   275  		}
   276  
   277  		if err := os.Chdir(vwd); err != nil {
   278  			return err
   279  		}
   280  
   281  		defer func() {
   282  			os.Chdir(wd)
   283  			os.RemoveAll(vwd)
   284  		}()
   285  
   286  		args := hook(vwd, match)
   287  		if exitStatus, err = virtual.Exec(bin, args, &stdin, &stdout, &stderr, 1<<20, 1<<20, wd); exitStatus != 0 || err != nil {
   288  			if b := stdout.Bytes(); b != nil {
   289  				fmt.Fprintf(&log, "stdout:\n%s\n", b)
   290  			}
   291  			if b := stderr.Bytes(); b != nil {
   292  				fmt.Fprintf(&log, "stderr:\n%s\n", b)
   293  			}
   294  			return fmt.Errorf("virtual.Exec: exit status %v, err %v", exitStatus, err)
   295  		}
   296  
   297  		return nil
   298  	}(); err != nil {
   299  		return log, exitStatus, err
   300  	}
   301  
   302  	if b := stdout.Bytes(); b != nil {
   303  		fmt.Fprintf(&log, "stdout:\n%s\n", b)
   304  	}
   305  	if b := stderr.Bytes(); b != nil {
   306  		fmt.Fprintf(&log, "stderr:\n%s\n", b)
   307  	}
   308  
   309  	expect := match[:len(match)-len(filepath.Ext(match))] + ".expect"
   310  	if _, err := os.Stat(expect); err != nil {
   311  		if !os.IsNotExist(err) {
   312  			return log, 0, err
   313  		}
   314  
   315  		return log, 0, nil
   316  	}
   317  
   318  	buf, err := ioutil.ReadFile(expect)
   319  	if err != nil {
   320  		return log, 0, err
   321  	}
   322  
   323  	if g, e := stdout.Bytes(), buf; !bytes.Equal(g, e) {
   324  		return log, 0, fmt.Errorf("==== %v\n==== got\n%s==== exp\n%s", match, g, e)
   325  	}
   326  	return log, 0, nil
   327  }
   328  
   329  func expect(t *testing.T, dir string, skip func(string) bool, hook func(string, string) []string, opts ...cc.Opt) {
   330  	wd, err := os.Getwd()
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  
   335  	matches, err := filepath.Glob(filepath.Join(dir, "*.c"))
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  
   340  	seq := 0
   341  	okSeq := 0
   342  	for _, match := range matches {
   343  		if skip(match) {
   344  			continue
   345  		}
   346  
   347  		if *trace {
   348  			fmt.Println(match)
   349  		}
   350  		seq++
   351  		doLog := *oLog
   352  		log, exitStatus, err := expect1(wd, match, hook, opts...)
   353  		switch {
   354  		case exitStatus <= 0 && err == nil:
   355  			okSeq++
   356  		default:
   357  			//dbg("%v\n%v", match, err)
   358  			if seq-okSeq == 1 {
   359  				t.Logf("%s: FAIL\n%s\n%s", match, errStr(err), log.Bytes())
   360  				doLog = false
   361  			}
   362  		}
   363  		if doLog {
   364  			t.Logf("%s:\n%s", match, log.Bytes())
   365  		}
   366  		log.Close()
   367  	}
   368  	t.Logf("%v/%v ok", okSeq, seq)
   369  	if okSeq != seq {
   370  		t.Errorf("failures: %v", seq-okSeq)
   371  	}
   372  }
   373  
   374  func TestTCC(t *testing.T) {
   375  	wd, err := os.Getwd()
   376  	if err != nil {
   377  		t.Fatal(err)
   378  	}
   379  
   380  	testdata, err := filepath.Rel(wd, ccTestdata)
   381  	if err != nil {
   382  		t.Fatal(err)
   383  	}
   384  
   385  	var re *regexp.Regexp
   386  	if s := *filter; s != "" {
   387  		re = regexp.MustCompile(s)
   388  	}
   389  
   390  	dir := filepath.Join(testdata, filepath.FromSlash("tcc-0.9.26/tests/tests2/"))
   391  	expect(
   392  		t,
   393  		dir,
   394  		func(match string) bool {
   395  			if re != nil && !re.MatchString(filepath.Base(match)) {
   396  				return true
   397  			}
   398  
   399  			return false
   400  		},
   401  		func(wd, match string) []string {
   402  			switch filepath.Base(match) {
   403  			case "31_args.c":
   404  				return []string{"./test", "-", "arg1", "arg2", "arg3", "arg4"}
   405  			case "46_grep.c":
   406  				ioutil.WriteFile(filepath.Join(wd, "test"), []byte("abc\ndef\nghi\n"), 0600)
   407  				return []string{"./grep", "[ea]", "test"}
   408  			default:
   409  				return []string{match}
   410  			}
   411  		},
   412  		cc.AllowCompatibleTypedefRedefinitions(),
   413  		cc.EnableAnonymousStructFields(),
   414  		cc.EnableDefineOmitCommaBeforeDDD(),
   415  		cc.EnableImplicitFuncDef(),
   416  		cc.ErrLimit(-1),
   417  		cc.SysIncludePaths([]string{LibcIncludePath}),
   418  	)
   419  }
   420  
   421  func TestGCCExec(t *testing.T) {
   422  	blacklist := map[string]struct{}{
   423  		// VLA struct field.
   424  		"20020412-1.c": {},
   425  		"20040308-1.c": {},
   426  		"align-nest.c": {},
   427  		"pr41935.c":    {},
   428  
   429  		// Nested function.
   430  		"20010209-1.c":   {},
   431  		"20010605-1.c":   {},
   432  		"20030501-1.c":   {},
   433  		"20040520-1.c":   {},
   434  		"20061220-1.c":   {},
   435  		"20090219-1.c":   {},
   436  		"920612-2.c":     {},
   437  		"921017-1.c":     {},
   438  		"nest-align-1.c": {},
   439  		"nest-stdar-1.c": {},
   440  		"nestfunc-7.c":   {},
   441  		"pr22061-3.c":    {},
   442  		"pr22061-4.c":    {},
   443  		"pr71494.c":      {},
   444  
   445  		// __real__, complex integers and and friends.
   446  		"20010605-2.c": {},
   447  		"20020411-1.c": {},
   448  		"20030910-1.c": {},
   449  		"20041124-1.c": {},
   450  		"20041201-1.c": {},
   451  		"20050121-1.c": {},
   452  		"complex-1.c":  {},
   453  		"complex-6.c":  {},
   454  		"pr38151.c":    {},
   455  		"pr38969.c":    {},
   456  		"pr56837.c":    {},
   457  
   458  		// Depends on __attribute__((aligned(N)))
   459  		"20010904-1.c": {},
   460  		"20010904-2.c": {},
   461  		"align-3.c":    {},
   462  		"pr23467.c":    {},
   463  
   464  		// Depends on __attribute__ ((vector_size (N)))
   465  		"20050316-1.c":   {},
   466  		"20050316-2.c":   {},
   467  		"20050316-3.c":   {},
   468  		"20050604-1.c":   {},
   469  		"20050607-1.c":   {},
   470  		"pr23135.c":      {},
   471  		"pr53645-2.c":    {},
   472  		"pr53645.c":      {},
   473  		"pr60960.c":      {},
   474  		"pr65427.c":      {},
   475  		"pr71626-1.c":    {},
   476  		"pr71626-2.c":    {},
   477  		"scal-to-vec1.c": {},
   478  		"scal-to-vec2.c": {},
   479  		"scal-to-vec3.c": {},
   480  		"simd-1.c":       {},
   481  		"simd-2.c":       {},
   482  		"simd-4.c":       {},
   483  		"simd-5.c":       {},
   484  		"simd-6.c":       {},
   485  
   486  		// https://goo.gl/XDxJEL
   487  		"20021127-1.c": {},
   488  
   489  		// asm
   490  		"20001009-2.c": {},
   491  		"20020107-1.c": {},
   492  		"20030222-1.c": {},
   493  		"20071211-1.c": {},
   494  		"20071220-1.c": {},
   495  		"20071220-2.c": {},
   496  		"960312-1.c":   {},
   497  		"960830-1.c":   {},
   498  		"990130-1.c":   {},
   499  		"990413-2.c":   {},
   500  		"pr38533.c":    {},
   501  		"pr40022.c":    {},
   502  		"pr40657.c":    {},
   503  		"pr41239.c":    {},
   504  		"pr43385.c":    {},
   505  		"pr43560.c":    {},
   506  		"pr45695.c":    {},
   507  		"pr46309.c":    {},
   508  		"pr49279.c":    {},
   509  		"pr49390.c":    {},
   510  		"pr51877.c":    {},
   511  		"pr51933.c":    {},
   512  		"pr52286.c":    {},
   513  		"pr56205.c":    {},
   514  		"pr56866.c":    {},
   515  		"pr56982.c":    {},
   516  		"pr57344-1.c":  {},
   517  		"pr57344-2.c":  {},
   518  		"pr57344-3.c":  {},
   519  		"pr57344-4.c":  {},
   520  		"pr63641.c":    {},
   521  		"pr65053-1.c":  {},
   522  		"pr65053-2.c":  {},
   523  		"pr65648.c":    {},
   524  		"pr65956.c":    {},
   525  		"pr68328.c":    {},
   526  		"pr69320-2.c":  {},
   527  		"stkalign.c":   {},
   528  
   529  		// __label__
   530  		"920415-1.c": {},
   531  		"920721-4.c": {},
   532  		"930406-1.c": {},
   533  		"980526-1.c": {},
   534  		"pr51447.c":  {},
   535  
   536  		// attribute alias
   537  		"alias-2.c": {},
   538  		"alias-3.c": {},
   539  		"alias-4.c": {},
   540  
   541  		// _Alignas
   542  		"pr68532.c": {},
   543  
   544  		// Profiling
   545  		"eeprof-1.c": {},
   546  
   547  		// 6.5.16/4: The order of evaluation of the operands is unspecified.
   548  		"pr58943.c": {},
   549  	}
   550  	todolist := map[string]struct{}{
   551  		// long double constant out of range for double.
   552  		"960405-1.c": {},
   553  
   554  		// case range
   555  		"pr34154.c": {},
   556  
   557  		// VLA. Need to resolve https://gitlab.com/cznic/cc/issues/91 first.
   558  		"20040411-1.c":    {},
   559  		"20040423-1.c":    {},
   560  		"20040811-1.c":    {},
   561  		"20041218-2.c":    {},
   562  		"20070919-1.c":    {},
   563  		"920929-1.c":      {},
   564  		"970217-1.c":      {},
   565  		"pr22061-1.c":     {},
   566  		"pr43220.c":       {},
   567  		"vla-dealloc-1.c": {},
   568  
   569  		// Initializer
   570  		"20050613-1.c":        {}, // struct B b = { .a.j = 5 };
   571  		"20050929-1.c":        {}, // struct C e = { &(struct B) { &(struct A) { 1, 2 }, &(struct A) { 3, 4 } }, &(struct A) { 5, 6 } };
   572  		"20071029-1.c":        {}, // t = (T) { { ++i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
   573  		"921019-1.c":          {}, // void *foo[]={(void *)&("X"[0])};
   574  		"991228-1.c":          {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/991228-1.c:1:51: invalid designator for type double
   575  		"compndlit-1.c":       {}, // x = (struct S) {b:0, a:0, c:({ struct S o = x; o.a == 1 ? 10 : 20;})};
   576  		"const-addr-expr-1.c": {}, // int *Upgd_minor_ID = (int *) &((Upgrade_items + 1)->uaattrid);
   577  		"pr22098-1.c":         {}, // b = (uintptr_t)(p = &(int []){0, 1, 2}[++a]);
   578  		"pr22098-2.c":         {}, // b = (uintptr_t)(p = &(int []){0, 1, 2}[1]);
   579  		"pr22098-3.c":         {}, // b = (uintptr_t)(p = &(int []){0, f(), 2}[1]);
   580  		"pr33631.c":           {}, // struct { int c; pthread_mutex_t m; } r = { .m = 0 };
   581  		"pr70460.c":           {}, // static int b[] = { &&lab1 - &&lab0, &&lab2 - &&lab0 };
   582  
   583  		// signal.h
   584  		"20101011-1.c": {},
   585  
   586  		// &&label expr
   587  		"comp-goto-1.c": {}, // # [100]: Verify (A): mismatched operand type, got int32, expected uint32; simulator_kernel:0x64: 	lsh             	uint32	; ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c:83:40
   588  
   589  		// builtins
   590  		"pr47237.c":       {}, // __builtin_apply, __builtin_apply_args
   591  		"pr64006.c":       {}, // __builtin_mul_overflow
   592  		"pr68381.c":       {}, // __builtin_mul_overflow
   593  		"pr71554.c":       {}, // __builtin_mul_overflow
   594  		"va-arg-pack-1.c": {}, // __builtin_va_arg_pack
   595  
   596  		// long double
   597  		"pr39228.c": {},
   598  
   599  		// un-flatten (wips wrt cc.0506a942f3efa9b7a0a4b98dbe45bf7e8d06a542)
   600  		"20030714-1.c": {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20030714-1.c:102:11: assignment from incompatible type ('unsigned' = '<undefined>')
   601  		"anon-1.c":     {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/anon-1.c:22:7: struct{int; ;} has no member named b
   602  
   603  		//TODO
   604  		"zero-struct-1.c": {}, // New: ccir.New: PANIC: 2
   605  	}
   606  
   607  	wd, err := os.Getwd()
   608  	if err != nil {
   609  		t.Fatal(err)
   610  	}
   611  
   612  	testdata, err := filepath.Rel(wd, ccTestdata)
   613  	if err != nil {
   614  		t.Fatal(err)
   615  	}
   616  
   617  	var re *regexp.Regexp
   618  	if s := *filter; s != "" {
   619  		re = regexp.MustCompile(s)
   620  	}
   621  
   622  	dir := filepath.Join(testdata, filepath.FromSlash("gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/"))
   623  	expect(
   624  		t,
   625  		dir,
   626  		func(match string) bool {
   627  			base := filepath.Base(match)
   628  			_, skip := blacklist[base]
   629  			if _, skip2 := todolist[base]; skip2 {
   630  				skip = true
   631  			}
   632  			if re != nil {
   633  				skip = !re.MatchString(base)
   634  			}
   635  			return skip
   636  		},
   637  		func(wd, match string) []string {
   638  			return []string{match}
   639  		},
   640  		cc.AllowCompatibleTypedefRedefinitions(),
   641  		cc.EnableAlignOf(),
   642  		cc.EnableAlternateKeywords(),
   643  		cc.EnableAnonymousStructFields(),
   644  		cc.EnableAsm(),
   645  		cc.EnableBuiltinClassifyType(),
   646  		cc.EnableBuiltinConstantP(),
   647  		cc.EnableComputedGotos(),
   648  		cc.EnableDefineOmitCommaBeforeDDD(),
   649  		cc.EnableEmptyDeclarations(),
   650  		cc.EnableEmptyStructs(),
   651  		cc.EnableImaginarySuffix(),
   652  		cc.EnableImplicitFuncDef(),
   653  		cc.EnableImplicitIntType(),
   654  		cc.EnableLegacyDesignators(),
   655  		cc.EnableNonConstStaticInitExpressions(),
   656  		cc.EnableOmitConditionalOperand(),
   657  		cc.EnableOmitFuncArgTypes(),
   658  		cc.EnableOmitFuncRetType(),
   659  		cc.EnableParenthesizedCompoundStatemen(),
   660  		cc.EnableTypeOf(),
   661  		cc.EnableUnsignedEnums(),
   662  		cc.EnableWideBitFieldTypes(),
   663  		cc.ErrLimit(-1),
   664  		cc.SysIncludePaths([]string{LibcIncludePath}),
   665  	)
   666  }
   667  
   668  type file struct {
   669  	name string
   670  	data []byte
   671  }
   672  
   673  func (f file) String() string { return fmt.Sprintf("%v %v", len(f.data), f.name) }
   674  
   675  func exec(t *testing.T, bin *virtual.Binary, argv []string, inputFiles []file) (output []byte, resultFiles []file, duration time.Duration) {
   676  	dir, err := ioutil.TempDir("", "ccir-test-")
   677  	if err != nil {
   678  		t.Fatal(err)
   679  	}
   680  
   681  	defer os.RemoveAll(dir)
   682  
   683  	cwd, err := os.Getwd()
   684  	if err != nil {
   685  		t.Fatal(err)
   686  	}
   687  
   688  	defer os.Chdir(cwd)
   689  
   690  	if err := os.Chdir(dir); err != nil {
   691  		t.Fatal(err)
   692  	}
   693  
   694  	for _, v := range inputFiles {
   695  		if err := ioutil.WriteFile(v.name, v.data, 0600); err != nil {
   696  			t.Fatal(err)
   697  		}
   698  	}
   699  
   700  	defer func() {
   701  		if e := recover(); e != nil && err == nil {
   702  			t.Fatal(fmt.Errorf("virtual.Exec: PANIC: %v\n%s", e, debug.Stack()))
   703  		}
   704  	}()
   705  
   706  	var stdin, stdout, stderr bytes.Buffer
   707  	t0 := time.Now()
   708  	exitStatus, err := virtual.Exec(bin, argv, &stdin, &stdout, &stderr, 1<<25, 1<<20, cwd)
   709  	duration = time.Since(t0)
   710  	if err != nil {
   711  		var log bytes.Buffer
   712  		if b := stdout.Bytes(); b != nil {
   713  			fmt.Fprintf(&log, "stdout:\n%s\n", b)
   714  		}
   715  		if b := stderr.Bytes(); b != nil {
   716  			fmt.Fprintf(&log, "stderr:\n%s\n", b)
   717  		}
   718  		t.Fatalf("exit status %v, err %v\n%s", exitStatus, err, log.Bytes())
   719  	}
   720  
   721  	glob, err := filepath.Glob("*")
   722  	if err != nil {
   723  		t.Fatal(err)
   724  	}
   725  
   726  	for _, m := range glob {
   727  		data, err := ioutil.ReadFile(m)
   728  		if err != nil {
   729  			t.Fatal(err)
   730  		}
   731  
   732  		resultFiles = append(resultFiles, file{m, data})
   733  	}
   734  
   735  	return bytes.TrimSpace(append(stdout.Bytes(), stderr.Bytes()...)), resultFiles, duration
   736  }
   737  
   738  func build(t *testing.T, predef string, tus [][]string, opts ...cc.Opt) *virtual.Binary {
   739  	var log buffer.Bytes
   740  	var lpos token.Position
   741  	if *cpp {
   742  		opts = append(opts, cc.Cpp(func(toks []xc.Token) {
   743  			if len(toks) != 0 {
   744  				p := toks[0].Position()
   745  				if p.Filename != lpos.Filename {
   746  					fmt.Fprintf(&log, "# %d %q\n", p.Line, p.Filename)
   747  				}
   748  				lpos = p
   749  			}
   750  			for _, v := range toks {
   751  				log.WriteString(cc.TokSrc(v))
   752  			}
   753  			log.WriteByte('\n')
   754  		}))
   755  	}
   756  
   757  	ndbg := ""
   758  	if *ndebug {
   759  		ndbg = "#define NDEBUG 1" //TODOOK
   760  	}
   761  	var build [][]ir.Object
   762  	tus = append(tus, []string{CRT0Path})
   763  	for _, src := range tus {
   764  		model, err := NewModel()
   765  		if err != nil {
   766  			t.Fatal(err)
   767  		}
   768  
   769  		ast, err := cc.Parse(
   770  			fmt.Sprintf(`
   771  %s
   772  #define __arch__ %s
   773  #define __os__ %s
   774  #include <builtin.h>
   775  %s
   776  `, ndbg, runtime.GOARCH, runtime.GOOS, predef),
   777  			src,
   778  			model,
   779  			append([]cc.Opt{
   780  				cc.AllowCompatibleTypedefRedefinitions(),
   781  				cc.EnableImplicitFuncDef(),
   782  				cc.EnableNonConstStaticInitExpressions(),
   783  				cc.ErrLimit(*errLimit),
   784  				cc.SysIncludePaths([]string{LibcIncludePath}),
   785  			}, opts...)...,
   786  		)
   787  		if s := log.Bytes(); len(s) != 0 {
   788  			t.Logf("\n%s", s)
   789  			log.Close()
   790  		}
   791  		if err != nil {
   792  			t.Fatal(errStr(err))
   793  		}
   794  
   795  		objs, err := New(ast)
   796  		if err != nil {
   797  			t.Fatal(err)
   798  		}
   799  
   800  		if *oLog {
   801  			for i, v := range objs {
   802  				switch x := v.(type) {
   803  				case *ir.DataDefinition:
   804  					fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
   805  				case *ir.FunctionDefinition:
   806  					fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
   807  					for i, v := range x.Body {
   808  						fmt.Fprintf(&log, "%#05x\t%v\n", i, v)
   809  					}
   810  				default:
   811  					t.Fatalf("[%v]: %T %v: %v", i, x, x, err)
   812  				}
   813  			}
   814  		}
   815  		for i, v := range objs {
   816  			if err := v.Verify(); err != nil {
   817  				switch x := v.(type) {
   818  				case *ir.FunctionDefinition:
   819  					fmt.Fprintf(&log, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
   820  					for i, v := range x.Body {
   821  						fmt.Fprintf(&log, "%#05x\t%v\n", i, v)
   822  					}
   823  					t.Fatalf("# [%v]: Verify (A): %v\n%s", i, err, log.Bytes())
   824  				default:
   825  					t.Fatalf("[%v]: %T %v: %v", i, x, x, err)
   826  				}
   827  			}
   828  		}
   829  		build = append(build, objs)
   830  	}
   831  
   832  	linked, err := ir.LinkMain(build...)
   833  	if err != nil {
   834  		t.Fatalf("ir.LinkMain: %s\n%s", err, log.Bytes())
   835  	}
   836  
   837  	for _, v := range linked {
   838  		if err := v.Verify(); err != nil {
   839  			t.Fatal(err)
   840  		}
   841  	}
   842  
   843  	bin, err := virtual.LoadMain(linked)
   844  	if err != nil {
   845  		t.Fatal(err)
   846  	}
   847  
   848  	return bin
   849  }
   850  
   851  func findRepo(t *testing.T, s string) string {
   852  	s = filepath.FromSlash(s)
   853  	for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
   854  		p := filepath.Join(v, "src", s)
   855  		fi, err := os.Lstat(p)
   856  		if err != nil {
   857  			continue
   858  		}
   859  
   860  		if fi.IsDir() {
   861  			wd, err := os.Getwd()
   862  			if err != nil {
   863  				t.Fatal(err)
   864  			}
   865  
   866  			if p, err = filepath.Rel(wd, p); err != nil {
   867  				t.Fatal(err)
   868  			}
   869  
   870  			return p
   871  		}
   872  	}
   873  	return ""
   874  }
   875  
   876  func TestSelfie(t *testing.T) {
   877  	const repo = "github.com/cksystemsteaching/selfie"
   878  	pth := findRepo(t, repo)
   879  	if pth == "" {
   880  		t.Logf("repository not found, skipping: %v", repo)
   881  		return
   882  	}
   883  
   884  	bin := build(t, "", [][]string{{filepath.Join(pth, "selfie.c")}})
   885  	if m, _ := NewModel(); m.Items[cc.Ptr].Size != 4 {
   886  		return
   887  	}
   888  
   889  	args := []string{"./selfie"}
   890  	out, _, d := exec(t, bin, args, nil)
   891  	if g, e := out, []byte("./selfie: usage: selfie { -c { source } | -o binary | -s assembly | -l binary } [ ( -m | -d | -y | -min | -mob ) size ... ]"); !bytes.Equal(g, e) {
   892  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   893  	}
   894  
   895  	t.Logf("%s\n%s\n%v", args, out, d)
   896  
   897  	args = []string{"./selfie", "-c", "hello.c", "-m", "1"}
   898  	out, _, d = exec(t, bin, args, []file{{"hello.c", []byte(`
   899  int *foo;
   900  
   901  int main() {
   902  	foo = "Hello world!";
   903  	while (*foo!=0) { 
   904  		write(1, foo, 4);
   905  		foo = foo + 1;
   906  	}
   907  	*foo = 10;
   908  	write(1, foo, 1);
   909  }
   910  `)}})
   911  	if g, e := out, []byte(`./selfie: this is selfie's starc compiling hello.c
   912  ./selfie: 141 characters read in 12 lines and 0 comments
   913  ./selfie: with 102(72.46%) characters in 52 actual symbols
   914  ./selfie: 1 global variables, 1 procedures, 1 string literals
   915  ./selfie: 2 calls, 3 assignments, 1 while, 0 if, 0 return
   916  ./selfie: 660 bytes generated with 159 instructions and 24 bytes of data
   917  ./selfie: this is selfie's mipster executing hello.c with 1MB of physical memory
   918  Hello world!
   919  hello.c: exiting with exit code 0 and 0.00MB of mallocated memory
   920  ./selfie: this is selfie's mipster terminating hello.c with exit code 0 and 0.01MB of mapped memory
   921  ./selfie: profile: total,max(ratio%)@addr(line#),2max(ratio%)@addr(line#),3max(ratio%)@addr(line#)
   922  ./selfie: calls: 5,4(80.00%)@0x88(~1),1(20.00%)@0x17C(~5),0(0.00%)
   923  ./selfie: loops: 3,3(100.00%)@0x198(~6),0(0.00%),0(0.00%)
   924  ./selfie: loads: 32,4(12.50%)@0x88(~1),3(9.38%)@0x1D4(~7),1(3.12%)@0x24(~1)
   925  ./selfie: stores: 20,3(15.01%)@0x1D0(~7),1(5.00%)@0x4C(~1),0(0.00%)`); !bytes.Equal(g, e) {
   926  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   927  	}
   928  
   929  	t.Logf("%s\n%s\n%v", args, out, d)
   930  
   931  	selfie, err := ioutil.ReadFile(filepath.Join(pth, "selfie.c"))
   932  	if err != nil {
   933  		t.Fatal(err)
   934  	}
   935  
   936  	args = []string{"./selfie", "-c", "selfie.c"}
   937  	out, _, d = exec(t, bin, args, []file{{"selfie.c", selfie}})
   938  	if g, e := out, []byte(`./selfie: this is selfie's starc compiling selfie.c
   939  ./selfie: 176362 characters read in 7086 lines and 970 comments
   940  ./selfie: with 97764(55.55%) characters in 28916 actual symbols
   941  ./selfie: 260 global variables, 290 procedures, 450 string literals
   942  ./selfie: 1960 calls, 722 assignments, 57 while, 571 if, 241 return
   943  ./selfie: 121676 bytes generated with 28783 instructions and 6544 bytes of data`); !bytes.Equal(g, e) {
   944  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   945  	}
   946  
   947  	t.Logf("%s\n%s\n%v", args, out, d)
   948  }
   949  
   950  func TestC4(t *testing.T) {
   951  	bin := build(t, "", [][]string{{"testdata/github.com/rswier/c4/c4.c"}})
   952  
   953  	args := []string{"./c4"}
   954  	out, _, d := exec(t, bin, args, nil)
   955  	if g, e := out, []byte("usage: c4 [-s] [-d] file ..."); !bytes.Equal(g, e) {
   956  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   957  	}
   958  
   959  	t.Logf("%s\n%s\n%v", args, out, d)
   960  
   961  	hello, err := ioutil.ReadFile("testdata/github.com/rswier/c4/hello.c")
   962  	if err != nil {
   963  		t.Fatal(err)
   964  	}
   965  
   966  	args = []string{"./c4", "hello.c"}
   967  	out, _, d = exec(t, bin, args, []file{{"hello.c", hello}})
   968  	if g, e := out, []byte(`hello, world
   969  exit(0) cycle = 9`); !bytes.Equal(g, e) {
   970  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   971  	}
   972  
   973  	t.Logf("%s\n%s\n%v", args, out, d)
   974  
   975  	args = []string{"./c4", "-s", "hello.c"}
   976  	out, _, d = exec(t, bin, args, []file{{"hello.c", hello}})
   977  	t.Logf("%s\n%s\n%v", args, out, d)
   978  
   979  	c4, err := ioutil.ReadFile("testdata/github.com/rswier/c4/c4.c")
   980  	if err != nil {
   981  		t.Fatal(err)
   982  	}
   983  
   984  	args = []string{"./c4", "c4.c", "hello.c"}
   985  	out, _, d = exec(t, bin, args, []file{{"c4.c", c4}, {"hello.c", hello}})
   986  	if g, e := out, []byte(`hello, world
   987  exit(0) cycle = 9
   988  exit(0) cycle = 25604`); !bytes.Equal(g, e) {
   989  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
   990  	}
   991  
   992  	t.Logf("%s\n%s\n%v", args, out, d)
   993  }
   994  
   995  func TestSQLite(t *testing.T) {
   996  	const repo = "sqlite.org/sqlite-amalgamation-3190300/"
   997  	pth := findRepo(t, repo)
   998  	if pth == "" {
   999  		t.Logf("repository not found, skipping: %v", repo)
  1000  		return
  1001  	}
  1002  
  1003  	bin := build(
  1004  		t,
  1005  		`#define SQLITE_DEBUG 1 //TODOOK
  1006  		#define SQLITE_ENABLE_MEMSYS5 1`,
  1007  		[][]string{
  1008  			{"testdata/sqlite/test.c"},
  1009  			{filepath.Join(pth, "sqlite3.c")},
  1010  		},
  1011  		cc.EnableAnonymousStructFields(),
  1012  		cc.EnableWideBitFieldTypes(),
  1013  		cc.IncludePaths([]string{pth}),
  1014  	)
  1015  	var gz bytes.Buffer
  1016  	zw := gzip.NewWriter(&gz)
  1017  	enc := gob.NewEncoder(zw)
  1018  	if err := enc.Encode(bin); err != nil {
  1019  		t.Fatal(err)
  1020  	}
  1021  
  1022  	if err := zw.Close(); err != nil {
  1023  		t.Fatal(err)
  1024  	}
  1025  
  1026  	t.Logf("code %#08x, text %#08x, data %#08x, bss %#08x, pc2func %v, pc2line %v, gz %v\n",
  1027  		len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(gz.Bytes()),
  1028  	)
  1029  
  1030  	args := []string{"./test"}
  1031  	out, f, d := exec(t, bin, args, nil)
  1032  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1033  	if g, e := out, []byte("Usage: ./test DATABASE SQL-STATEMENT"); !bytes.Equal(g, e) {
  1034  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1035  	}
  1036  
  1037  	args = []string{"./test", "foo"}
  1038  	out, f, d = exec(t, bin, args, nil)
  1039  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1040  	if g, e := out, []byte("Usage: ./test DATABASE SQL-STATEMENT"); !bytes.Equal(g, e) {
  1041  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1042  	}
  1043  
  1044  	args = []string{"./test", "foo", "bar"}
  1045  	out, f, d = exec(t, bin, args, nil)
  1046  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1047  	if g, e := out, []byte(`FAIL (1) near "bar": syntax error
  1048  SQL error: near "bar": syntax error`); !bytes.Equal(g, e) {
  1049  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1050  	}
  1051  
  1052  	args = []string{"./test", "foo", "select * from t"}
  1053  	out, f, d = exec(t, bin, args, nil)
  1054  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1055  	if g, e := out, []byte(`FAIL (1) no such table: t
  1056  SQL error: no such table: t`); !bytes.Equal(g, e) {
  1057  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1058  	}
  1059  
  1060  	args = []string{"./test", "foo", "select name from sqlite_master where type='table'"}
  1061  	out, f, d = exec(t, bin, args, nil)
  1062  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1063  	if g, e := out, []byte(""); !bytes.Equal(g, e) {
  1064  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1065  	}
  1066  
  1067  	args = []string{"./test", "foo", "create table t(i int)"}
  1068  	out, f, d = exec(t, bin, args, nil)
  1069  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1070  	if g, e := out, []byte(""); !bytes.Equal(g, e) {
  1071  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1072  	}
  1073  
  1074  	args = []string{"./test", "foo", `
  1075  	create table t(i int);
  1076  	select name from sqlite_master where type='table';
  1077  	`}
  1078  	out, f, d = exec(t, bin, args, nil)
  1079  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1080  	if g, e := out, []byte("name = t"); !bytes.Equal(g, e) {
  1081  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1082  	}
  1083  
  1084  	args = []string{"./test", "foo", `
  1085  	create table t(i int);
  1086  	select name from sqlite_master where type='table';
  1087  	insert into t values(42), (314);
  1088  	select * from t order by i asc;
  1089  	select * from t order by i desc;
  1090  	`}
  1091  	out, f, d = exec(t, bin, args, nil)
  1092  	t.Logf("%q\n%s\n%v\n%v", args, out, d, f)
  1093  	if g, e := out, []byte(`name = t
  1094  i = 42
  1095  i = 314
  1096  i = 314
  1097  i = 42`); !bytes.Equal(g, e) {
  1098  		t.Fatalf("\ngot\n%s\nexp\n%s", g, e)
  1099  	}
  1100  }
  1101  
  1102  func TestOther(t *testing.T) {
  1103  	var re *regexp.Regexp
  1104  	if s := *filter; s != "" {
  1105  		re = regexp.MustCompile(s)
  1106  	}
  1107  
  1108  	expect(
  1109  		t,
  1110  		"testdata",
  1111  		func(match string) bool {
  1112  			if re != nil && !re.MatchString(filepath.Base(match)) {
  1113  				return true
  1114  			}
  1115  
  1116  			return false
  1117  		},
  1118  		func(wd, match string) []string {
  1119  			return []string{match}
  1120  		},
  1121  		cc.EnableImplicitFuncDef(),
  1122  		cc.ErrLimit(-1),
  1123  		cc.SysIncludePaths([]string{LibcIncludePath}),
  1124  		cc.AllowCompatibleTypedefRedefinitions(),
  1125  	)
  1126  }