@@ -13,12 +13,17 @@ import (
13
13
"github.com/pkg/errors"
14
14
)
15
15
16
- const CompilationMemoryLimit = 50 * 1024 * 1024
16
+ // Memory Limit of a G++ Process
17
+ const CompilationMemoryLimit = 100 * 1024 * 1024
18
+
19
+ // it is required that the docker image is built before the program runs
17
20
const imageName = "markhuang1212/code-grader/runtime-compile"
18
21
19
22
var InternalError = errors .New ("internal error" )
20
23
var CompilationFailure = errors .New ("compilation error" )
21
24
25
+ // The function compiles user's code inside a docker container, and returns the
26
+ // executable on success
22
27
func CompileUserCode (ctx context.Context , gr types.GradeRequest ) ([]byte , error ) {
23
28
24
29
cli , err := client .NewClientWithOpts (client .FromEnv , client .WithAPIVersionNegotiation ())
@@ -33,52 +38,59 @@ func CompileUserCode(ctx context.Context, gr types.GradeRequest) ([]byte, error)
33
38
},
34
39
AttachStdin : true ,
35
40
AttachStdout : true ,
41
+ AttachStderr : true ,
42
+ OpenStdin : true ,
36
43
}, & container.HostConfig {
37
44
NetworkMode : "none" ,
38
- Resources : container.Resources {
39
- Memory : CompilationMemoryLimit ,
45
+ Resources : container.Resources {
46
+ // Memory: CompilationMemoryLimit,
40
47
},
41
48
}, nil , nil , "" )
42
49
43
50
if err != nil {
44
- return nil , errors .Wrap (err , "cannot create container" )
51
+ return nil , errors .Wrap (InternalError , "cannot create container" )
45
52
}
46
53
47
- cli .ContainerStart (ctx , resp .ID , dockertypes.ContainerStartOptions {})
48
-
49
54
hjresp , err := cli .ContainerAttach (ctx , resp .ID , dockertypes.ContainerAttachOptions {
55
+ Stream : true ,
50
56
Stdin : true ,
51
57
Stdout : true ,
52
58
Stderr : true ,
53
59
})
54
60
55
61
if err != nil {
56
- return nil , errors .Wrap (err , "cannot attach container" )
62
+ return nil , errors .Wrap (InternalError , "cannot attach container" )
63
+ }
64
+
65
+ statucCh , errCh := cli .ContainerWait (ctx , resp .ID , container .WaitConditionNextExit )
66
+
67
+ err = cli .ContainerStart (ctx , resp .ID , dockertypes.ContainerStartOptions {})
68
+ if err != nil {
69
+ return nil , errors .Wrap (InternalError , "cannot start container" )
57
70
}
58
71
59
72
outR , outW := io .Pipe ()
60
73
errR , errW := io .Pipe ()
61
-
62
- stdcopy .StdCopy (outW , errW , hjresp .Reader )
63
74
hjresp .Conn .Write ([]byte (gr .UserCode ))
75
+ hjresp .Conn .Close ()
76
+ stdcopy .StdCopy (outW , errW , hjresp .Conn )
64
77
65
- statucCh , errCh := cli .ContainerWait (ctx , resp .ID , container .WaitConditionNextExit )
66
78
select {
67
79
case status := <- statucCh :
68
80
if status .StatusCode == 0 {
69
81
out , err := io .ReadAll (outR )
70
82
if err != nil {
71
- return nil , errors .Wrap (err , "cannot read stdout" )
83
+ return nil , errors .Wrap (InternalError , "cannot read stdout" )
72
84
}
73
85
return out , err
74
86
} else {
75
87
out , err := io .ReadAll (errR )
76
88
if err != nil {
77
- return nil , errors .Wrap (err , "cannot read stderr" )
89
+ return nil , errors .Wrap (InternalError , "cannot read stderr" )
78
90
}
79
- return out , errors . New ( "compilation failed" )
91
+ return out , CompilationFailure
80
92
}
81
- case err := <- errCh :
82
- return nil , err
93
+ case <- errCh :
94
+ return nil , errors . Wrap ( InternalError , "error waiting container" )
83
95
}
84
96
}
0 commit comments