Skip to content

Commit cb5f7ad

Browse files
aykevldeadprogram
authored andcommitted
interp: fix copy() from/to external buffers
This includes copying from a //go:embed slice for example. The slice with data is not available at interp time. See: #4895
1 parent 704489e commit cb5f7ad

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

interp/interpreter.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,22 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
364364
continue
365365
}
366366
nBytes := uint32(n * elemSize)
367+
srcObj := mem.get(src.index())
367368
dstObj := mem.getWritable(dst.index())
369+
if srcObj.buffer == nil || dstObj.buffer == nil {
370+
// If the buffer is nil, it means the slice is external.
371+
// This can happen for example when copying data out of
372+
// a //go:embed slice, which is not available at interp
373+
// time.
374+
// See: https://github.com/tinygo-org/tinygo/issues/4895
375+
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
376+
if err != nil {
377+
return nil, mem, err
378+
}
379+
continue
380+
}
368381
dstBuf := dstObj.buffer.asRawValue(r)
369-
srcBuf := mem.get(src.index()).buffer.asRawValue(r)
382+
srcBuf := srcObj.buffer.asRawValue(r)
370383
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
371384
dstObj.buffer = dstBuf
372385
mem.put(dst.index(), dstObj)

interp/testdata/slice-copy.ll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ target triple = "x86_64--linux"
1111
@main.sliceDstUntaint.buf = internal global [2 x i8] zeroinitializer
1212
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
1313
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
14+
@main.sliceSrcExternal1.buf = external global [2 x i8]
15+
@main.sliceDstExternal1.buf = internal global [2 x i8] zeroinitializer
16+
@main.sliceSrcExternal2.buf = internal global [2 x i8] zeroinitializer
17+
@main.sliceDstExternal2.buf = external global [2 x i8]
1418

1519
declare i64 @runtime.sliceCopy(ptr %dst, ptr %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
1620

@@ -58,6 +62,14 @@ entry:
5862
%sliceDstTaint.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstTaint.buf, i32 0)
5963
call void @runtime.printuint8(i8 %sliceDstTaint.val)
6064

65+
; print(sliceDstExternal1[0])
66+
%sliceDstExternal1.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstExternal1.buf, i32 0)
67+
call void @runtime.printuint8(i8 %sliceDstExternal1.val)
68+
69+
; print(sliceDstExternal2[0])
70+
%sliceDstExternal2.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstExternal2.buf, i32 0)
71+
call void @runtime.printuint8(i8 %sliceDstExternal2.val)
72+
6173
ret void
6274
}
6375

@@ -102,5 +114,11 @@ entry:
102114
call void @use(ptr @main.sliceSrcTaint.buf)
103115
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
104116

117+
; Test that copying from or into external buffers works correctly.
118+
; These copy operations must be done at runtime.
119+
; https://github.com/tinygo-org/tinygo/issues/4895
120+
%copy.n5 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal1.buf, ptr @main.sliceSrcExternal1.buf, i64 2, i64 2, i64 1)
121+
%copy.n6 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal2.buf, ptr @main.sliceSrcExternal2.buf, i64 2, i64 2, i64 1)
122+
105123
ret void
106124
}

interp/testdata/slice-copy.out.ll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ target triple = "x86_64--linux"
33

44
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
55
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
6+
@main.sliceSrcExternal1.buf = external global [2 x i8]
7+
@main.sliceDstExternal1.buf = internal global [2 x i8] zeroinitializer
8+
@main.sliceSrcExternal2.buf = internal global [2 x i8] zeroinitializer
9+
@main.sliceDstExternal2.buf = external global [2 x i8]
610

711
declare i64 @runtime.sliceCopy(ptr, ptr, i64, i64, i64) unnamed_addr
812

@@ -16,6 +20,8 @@ define void @runtime.initAll() unnamed_addr {
1620
entry:
1721
call void @use(ptr @main.sliceSrcTaint.buf)
1822
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
23+
%copy.n5 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal1.buf, ptr @main.sliceSrcExternal1.buf, i64 2, i64 2, i64 1)
24+
%copy.n6 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal2.buf, ptr @main.sliceSrcExternal2.buf, i64 2, i64 2, i64 1)
1925
ret void
2026
}
2127

@@ -28,5 +34,9 @@ entry:
2834
call void @runtime.printuint8(i8 97)
2935
%sliceDstTaint.val = load i8, ptr @main.sliceDstTaint.buf, align 1
3036
call void @runtime.printuint8(i8 %sliceDstTaint.val)
37+
%sliceDstExternal1.val = load i8, ptr @main.sliceDstExternal1.buf, align 1
38+
call void @runtime.printuint8(i8 %sliceDstExternal1.val)
39+
%sliceDstExternal2.val = load i8, ptr @main.sliceDstExternal2.buf, align 1
40+
call void @runtime.printuint8(i8 %sliceDstExternal2.val)
3141
ret void
3242
}

0 commit comments

Comments
 (0)