Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | 47x 16x 47x 1250x 1093x 157x 157x 6x 6x 151x 157x 157x 166x 166x 166x 164x 157x 47x 1242x 1229x 13x 13x 13x 13x 104x 104x 104x 89x 15x 15x 12x 15x 4x 13x 47x 1232x 2x 9x 2x 2x 3x 3x 3x 3x 3x 2x 47x | /**
* Helper function generators for overflow-safe arithmetic and safe division.
* Extracted from CodeGenerator.ts.
*
* Portability note: Uses __builtin_add_overflow, __builtin_sub_overflow, and
* __builtin_mul_overflow intrinsics (GCC 5+, Clang 3.4+). C-Next targets embedded
* systems using arm-none-eabi-gcc, so these are available. MSVC is not supported.
*
* Issue #707: Refactored to use OverflowHelperTemplates for reduced duplication.
*/
import TYPE_MAP from "../../types/TYPE_MAP";
import OverflowHelperTemplates from "./OverflowHelperTemplates";
import SaturatingCast from "../../helpers/SaturatingCast";
import CppModeHelper from "../../helpers/CppModeHelper";
import ReservedCnxName from "../../../../../utils/ReservedCnxName";
import ToolchainRequirements from "../../../../../instrumentation/ToolchainRequirements";
/**
* Generate a safe arithmetic helper function (div or mod).
* Extracted to eliminate duplication between safe_div and safe_mod generation.
*/
const generateSafeArithmeticHelper = (
opName: string,
opSymbol: string,
cnxType: string,
cType: string,
): string[] => [
`static inline bool cnx_safe_${opName}_${cnxType}(${cType}* output, ${cType} numerator, ${cType} divisor, ${cType} defaultValue) {`,
` if (divisor == 0) {`,
` *output = defaultValue;`,
` return true; // Error occurred`,
` }`,
` *output = numerator ${opSymbol} divisor;`,
` return false; // Success`,
`}`,
"",
];
/**
* Generate all needed overflow helper functions
* ADR-044: Overflow helper functions with clamping or panic behavior
*/
const generateOverflowHelpers = (
usedClampOps: ReadonlySet<string>,
debugMode: boolean,
): string[] => {
if (usedClampOps.size === 0) {
return [];
}
const lines: string[] = [];
if (debugMode) {
// Issue #1143: this branch, and only this branch, pulls in a hosted libc.
// Release-mode clamp helpers are freestanding-safe, so the requirement is
// recorded here rather than wherever a clamp op happens to be registered.
ToolchainRequirements.record("overflow-panic-hosted-libc");
lines.push(
"// ADR-044: Debug overflow helper functions (panic on overflow)",
"#include <limits.h>",
"#include <stdio.h>",
"#include <stdlib.h>",
"",
"/* ADR-044 / Issue #94: the second parameter is the WIDER type, not the value type.",
" Narrowing it first would let an out-of-range operand truncate INTO range and defeat",
" the check: cnx_clamp_add_u8(0, 256) must saturate to 255, but (uint8_t)256 is 0, so a",
" uint8_t parameter would return 0 -- the opposite of saturation. */",
"",
);
} else {
lines.push(
"// ADR-044: Overflow helper functions",
"#include <limits.h>",
"",
"/* ADR-044 / Issue #94: the second parameter is the WIDER type, not the value type.",
" Narrowing it first would let an out-of-range operand truncate INTO range and defeat",
" the check: cnx_clamp_add_u8(0, 256) must saturate to 255, but (uint8_t)256 is 0, so a",
" uint8_t parameter would return 0 -- the opposite of saturation. */",
"",
);
}
// Sort for deterministic output
const sortedOps = Array.from(usedClampOps).sort((a, b) => a.localeCompare(b));
for (const op of sortedOps) {
const [operation, cnxType] = op.split("_");
const helper = debugMode
? OverflowHelperTemplates.generatePanicHelper(operation, cnxType)
: OverflowHelperTemplates.generateClampHelper(operation, cnxType);
if (helper) {
lines.push(helper, "");
}
}
return lines;
};
/**
* Generate safe division helper functions for used integer types only
* ADR-051: Safe division helpers that return error flag on division by zero
*/
const generateSafeDivHelpers = (
usedSafeDivOps: ReadonlySet<string>,
): string[] => {
if (usedSafeDivOps.size === 0) {
return [];
}
const lines: string[] = [];
// Issue #1108: the <stdbool.h> dependency (helpers return a bool error flag)
// is signalled via requireInclude("stdbool") when the safe-div effect is
// applied, so it flows through the single addAutoIncludes path. Emitting it
// here too would duplicate the include.
lines.push("// ADR-051: Safe division helper functions", "");
const integerTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"];
for (const cnxType of integerTypes) {
const needsDiv = usedSafeDivOps.has(`div_${cnxType}`);
const needsMod = usedSafeDivOps.has(`mod_${cnxType}`);
if (!needsDiv && !needsMod) {
continue; // Skip types that aren't used
}
const cType = TYPE_MAP[cnxType];
// Generate safe_div helper if needed
if (needsDiv) {
lines.push(...generateSafeArithmeticHelper("div", "/", cnxType, cType));
}
// Generate safe_mod helper if needed
if (needsMod) {
lines.push(...generateSafeArithmeticHelper("mod", "%", cnxType, cType));
}
}
return lines;
};
/**
* #1668: the single-evaluation saturating casts a file calls, one per
* source/target pair (`"f32_u8"`). Each body is ADR-024's bounded ternary,
* from the one shape `SaturatingCast` writes, over its parameter -- which is
* the operand, evaluated once, at the call.
*/
const generateCastHelpers = (
keys: readonly string[],
cppMode: boolean,
): string[] => {
if (keys.length === 0) return [];
const cast = (type: string, expr: string): string =>
CppModeHelper.cast(type, expr, { cppMode });
const lines: string[] = [
"/* ADR-024 / Issue #1668: a saturating float-to-integer cast whose operand has a side",
" effect -- a call, or a volatile or atomic read -- calls one of these, so the operand is",
" evaluated once. The inline bounded ternary reads its operand up to three times,",
" repeating the side effect. */",
"",
];
for (const key of keys) {
const [sourceType, targetType] = key.split("_");
const cType = TYPE_MAP[targetType];
const body = SaturatingCast.expression(
"value",
sourceType,
targetType,
cType,
cast,
);
Iif (cType === undefined || body === null) continue;
lines.push(
`static inline ${cType} ${ReservedCnxName.castHelper(sourceType, targetType)}(${SaturatingCast.floatCType(sourceType)} value) {`,
` return ${body};`,
"}",
"",
);
}
return lines;
};
// Export as an object for consistent module pattern
const helperGenerators = {
generateOverflowHelpers,
generateSafeDivHelpers,
generateCastHelpers,
};
export default helperGenerators;
|