From be1e3c4e09e4c5592428e71d875ef6a623c82804 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 3 Nov 2016 21:11:39 +0800 Subject: [PATCH 1/3] add a simple sizeof checker to compare nim & c types --- compiler/ccgtypes.nim | 5 ++++- lib/nimbase.h | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index bd2e2cdda3..0327d9b82e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -701,7 +701,10 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = idTablePut(m.typeCache, t, result) # always call for sideeffects: let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check) else: getTupleDesc(m, t, result, check) - if not isImportedType(t): add(m.s[cfsTypes], recdesc) + if not isImportedType(t): + add(m.s[cfsTypes], recdesc) + elif tfIncompleteStruct notin t.flags: + addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [result, rope(getSize(t))]) of tySet: result = getTypeName(t.lastSon) & "Set" idTablePut(m.typeCache, t, result) diff --git a/lib/nimbase.h b/lib/nimbase.h index 52de60969c..a75016ed74 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -459,3 +459,11 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz #elif defined(__FreeBSD__) # include #endif + +/* Compile with -t:-DNIM_CHECK_ABI to enable */ +#ifdef NIM_CHECK_ABI +# define NIM_CHECK_SIZE(typ, sz) \ + _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") +#else +# define NIM_CHECK_SIZE(typ, sz) +#endif From fa86571448ea89143ca78576c8248bc02ad056bd Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 3 Nov 2016 22:30:00 +0800 Subject: [PATCH 2/3] abi check: prefer nim constant to enable, document --- compiler/ccgtypes.nim | 2 +- doc/nimc.rst | 4 ++++ lib/nimbase.h | 8 ++------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 0327d9b82e..a9c27217a4 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -703,7 +703,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = else: getTupleDesc(m, t, result, check) if not isImportedType(t): add(m.s[cfsTypes], recdesc) - elif tfIncompleteStruct notin t.flags: + elif tfIncompleteStruct notin t.flags and isDefined("checkabi"): addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [result, rope(getSize(t))]) of tySet: result = getTypeName(t.lastSon) & "Set" diff --git a/doc/nimc.rst b/doc/nimc.rst index eb1beb549f..5d9ed03ab6 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -258,6 +258,10 @@ Define Effect ``ssl`` Enables OpenSSL support for the sockets module. ``memProfiler`` Enables memory profiling for the native GC. ``uClibc`` Use uClibc instead of libc. (Relevant for Unix-like OSes) +``checkAbi`` When using types from C headers, add checks that compare + what's in the Nim file with what's in the C header + (requires a C compiler with _Static_assert support, like + any C11 compiler) ================== ========================================================= diff --git a/lib/nimbase.h b/lib/nimbase.h index a75016ed74..818bff462b 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -460,10 +460,6 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz # include #endif -/* Compile with -t:-DNIM_CHECK_ABI to enable */ -#ifdef NIM_CHECK_ABI -# define NIM_CHECK_SIZE(typ, sz) \ +/* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */ +#define NIM_CHECK_SIZE(typ, sz) \ _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") -#else -# define NIM_CHECK_SIZE(typ, sz) -#endif From fb7850a10a8dbbbbc11568fc58584af37a507386 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 3 Nov 2016 23:04:33 +0800 Subject: [PATCH 3/3] add primitive type abi check --- compiler/ccgtypes.nim | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index a9c27217a4..60ee0eaeeb 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -206,6 +206,10 @@ proc cacheGetType(tab: TIdTable, key: PType): Rope = # linear search is not necessary anymore: result = Rope(idTableGet(tab, key)) +proc addAbiCheck(m: BModule, t: PType, name: Rope) = + if isDefined("checkabi"): + addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))]) + proc getTempName(m: BModule): Rope = result = m.tmpBase & rope(m.labels) inc m.labels @@ -267,6 +271,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = result = getSimpleTypeDesc(m, lastSon typ) else: result = nil + if result != nil and typ.isImportedType(): + if cacheGetType(m.typeCache, typ) == nil: + idTablePut(m.typeCache, typ, result) + addAbiCheck(m, typ, result) + proc pushType(m: BModule, typ: PType) = add(m.typeStack, typ) @@ -656,6 +665,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = let foo = getTypeDescAux(m, t.sons[1], check) addf(m.s[cfsTypes], "typedef $1 $2[$3];$n", [foo, result, rope(n)]) + else: addAbiCheck(m, t, result) of tyObject, tyTuple: if isImportedCppType(t) and typ.kind == tyGenericInst: # for instantiated templates we do not go through the type cache as the @@ -703,8 +713,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = else: getTupleDesc(m, t, result, check) if not isImportedType(t): add(m.s[cfsTypes], recdesc) - elif tfIncompleteStruct notin t.flags and isDefined("checkabi"): - addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [result, rope(getSize(t))]) + elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result) of tySet: result = getTypeName(t.lastSon) & "Set" idTablePut(m.typeCache, t, result)