aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvan Haas <evan@lagerdata.com>2022-09-08 20:19:10 -0700
committerVeikka Tuominen <git@vexu.eu>2022-09-10 01:50:17 +0300
commit8e631ee3e7b4e7b4466c0efafaffb4151447785f (patch)
tree1873bad537882c07d240b8ceed55e0221f81705c /src
parent9e070b653c89a9216f9dd9f78ed7c78c11460ac7 (diff)
downloadzig-8e631ee3e7b4e7b4466c0efafaffb4151447785f.tar.gz
zig-8e631ee3e7b4e7b4466c0efafaffb4151447785f.zip
translate-c: Escape non-ASCII characters that appear in macros
Macro definitions are simply a slice of bytes, which may not be UTF-8 encoded. If they are not UTF-8 encoded, escape non-printable and non-ASCII characters as `\xNN`. Fixes #12784
Diffstat (limited to 'src')
-rw-r--r--src/translate_c.zig20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 014f6b1934..f969bf1c8b 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -5957,20 +5957,36 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
return bytes[0..i];
}
+/// non-ASCII characters (c > 127) are also treated as non-printable by fmtSliceEscapeLower.
+/// If a C string literal or char literal in a macro is not valid UTF-8, we need to escape
+/// non-ASCII characters so that the Zig source we output will itself be UTF-8.
+fn escapeUnprintables(ctx: *Context, m: *MacroCtx) ![]const u8 {
+ const zigified = try zigifyEscapeSequences(ctx, m);
+ if (std.unicode.utf8ValidateSlice(zigified)) return zigified;
+
+ const formatter = std.fmt.fmtSliceEscapeLower(zigified);
+ const encoded_size = @intCast(usize, std.fmt.count("{s}", .{formatter}));
+ var output = try ctx.arena.alloc(u8, encoded_size);
+ return std.fmt.bufPrint(output, "{s}", .{formatter}) catch |err| switch (err) {
+ error.NoSpaceLeft => unreachable,
+ else => |e| return e,
+ };
+}
+
fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
const tok = m.next().?;
const slice = m.slice();
switch (tok) {
.CharLiteral => {
if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
- return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
+ return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
} else {
const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});
return Tag.integer_literal.create(c.arena, str);
}
},
.StringLiteral => {
- return Tag.string_literal.create(c.arena, try zigifyEscapeSequences(c, m));
+ return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));
},
.IntegerLiteral, .FloatLiteral => {
return parseCNumLit(c, m);