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 | 29x 16x 29x 1073x 973x 100x 100x 6x 6x 94x 100x 100x 105x 105x 105x 103x 100x 29x 1065x 1052x 13x 13x 13x 13x 104x 104x 104x 89x 15x 15x 12x 15x 4x 13x 29x | /**
* 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 CodeGenState from "../../../../state/CodeGenState";
/**
* 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.
CodeGenState.requireToolchain("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;
};
// Export as an object for consistent module pattern
const helperGenerators = {
generateOverflowHelpers,
generateSafeDivHelpers,
};
export default helperGenerators;
|