[automerger skipped] Merge "Fix heap-use-after-free issue flagged by fuzzer test." into sc-qpr1-dev am: 5c3d1d4cc5 -s ours am: c22d00248f -s ours am: 300b18a3fc -s ours am: eb075b66c6 -s ours am: 1e1e3c5c3c -s ours am: b0da80826a -s ours
am skip reason: Merged-In I41dde165a5eba151c958b81417d9e1065af1b411 with SHA-1 73d89318a6 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/av/+/24303956
Change-Id: I34bd1bccaee41461a38cda7f38b96b210d9dd7d7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index d865ab2..721a12a 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -69,7 +69,7 @@
addParameter(
DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
.withDefault(new C2StreamChannelCountInfo::input(0u, 1))
- .withFields({C2F(mChannelCount, value).inRange(1, 6)})
+ .withFields({C2F(mChannelCount, value).inRange(1, kMaxChannelCount)})
.withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
.build());
@@ -198,10 +198,17 @@
}
c2_status_t C2SoftAacEnc::onFlush_sm() {
+ if (mAACEncoder != nullptr) {
+ /* encoder's internal input buffer needs to be reset during flush */
+ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CONTROL_STATE, AACENC_INIT_ALL)) {
+ ALOGE("Failed to reset AAC encoder");
+ }
+ }
mSentCodecSpecificData = false;
mInputSize = 0u;
mNextFrameTimestampUs.reset();
mLastFrameEndTimestampUs.reset();
+ mRemainderLen = 0;
return C2_OK;
}
@@ -562,6 +569,11 @@
inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
inargs.numInSamples -= outargs.numInSamples;
}
+ } else {
+ // In case of error in encode call, discard remaining input bytes.
+ inBuffer[0] = nullptr;
+ inBufferSize[0] = 0;
+ inargs.numInSamples = 0;
}
ALOGV("encoderErr = %d mInputSize = %zu "
"inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
@@ -597,10 +609,19 @@
&outBufDesc,
&inargs,
&outargs);
+
+ // after flush, discard remaining input bytes.
+ inBuffer[0] = nullptr;
inBufferSize[0] = 0;
}
if (inBufferSize[0] > 0) {
+ if (inBufferSize[0] > kRemainderBufSize) {
+ ALOGE("Remaining bytes %d greater than remainder buffer size %zu", inBufferSize[0],
+ kRemainderBufSize);
+ work->result = C2_CORRUPTED;
+ return;
+ }
for (size_t i = 0; i < inBufferSize[0]; ++i) {
mRemainder[i] = static_cast<uint8_t *>(inBuffer[0])[i];
}
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 9a28280..c79526c 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -47,6 +47,9 @@
const std::shared_ptr<C2BlockPool> &pool) override;
private:
+ static constexpr size_t kMaxChannelCount = 6;
+ static constexpr size_t kRemainderBufSize = kMaxChannelCount * sizeof(int16_t);
+
std::shared_ptr<IntfImpl> mIntf;
HANDLE_AACENCODER mAACEncoder;
@@ -63,7 +66,7 @@
std::atomic_uint64_t mOutIndex;
// We support max 6 channels
- uint8_t mRemainder[6 * sizeof(int16_t)];
+ uint8_t mRemainder[kRemainderBufSize];
size_t mRemainderLen;
status_t initEncoder();
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index 182edfb..591d56d 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -188,12 +188,6 @@
return onStop();
}
-static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
-}
-
void C2SoftFlacEnc::process(
const std::unique_ptr<C2Work> &work,
const std::shared_ptr<C2BlockPool> &pool) {
@@ -245,12 +239,10 @@
mWroteHeader = true;
}
- const uint32_t sampleRate = mIntf->getSampleRate();
const uint32_t channelCount = mIntf->getChannelCount();
const bool inputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
const unsigned sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
const unsigned frameSize = channelCount * sampleSize;
- const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
size_t outCapacity = inSize;
outCapacity += mBlockSize * frameSize;
@@ -270,6 +262,33 @@
return;
}
+ class FillWork {
+ public:
+ FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
+ const std::shared_ptr<C2Buffer> &buffer)
+ : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
+ ~FillWork() = default;
+
+ void operator()(const std::unique_ptr<C2Work> &work) {
+ work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
+ work->worklets.front()->output.buffers.clear();
+ work->worklets.front()->output.ordinal = mOrdinal;
+ work->workletsProcessed = 1u;
+ work->result = C2_OK;
+ if (mBuffer) {
+ work->worklets.front()->output.buffers.push_back(mBuffer);
+ }
+ ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
+ mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
+ mBuffer ? "" : "o");
+ }
+
+ private:
+ const uint32_t mFlags;
+ const C2WorkOrdinalStruct mOrdinal;
+ const std::shared_ptr<C2Buffer> mBuffer;
+ };
+
mEncoderWriteData = true;
mEncoderReturnedNbBytes = 0;
size_t inPos = 0;
@@ -308,14 +327,33 @@
mOutputBlock.reset();
return;
}
- fillEmptyWork(work);
- if (mEncoderReturnedNbBytes != 0) {
- std::shared_ptr<C2Buffer> buffer = createLinearBuffer(std::move(mOutputBlock), 0, mEncoderReturnedNbBytes);
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
- } else {
- ALOGV("encoder process_interleaved returned without data to write");
+
+ // cloneAndSend will create clone of work when more than one encoded frame is produced
+ while (mOutputBuffers.size() > 1) {
+ const OutputBuffer& front = mOutputBuffers.front();
+ C2WorkOrdinalStruct ordinal = work->input.ordinal;
+ ordinal.frameIndex = front.frameIndex;
+ ordinal.timestamp = front.timestampUs;
+ cloneAndSend(work->input.ordinal.frameIndex.peeku(), work,
+ FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer));
+ mOutputBuffers.pop_front();
}
+
+ std::shared_ptr<C2Buffer> buffer;
+ C2WorkOrdinalStruct ordinal = work->input.ordinal;
+ if (mOutputBuffers.size() == 1) {
+ const OutputBuffer& front = mOutputBuffers.front();
+ ordinal.frameIndex = front.frameIndex;
+ ordinal.timestamp = front.timestampUs;
+ buffer = front.buffer;
+ mOutputBuffers.pop_front();
+ }
+ // finish the response for the overall transaction.
+ // this includes any final frame that the encoder produced during this request
+ // this response is required even if no data was encoded.
+ FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0),
+ ordinal, buffer)(work);
+
mOutputBlock = nullptr;
if (eos) {
mSignalledOutputEos = true;
@@ -349,6 +387,8 @@
// write encoded data
C2WriteView wView = mOutputBlock->map().get();
uint8_t* outData = wView.data();
+ const uint32_t sampleRate = mIntf->getSampleRate();
+ const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
ALOGV("writing %zu bytes of encoded data on output", bytes);
// increment mProcessedSamples to maintain audio synchronization during
// play back
@@ -359,7 +399,12 @@
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
memcpy(outData + mEncoderReturnedNbBytes, buffer, bytes);
+
+ std::shared_ptr<C2Buffer> c2Buffer =
+ createLinearBuffer(mOutputBlock, mEncoderReturnedNbBytes, bytes);
+ mOutputBuffers.push_back({c2Buffer, mAnchorTimeStamp + outTimeStamp, current_frame});
mEncoderReturnedNbBytes += bytes;
+
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.h b/media/codec2/components/flac/C2SoftFlacEnc.h
index b3f01d5..a971ab5 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.h
+++ b/media/codec2/components/flac/C2SoftFlacEnc.h
@@ -79,6 +79,12 @@
unsigned mHeaderOffset;
bool mWroteHeader;
char mHeader[FLAC_HEADER_SIZE];
+ struct OutputBuffer {
+ std::shared_ptr<C2Buffer> buffer;
+ c2_cntr64_t timestampUs;
+ std::uint64_t frameIndex;
+ };
+ std::list<OutputBuffer> mOutputBuffers;
C2_DO_NOT_COPY(C2SoftFlacEnc);
};
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 3e4247b..d9c5d29 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -773,6 +773,14 @@
return false;
}
+ if (buffer->bitdepth > 10) {
+ ALOGE("bitdepth %d is not supported", buffer->bitdepth);
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return false;
+ }
+
const int width = buffer->displayed_width[0];
const int height = buffer->displayed_height[0];
if (width != mWidth || height != mHeight) {
diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
index bb6c1b8..43533fd 100644
--- a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
@@ -31,11 +31,19 @@
namespace android {
-bool isAtLeastT() {
+
+static bool isAtLeast(int version, const char *codeName) {
char deviceCodeName[PROP_VALUE_MAX];
__system_property_get("ro.build.version.codename", deviceCodeName);
- return android_get_device_api_level() >= __ANDROID_API_T__ ||
- !strcmp(deviceCodeName, "Tiramisu");
+ return android_get_device_api_level() >= version || !strcmp(deviceCodeName, codeName);
+}
+
+bool isAtLeastT() {
+ return isAtLeast(__ANDROID_API_T__, "Tiramisu");
+}
+
+bool isAtLeastU() {
+ return isAtLeast(__ANDROID_API_U__, "UpsideDownCake");
}
static bool isP010Allowed() {
@@ -83,7 +91,7 @@
}
// Default scenario --- the consumer is display or GPU
- const AHardwareBuffer_Desc desc = {
+ const AHardwareBuffer_Desc consumableForDisplayOrGpu = {
.width = 320,
.height = 240,
.format = format,
@@ -98,7 +106,7 @@
};
// The consumer is a HW encoder
- const AHardwareBuffer_Desc descHwEncoder = {
+ const AHardwareBuffer_Desc consumableForHwEncoder = {
.width = 320,
.height = 240,
.format = format,
@@ -114,7 +122,7 @@
};
// The consumer is a SW encoder
- const AHardwareBuffer_Desc descSwEncoder = {
+ const AHardwareBuffer_Desc consumableForSwEncoder = {
.width = 320,
.height = 240,
.format = format,
@@ -127,10 +135,16 @@
.rfu0 = 0,
.rfu1 = 0,
};
-
- return AHardwareBuffer_isSupported(&desc)
- && AHardwareBuffer_isSupported(&descHwEncoder)
- && AHardwareBuffer_isSupported(&descSwEncoder);
+ // Some devices running versions prior to Android U aren't guaranteed to advertise support
+ // for some color formats when the consumer is an encoder. Hence limit these checks to
+ // Android U and beyond.
+ if (isAtLeastU()) {
+ return AHardwareBuffer_isSupported(&consumableForDisplayOrGpu)
+ && AHardwareBuffer_isSupported(&consumableForHwEncoder)
+ && AHardwareBuffer_isSupported(&consumableForSwEncoder);
+ } else {
+ return AHardwareBuffer_isSupported(&consumableForDisplayOrGpu);
+ }
}
} // namespace android
diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.h b/media/codec2/sfplugin/utils/Codec2CommonUtils.h
index 98dd65b..9bb52bd 100644
--- a/media/codec2/sfplugin/utils/Codec2CommonUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.h
@@ -23,6 +23,8 @@
bool isAtLeastT();
+bool isAtLeastU();
+
bool isVendorApiOrFirstApiAtLeastT();
/**