summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzaima <dzaimagit@gmail.com>2024-02-06 20:26:40 +0200
committerdzaima <dzaimagit@gmail.com>2024-02-06 20:29:24 +0200
commit2b30010c257d265eb65c544f2f3de5587a63ac79 (patch)
treee8bdde85b8c705c3120f3532170b8656247fba43
parent74f7e4701db36841b7c94984495de6f6bdc4a71f (diff)
disallow writing array to pointer within pointer object
and while at it move a global to an argument
-rw-r--r--src/ffi.c52
-rw-r--r--test/cases/ffi.bqn4
2 files changed, 28 insertions, 28 deletions
diff --git a/src/ffi.c b/src/ffi.c
index 30e38028..d0620fd4 100644
--- a/src/ffi.c
+++ b/src/ffi.c
@@ -681,16 +681,15 @@ static NOINLINE B ty_fmt(B o) {
-STATIC_GLOBAL B ffiObjsGlobal;
-static void genObj_ptrobj(void* res, B c, B expEl) {
+static void genObj_writePtr(void* res, B c, B expEl, B* sourceObjs) {
B h = ptrobj_checkget(c);
#if FFI_CHECKS
if (!ty_equal(ptrh_type(h), expEl)) thrF("FFI: Pointer object type isn't compatible with argument type");
#endif
- ffiObjsGlobal = vec_addN(ffiObjsGlobal, incG(c));
*(void**)res = ptrh_ptr(h);
+ if (sourceObjs!=NULL) *sourceObjs = vec_addN(*sourceObjs, incG(c));
}
-void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
+void genObj(B o, B c, void* ptr, B* sourceObjs) { // doesn't consume
if (isC32(o)) { // scalar
u32 t = styG(o);
f64 f = c.f;
@@ -712,9 +711,10 @@ void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
if (t->ty==cty_ptr || t->ty==cty_tlarr) { // *any / &any / top-level [n]any
B e = t->a[0].o;
if (isAtm(c)) {
- if (isNsp(c)) { genObj_ptrobj(ptr, c, e); return; }
+ if (isNsp(c)) { genObj_writePtr(ptr, c, e, sourceObjs); return; }
thrF("FFI: Expected array or pointer object corresponding to %R", ty_fmt(o));
}
+ if (sourceObjs==NULL) thrF("ptr.Write: Cannot write array to %R", ty_fmt(o));
usz ia = IA(c);
if (t->ty==cty_tlarr && t->arrCount!=ia) thrF("FFI: Incorrect item count of %s corresponding to %R", ia, ty_fmt(o));
if (isC32(e)) { // *num / &num
@@ -732,8 +732,8 @@ void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
case sty_f32: ffi_checkRange(c, mut, "f64", 0, 0); cG = cpyF32Bits(c); break; // no direct f32 type, so no direct reference option
}
- ffiObjsGlobal = vec_addN(ffiObjsGlobal, cG);
*(void**)ptr = tyany_ptr(cG);
+ *sourceObjs = vec_addN(*sourceObjs, cG);
} else { // *{...} / &{...} / *[n]any
BQNFFIType* t2 = c(BQNFFIType, e);
if (t2->ty!=cty_struct && t2->ty!=cty_starr) thrM("FFI: Pointer element type not implemented");
@@ -743,9 +743,9 @@ void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
void* dataStruct = dataAll+sizeof(usz);
*((usz*)dataAll) = ia;
SGetU(c)
- for (usz i = 0; i < ia; i++) genObj(t->a[0].o, GetU(c, i), dataStruct + elSz*i);
+ for (usz i = 0; i < ia; i++) genObj(t->a[0].o, GetU(c, i), dataStruct + elSz*i, sourceObjs);
*(void**)ptr = dataStruct;
- ffiObjsGlobal = vec_addN(ffiObjsGlobal, tag(TOBJ(dataAll), OBJ_TAG));
+ *sourceObjs = vec_addN(*sourceObjs, tag(TOBJ(dataAll), OBJ_TAG));
}
} else if (t->ty==cty_repr) { // any:any
B o2 = t->a[0].o;
@@ -765,11 +765,12 @@ void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
BQNFFIType* t2 = c(BQNFFIType, o2);
B ore = t2->a[0].o;
assert(t2->ty==cty_ptr && (isC32(ore) || ore.u==ty_voidptr.u));
- if (isNsp(c)) { genObj_ptrobj(ptr, c, ore); return; }
+ if (isNsp(c)) { genObj_writePtr(ptr, c, ore, sourceObjs); return; }
if (ore.u == m_c32(sty_void).u) { // *:any
elSz = sizeof(void*);
goto toScalarReinterpret;
}
+ if (sourceObjs==NULL) thrF("ptr.Write: Cannot write array to %R", ty_fmt(o));
bool mut = t2->mutPtr;
elSz = isC32(ore)? sty_w[styG(ore)] : sizeof(void*);
@@ -790,7 +791,7 @@ void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
cG = taga(cGp);
} else cG = toW(reT, reW, c);
*(void**)ptr = tyany_ptr(cG);
- ffiObjsGlobal = vec_addN(ffiObjsGlobal, cG);
+ *sourceObjs = vec_addN(*sourceObjs, cG);
}
} else if (t->ty==cty_struct || t->ty==cty_starr) {
if (!isArr(c)) thrF("FFI: Expected array corresponding to %R", ty_fmt(o));
@@ -798,7 +799,7 @@ void genObj(B o, B c, void* ptr) { // doesn't consume; mutates ffiObjsGlobal
SGetU(c)
for (usz i = 0; i < t->ia-1; i++) {
BQNFFIEnt e = t->a[i];
- genObj(e.o, GetU(c, i), e.structOffset + (u8*)ptr);
+ genObj(e.o, GetU(c, i), e.structOffset + (u8*)ptr, sourceObjs);
}
} else thrM("FFI: Unimplemented type (genObj)");
}
@@ -816,19 +817,17 @@ static B readStruct(BQNFFIType* t, u8* ptr) {
}
static B readSimple(u8 resCType, u8* ptr) {
- B r;
switch(resCType) { default: UD; // thrM("FFI: Unimplemented type");
- case sty_void: r = m_c32(0); break;
- case sty_a: r = getB(*(BQNV*)ptr); break;
- case sty_i8: r = m_i32(*( i8*)ptr); break; case sty_u8: r = m_i32(*( u8*)ptr); break;
- case sty_i16: r = m_i32(*(i16*)ptr); break; case sty_u16: r = m_i32(*(u16*)ptr); break;
- case sty_i32: r = m_i32(*(i32*)ptr); break; case sty_u32: r = m_f64(*(u32*)ptr); break;
- case sty_i64: { i64 v = *(i64*)ptr; if (i64abs(v)>=(1ULL<<53)) thrM("FFI: i64 result absolute value ≥ 2⋆53"); r = m_f64(v); break; }
- case sty_u64: { u64 v = *(u64*)ptr; if ( v >=(1ULL<<53)) thrM("FFI: u64 result ≥ 2⋆53"); r = m_f64(v); break; }
- case sty_f32: r = m_f64(*(float* )ptr); break;
- case sty_f64: r = m_f64(*(double*)ptr); break;
+ case sty_void:return m_c32(0);
+ case sty_a: return getB(*(BQNV*)ptr);
+ case sty_i8: return m_i32(*( i8*)ptr); case sty_u8: return m_i32(*( u8*)ptr);
+ case sty_i16: return m_i32(*(i16*)ptr); case sty_u16: return m_i32(*(u16*)ptr);
+ case sty_i32: return m_i32(*(i32*)ptr); case sty_u32: return m_f64(*(u32*)ptr);
+ case sty_i64: { i64 v = *(i64*)ptr; if (i64abs(v)>=(1ULL<<53)) thrM("FFI: i64 result absolute value ≥ 2⋆53"); return m_f64(v); }
+ case sty_u64: { u64 v = *(u64*)ptr; if ( v >=(1ULL<<53)) thrM("FFI: u64 result ≥ 2⋆53"); return m_f64(v); }
+ case sty_f32: return m_f64(*(float* )ptr);
+ case sty_f64: return m_f64(*(double*)ptr);
}
- return r;
}
static u8 const reTyMapC[] = { [3]=t_c8arr, [4]=t_c16arr, [5]=t_c32arr };
@@ -940,7 +939,7 @@ B libffiFn_c2(B t, B w, B x) {
usz argn = cif->nargs;
BQNFFIEnt* ents = argObj->a;
- ffiObjsGlobal = emptyHVec(); // implicit parameter to genObj
+ B ffiObjs = emptyHVec(); // implicit parameter to genObj
for (usz i = 0; i < argn; i++) {
BQNFFIEnt e = ents[i+1];
B o;
@@ -949,9 +948,8 @@ B libffiFn_c2(B t, B w, B x) {
} else {
o = (e.onW? wf : xf)(e.onW?wa:xa, idxs[e.onW]++);
}
- genObj(e.o, o, tmpAlloc + e.staticOffset);
+ genObj(e.o, o, tmpAlloc + e.staticOffset, &ffiObjs);
}
- B ffiObjs = ffiObjsGlobal; // load the global before ffi_call to prevent issues on recursive calls
for (usz i = 0; i < argn; i++) argPtrs[i] = tmpAlloc + ents[i+1].staticOffset;
void* res = tmpAlloc + ents[0].staticOffset;
@@ -1228,9 +1226,7 @@ static B ptrobjRead_c1(B t, B x) {
}
static B ptrobjWrite_c2(B t, B w, B x) {
B h = nfn_objU(t);
- ffiObjsGlobal = emptyHVec();
- genObj(ptrh_type(h), x, ptrobj_elbase(h, w, false));
- decG(ffiObjsGlobal);
+ genObj(ptrh_type(h), x, ptrobj_elbase(h, w, false), NULL);
dec(x);
return m_f64(1);
diff --git a/test/cases/ffi.bqn b/test/cases/ffi.bqn
index 8182bcd8..983e1058 100644
--- a/test/cases/ffi.bqn
+++ b/test/cases/ffi.bqn
@@ -75,6 +75,7 @@
!"FFI: Return value is specified as ""&"", but there are 0 mutated values" % @•FFI"&"‿"bqn_init"‿">*i32"
!"FFI: Return value is specified as ""&"", but there are 2 mutated values" % @•FFI"&"‿"bqn_init"‿"&i32"‿"&i32"
!"FFI: Cannot return array" % @•FFI"[4]i32"‿"bqn_init"
+!"FFI: Unimplemented result type" % @•FFI"**:i8"‿"bqn_init"
# correct elements
@@ -195,6 +196,9 @@
%USE Walloc {{𝕊al: p←"{i16,i16,i16,i64}" Al 99 ⋄ p.Write ¯4‿10000‿¯30000‿7e12 ⋄ s←-○{CpyA 0∾˜⋈˜𝕩}´ ⟨p.Field 2, p⟩ ⋄ Cpy ⟨p.Add 1, p, s⟩ ⋄ p.Read¨ ↕2}} %% ⟨¯4‿10000‿¯30000‿7e12, ¯4‿10000‿0‿0⟩
%USE Walloc {{𝕊al: p←"{i32,{i64,i64}}" Al 999 ⋄ {𝕩 p.Write ⟨𝕩×10,𝕩×20‿30⟩}¨ ↕4 ⋄ ((p.Field 1).Field 0).Read¨ ↕4 }} %% 20×↕4
!"Cannot get a field of a pointer to a scalar" % %USE WallocE {{𝕊al: ("i32" Al 99).Field 0}}
+!"ptr.Write: Cannot write array to ""*i32""" % %USE WallocE {{𝕊al: ("*i32" Al 99).Write 1‿2‿3}}
+!"ptr.Write: Cannot write array to ""*i32:i32""" % %USE WallocE {{𝕊al: ("*i32:i32"Al 99).Write ↕16}}
+%USE Walloc {{𝕊al: p←("" Al 99).Cast "*:i8" ⋄ a←"i32"Al 99 ⋄ a.Write 12345 ⋄ p.Write ar←Cpy a‿a‿0 ⋄ ! ar ≡ p.Read 0 ⋄ a.Read 0}} %% 12345
%USE Walloc {{𝕊al: p←"i16" Al 99 ⋄ raw ← Cpy 0∾˜⋈˜p.Add 3 ⋄ cpy2←@•FFI"*i16"‿"memcpy"‿"*:i8"‿"*:i8"‿size_t ⋄ p.Sub Cpy2 raw‿raw‿0 }} %% ¯3
# garbage arguments