/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
/**
* @file
*
* This file implements libfuzzer callback method.
*/
package stdx.fuzz
/**
* 1. Convert data & size to the data type of Cangjie.
* 2. Executing target function of g_fuzzer
* 3. Return the execution result.
*/
@C
@OverflowWrapping
func libfuzzerCallback(data: CPointer<UInt8>, size: UIntNative): Int32 {
let _size = Int64(size)
let cangjieData: Array<UInt8> = Array(_size, repeat: 0)
unsafe {
let ptr: CPointerHandle<UInt8> = acquireArrayRawData(cangjieData)
memcpy_s(ptr.pointer, size, data, size)
releaseArrayRawData(ptr)
}
let fuzzer: Fuzzer = g_fuzzer.getOrThrow()
var ret: Int32 = 0
try {
match (fuzzer.ftype) {
case FuncType.ArrayFunc => ret = fuzzer.arrayTargetFunc(cangjieData)
case FuncType.DataProviderFunc =>
if (fuzzer.fakeCoverage && _size > 0) {
unsafe {
// Libfuzzer will invoke callback twice, we should cheat at second invocation.
// 1st: Empty Array
// 2nd: Array with "\n" only
fuzzer.fakeCoverageArea.write(1)
}
fuzzer.fakeCoverage = false
}
try {
let dp = FuzzDataProvider.withCangjieData(cangjieData)
if (fuzzer.debugDataProvider) {
ret = fuzzer.dpTargetFunc(DebugDataProvider.wrap(dp))
} else {
ret = fuzzer.dpTargetFunc(dp)
}
} catch (e: ExhaustedException) {
if (fuzzer.dpMaxLen <= UInt32(size)) {
e.printStackTrace()
unsafe { _exit(0) }
} else {
// If the fuzz target returns -1 on a given input, libFuzzer will not add the input into the corpus.
// Required llvm15
return -1
}
}
}
} catch (e: Exception) {
// During exception reporting, atexit is temporarily used to enable libfuzzer
// to take over the service. Other signals or stop_file can be used.
report(e, cangjieData)
unsafe { exit(0) }
} catch (e: OutOfMemoryError) {
unsafe { CJ_CORE_ErrorPrintUTF8(oomString.getChars(), oomString.size(), true, true) }
unsafe { exit(0) }
} catch (e: Error) {
// During exception reporting, atexit is temporarily used to enable libfuzzer
// to take over the service. Other signals or stop_file can be used.
report(e, cangjieData)
unsafe { exit(0) }
}
return ret
}