Boundary checks for rsAllocationCopy[12]DRange Performs the following checks: * On X and Y ranges * On the given LOD vs. available LODs * On expected vs. given dimensionality of rs_allocations Report error using setError() under all context types while only Debug Context requires so. Some implementations call rsrAllocationCopy[12]DRange directly, bypassing top-level rsAllocationCopy[12]DRange. Thus the boundary checks are placed at rsr level for now. Bug: http://b/19800472 Test: cts RenderscriptTest and RsTest for angler_aosp-eng Change-Id: I5c57cee5ed106e8f594f04abfc27a4e127d56a69
diff --git a/rsScriptC_Lib.cpp b/rsScriptC_Lib.cpp index b460031..c00015a 100644 --- a/rsScriptC_Lib.cpp +++ b/rsScriptC_Lib.cpp
@@ -26,6 +26,7 @@ #endif #include <time.h> +#include <sstream> using namespace android; using namespace android::renderscript; @@ -253,12 +254,80 @@ a->syncAll(rsc, usage); } +// Helper for validateCopyArgs() - initialize the error message; only called on +// infrequently executed paths +static void initializeErrorMsg(std::stringstream &ss, int expectDim, bool isSrc) { + ss << (expectDim == 1 ? "rsAllocationCopy1DRange" : "rsAllocationCopy2DRange") << ": "; + ss << (isSrc? "source" : "destination") << " "; +} + +// We are doing the check even in a non-debug context, which is permissible because in that case +// a failed bound check results in unspecified behavior. +static bool validateCopyArgs(Context *rsc, bool isSrc, uint32_t expectDim, + const Allocation *alloc, uint32_t xoff, uint32_t yoff, + uint32_t lod, uint32_t w, uint32_t h) { + std::stringstream ss; + + if (lod >= alloc->mHal.drvState.lodCount) { + initializeErrorMsg(ss, expectDim, isSrc); + ss << "Mip level out of range: "; + ss << lod << " >= " << alloc->mHal.drvState.lodCount; + rsc->setError(RS_ERROR_FATAL_DEBUG, ss.str().c_str()); + return false; + } + + const uint32_t allocDimX = alloc->mHal.drvState.lod[lod].dimX; + + // Check both in case xoff + w overflows + if (xoff >= allocDimX || (xoff + w) > allocDimX) { + initializeErrorMsg(ss, expectDim, isSrc); + ss << "X range: "; + ss << "[" << xoff << ", " << xoff + w << ") outside "; + ss << "[0, " << allocDimX << ")"; + rsc->setError(RS_ERROR_FATAL_DEBUG, ss.str().c_str()); + return false; + } + + const uint32_t allocDimY = alloc->mHal.drvState.lod[lod].dimY; + + if (expectDim > 1) { + if (allocDimY == 0) { // Copy2D was given an allocation of 1D + initializeErrorMsg(ss, expectDim, isSrc); + ss << "dimensionality invalid: expected 2D; given 1D rs_allocation"; + rsc->setError(RS_ERROR_FATAL_DEBUG, ss.str().c_str()); + return false; + } + // Check both in case yoff + h overflows + if (yoff >= allocDimY || (yoff + h) > allocDimY) { + initializeErrorMsg(ss, expectDim, isSrc); + ss << "Y range: "; + ss << "[" << yoff << ", " << yoff + h << ") outside "; + ss << "[0, " << allocDimY << ")"; + rsc->setError(RS_ERROR_FATAL_DEBUG, ss.str().c_str()); + return false; + } + } else { + if (allocDimY != 0) { // Copy1D was given an allocation of 2D + initializeErrorMsg(ss, expectDim, isSrc); + ss << "dimensionality invalid: expected 1D; given 2D rs_allocation"; + rsc->setError(RS_ERROR_FATAL_DEBUG, ss.str().c_str()); + return false; + } + } + + return true; +} + void rsrAllocationCopy1DRange(Context *rsc, Allocation *dstAlloc, uint32_t dstOff, uint32_t dstMip, uint32_t count, Allocation *srcAlloc, uint32_t srcOff, uint32_t srcMip) { + if (!validateCopyArgs(rsc, false, 1, dstAlloc, dstOff, 0, dstMip, count, 1) || + !validateCopyArgs(rsc, true, 1, srcAlloc, srcOff, 0, srcMip, count, 1)) { + return; + } rsi_AllocationCopy2DRange(rsc, dstAlloc, dstOff, 0, dstMip, 0, count, 1, srcAlloc, srcOff, 0, srcMip, 0); @@ -271,6 +340,11 @@ Allocation *srcAlloc, uint32_t srcXoff, uint32_t srcYoff, uint32_t srcMip, uint32_t srcFace) { + if (!validateCopyArgs(rsc, false, 2, dstAlloc, dstXoff, dstYoff, dstMip, width, height) || + !validateCopyArgs(rsc, true, 2, srcAlloc, srcXoff, srcYoff, srcMip, width, height)) { + return; + } + rsi_AllocationCopy2DRange(rsc, dstAlloc, dstXoff, dstYoff, dstMip, dstFace, width, height, srcAlloc, srcXoff, srcYoff, srcMip, srcFace);