diff options
author | dzaima <dzaimagit@gmail.com> | 2024-02-06 20:26:40 +0200 |
---|---|---|
committer | dzaima <dzaimagit@gmail.com> | 2024-02-06 20:29:24 +0200 |
commit | 2b30010c257d265eb65c544f2f3de5587a63ac79 (patch) | |
tree | e8bdde85b8c705c3120f3532170b8656247fba43 | |
parent | 74f7e4701db36841b7c94984495de6f6bdc4a71f (diff) |
disallow writing array to pointer within pointer object
and while at it move a global to an argument
-rw-r--r-- | src/ffi.c | 52 | ||||
-rw-r--r-- | test/cases/ffi.bqn | 4 |
2 files changed, 28 insertions, 28 deletions
@@ -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 |