a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
150 lines
3.8 KiB
Go
150 lines
3.8 KiB
Go
package languages
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
func fnPtrReg(edges []*graph.Edge, st, field string) *graph.Edge {
|
|
for _, e := range edges {
|
|
if e.Kind != graph.EdgeReferences || e.Meta == nil {
|
|
continue
|
|
}
|
|
if v, _ := e.Meta["via"].(string); v != "fn-pointer-reg" {
|
|
continue
|
|
}
|
|
s, _ := e.Meta["fnptr_struct"].(string)
|
|
f, _ := e.Meta["fnptr_field"].(string)
|
|
if s == st && f == field {
|
|
return e
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func fnPtrRegFn(edges []*graph.Edge, fn string) *graph.Edge {
|
|
for _, e := range edges {
|
|
if e.Meta == nil {
|
|
continue
|
|
}
|
|
if v, _ := e.Meta["via"].(string); v != "fn-pointer-reg" {
|
|
continue
|
|
}
|
|
if f, _ := e.Meta["fnptr_fn"].(string); f == fn {
|
|
return e
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func fnPtrDisp(edges []*graph.Edge, st, field string) *graph.Edge {
|
|
for _, e := range edges {
|
|
if e.Kind != graph.EdgeCalls || e.Meta == nil {
|
|
continue
|
|
}
|
|
if v, _ := e.Meta["via"].(string); v != "fn-pointer-dispatch" {
|
|
continue
|
|
}
|
|
s, _ := e.Meta["fnptr_struct"].(string)
|
|
f, _ := e.Meta["fnptr_field"].(string)
|
|
if s == st && f == field {
|
|
return e
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestCFnPtr_CommandTablePattern(t *testing.T) {
|
|
src := `typedef int (*cmd_fn)(int, char**);
|
|
struct cmd { char *name; int (*fn)(int,char**); };
|
|
int cmd_add(int a, char**b){return 0;}
|
|
int cmd_rm(int a, char**b){return 0;}
|
|
static struct cmd cmds[] = { {"add", cmd_add}, {"rm", cmd_rm} };
|
|
int run(int i, int argc, char **argv) {
|
|
return cmds[i].fn(argc, argv);
|
|
}
|
|
`
|
|
res, err := NewCExtractor().Extract("cmds.c", []byte(src))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if fnPtrRegFn(res.Edges, "cmd_add") == nil || fnPtrRegFn(res.Edges, "cmd_rm") == nil {
|
|
t.Errorf("positional registrations for cmd_add/cmd_rm not captured")
|
|
}
|
|
d := fnPtrDisp(res.Edges, "cmd", "fn")
|
|
if d == nil {
|
|
t.Fatalf("dispatch placeholder for cmds[i].fn() not stamped")
|
|
}
|
|
if d.From != "cmds.c::run" {
|
|
t.Errorf("dispatch From = %q (want cmds.c::run)", d.From)
|
|
}
|
|
}
|
|
|
|
func TestCFnPtr_DesignatedAndTypedefField(t *testing.T) {
|
|
src := `typedef int (*op_fn)(void);
|
|
struct ops { op_fn handler; };
|
|
int op_x(void){return 0;}
|
|
struct ops base = { .handler = op_x };
|
|
int run_op(struct ops *o) { return o->handler(); }
|
|
`
|
|
res, err := NewCExtractor().Extract("ops.c", []byte(src))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if r := fnPtrReg(res.Edges, "ops", "handler"); r == nil {
|
|
t.Errorf("designated registration .handler = op_x not captured")
|
|
}
|
|
if fnPtrDisp(res.Edges, "ops", "handler") == nil {
|
|
t.Errorf("dispatch o->handler() not stamped (typedef'd fn-pointer field)")
|
|
}
|
|
}
|
|
|
|
func TestCFnPtr_FieldCopyCaptured(t *testing.T) {
|
|
src := `typedef int (*h_fn)(void);
|
|
struct a { h_fn h; };
|
|
struct b { h_fn h; };
|
|
void wire(struct a *x, struct b *y) { x->h = y->h; }
|
|
`
|
|
res, err := NewCExtractor().Extract("wire.c", []byte(src))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var copyEdge *graph.Edge
|
|
for _, e := range res.Edges {
|
|
if e.Meta != nil {
|
|
if cf, _ := e.Meta["fnptr_copy_field"].(string); cf == "h" {
|
|
copyEdge = e
|
|
}
|
|
}
|
|
}
|
|
if copyEdge == nil {
|
|
t.Fatalf("field-copy x->h = y->h not captured")
|
|
}
|
|
if st, _ := copyEdge.Meta["fnptr_struct"].(string); st != "a" {
|
|
t.Errorf("copy target struct = %q (want a)", st)
|
|
}
|
|
if cs, _ := copyEdge.Meta["fnptr_copy_struct"].(string); cs != "b" {
|
|
t.Errorf("copy source struct = %q (want b)", cs)
|
|
}
|
|
}
|
|
|
|
func TestCppFnPtr_StructDispatch(t *testing.T) {
|
|
// The shared pass also runs for C++ structs.
|
|
src := `struct Ops { int (*run)(int); };
|
|
int impl(int x){return x;}
|
|
static struct Ops table = { impl };
|
|
int dispatch(struct Ops *o) { return o->run(1); }
|
|
`
|
|
res, err := NewCppExtractor().Extract("ops.cpp", []byte(src))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if fnPtrRegFn(res.Edges, "impl") == nil {
|
|
t.Errorf("C++ struct fn-pointer registration not captured")
|
|
}
|
|
if fnPtrDisp(res.Edges, "Ops", "run") == nil {
|
|
t.Errorf("C++ dispatch o->run() not stamped")
|
|
}
|
|
}
|