Hi community, I‘m studying TVM and its low-level operators recently. These days I tried to construct some simple loops, and I found an undefined behavior may occur if we cast string to a boolean value.
As listed below, I cast string to bool as the condition of a While loop, I found it will crash if I build the module several times.
import tvm
from tvm import tir
v = tir.Cast('bool', tvm.runtime.convert("a"))
body = tir.stmt.While(v, body=tir.Evaluate(tir.const(0)))
func = tir.PrimFunc(params={}, body=body)
mod = tvm.lower(func)
nopt_mod = tvm.build(mod)
nopt_mod = tvm.build(mod)
I build the latest TVM on my server, with Ubuntu 18.04 and llvm-12, after executing my code, I got such a crash message:
(tvm-build) ➜ ~ python3 cast_str.py
[1] 33220 segmentation fault (core dumped) python3 cast_str.py
To find the root cause, I read the source and found the function CodeGenLLVM::CreateCast
doesn’t consider the case casting from handle to int. If to.is_uint() && to.bits() == 1
exists and from
is not float number, it will be treated as an Int type.
Since we pass StringImm
, whose dtype
is handle
, as the original type, it will be treated as an int and finally cause undefined behavior, like such crash.
llvm::Value* CodeGenLLVM::CreateCast(DataType from, DataType to, llvm::Value* value) {
llvm::Type* target = DTypeToLLVMType(to);
if (value->getType() == target) return value;
if (to.is_handle()) {
return builder_->CreateBitCast(value, target);
} else if (to.is_uint() && to.bits() == 1) {
if (from.is_float()) {
llvm::Constant* zero = llvm::ConstantFP::get(DTypeToLLVMType(from), 0.);
return builder_->CreateFCmpONE(value, zero);
} else {
llvm::Constant* zero = llvm::ConstantInt::get(DTypeToLLVMType(from), 0);
return builder_->CreateICmpNE(value, zero);
}
} else if (!from.is_float() && !to.is_float()) {
return builder_->CreateIntCast(value, target, from.is_int());
} else if (from.is_float() && to.is_int()) {
return builder_->CreateFPToSI(value, target);
} else if (from.is_float() && to.is_uint()) {
if (to.bits() < 8) {
value = builder_->CreateFPToUI(value, DTypeToLLVMType(to.with_bits(8)));
return builder_->CreateIntCast(value, target, false);
} else {
return builder_->CreateFPToUI(value, target);
}
} else if (from.is_int() && to.is_float()) {
return builder_->CreateSIToFP(value, target);
} else if (from.is_uint() && to.is_float()) {
return builder_->CreateUIToFP(value, target);
} else {
ICHECK(from.is_float() && to.is_float());
return builder_->CreateFPCast(value, target);
}
}
I’m curious whether casting string to boolean is a legal behavior in TVM, if yes, how can we fix this bug? Or if not, it will be better if we provide some tips to developers to prevent it. I would be grateful if anyone can help me