Fix undefined behaviors caught by ubsan
This fixes a couple of integer overflows in parsing as well as removes the construction of a null reference that never got dereferenced. This also initializes the bool members in TCall Finally, this adds a UBSAN run alongside ASAN and TSAN in CI.
This commit is contained in:
parent
702026e3f5
commit
48eaea60b8
5 changed files with 14 additions and 5 deletions
6
.github/workflows/continuous_integration.yml
vendored
6
.github/workflows/continuous_integration.yml
vendored
|
|
@ -51,7 +51,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
compiler: [{cc: gcc, cxx: g++}]
|
compiler: [{cc: gcc, cxx: g++}]
|
||||||
cmake_build_type: [Debug]
|
cmake_build_type: [Debug]
|
||||||
flags: ['-fsanitize=address', '-fsanitize=thread']
|
flags: ['-fsanitize=address', '-fsanitize=thread', '-fsanitize=undefined']
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
- uses: lukka/get-cmake@983956e4a5edce90f0dfcc38c1543077e668402b # v3.30.0
|
- uses: lukka/get-cmake@983956e4a5edce90f0dfcc38c1543077e668402b # v3.30.0
|
||||||
|
|
@ -82,8 +82,12 @@ jobs:
|
||||||
- name: Install
|
- name: Install
|
||||||
run: cmake --install build --prefix build/install
|
run: cmake --install build --prefix build/install
|
||||||
- name: Test
|
- name: Test
|
||||||
|
env:
|
||||||
|
UBSAN_OPTIONS: 'halt_on_error=1:print_stacktrace=1'
|
||||||
run: ctest --output-on-failure --test-dir build
|
run: ctest --output-on-failure --test-dir build
|
||||||
- name: Test (standalone)
|
- name: Test (standalone)
|
||||||
|
env:
|
||||||
|
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
|
||||||
run: cd Test && ./runtests
|
run: cd Test && ./runtests
|
||||||
|
|
||||||
# Ensure we can compile/run on an older distro
|
# Ensure we can compile/run on an older distro
|
||||||
|
|
|
||||||
|
|
@ -6059,7 +6059,7 @@ void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fn
|
||||||
unaryArg = callNode.getAsUnaryNode()->getOperand();
|
unaryArg = callNode.getAsUnaryNode()->getOperand();
|
||||||
arg0 = unaryArg;
|
arg0 = unaryArg;
|
||||||
}
|
}
|
||||||
const TIntermSequence& aggArgs = *argp; // only valid when unaryArg is nullptr
|
const TIntermSequence& aggArgs = argp ? *argp : TIntermSequence(); // only valid when unaryArg is nullptr
|
||||||
|
|
||||||
switch (callNode.getOp()) {
|
switch (callNode.getOp()) {
|
||||||
case EOpTextureGather:
|
case EOpTextureGather:
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,11 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
|
||||||
case EbtUint8: newConstArray[i].setU8Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU8Const()))); break;
|
case EbtUint8: newConstArray[i].setU8Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU8Const()))); break;
|
||||||
case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break;
|
case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break;
|
||||||
case EbtUint16:newConstArray[i].setU16Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU16Const()))); break;
|
case EbtUint16:newConstArray[i].setU16Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU16Const()))); break;
|
||||||
case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
|
case EbtInt64: {
|
||||||
|
int64_t i64val = unionArray[i].getI64Const();
|
||||||
|
newConstArray[i].setI64Const(i64val == INT64_MIN ? INT64_MIN : -i64val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned long long>(-static_cast<long long>(unionArray[i].getU64Const()))); break;
|
case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned long long>(-static_cast<long long>(unionArray[i].getU64Const()))); break;
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,8 @@ private:
|
||||||
// A "call" is a pair: <caller, callee>.
|
// A "call" is a pair: <caller, callee>.
|
||||||
// There can be duplicates. General assumption is the list is small.
|
// There can be duplicates. General assumption is the list is small.
|
||||||
struct TCall {
|
struct TCall {
|
||||||
TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
|
TCall(const TString& pCaller, const TString& pCallee)
|
||||||
|
: caller(pCaller), callee(pCallee), visited(false), currentPath(false), errorGiven(false) { }
|
||||||
TString caller;
|
TString caller;
|
||||||
TString callee;
|
TString callee;
|
||||||
bool visited;
|
bool visited;
|
||||||
|
|
|
||||||
|
|
@ -374,7 +374,7 @@ namespace {
|
||||||
int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; }
|
int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; }
|
||||||
int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; }
|
int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; }
|
||||||
int op_pos(int a) { return a; }
|
int op_pos(int a) { return a; }
|
||||||
int op_neg(int a) { return -a; }
|
int op_neg(int a) { return a == INT_MIN ? INT_MIN : -a; }
|
||||||
int op_cmpl(int a) { return ~a; }
|
int op_cmpl(int a) { return ~a; }
|
||||||
int op_not(int a) { return !a; }
|
int op_not(int a) { return !a; }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue