Skip to content

Commit

Permalink
Merge pull request #4429 from larsewi/CFE-2686
Browse files Browse the repository at this point in the history
CFE-2686: Policy function format() no longer truncates strings lager than 4KiB
  • Loading branch information
olehermanse authored Dec 17, 2020
2 parents 368d737 + 0043008 commit 7c3ba84
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 26 deletions.
40 changes: 14 additions & 26 deletions libpromises/evalfunction.c
Original file line number Diff line number Diff line change
Expand Up @@ -5334,9 +5334,7 @@ static FnCallResult FnCallSort(EvalContext *ctx, ARG_UNUSED const Policy *policy

static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs)
{
char id[CF_BUFSIZE];

snprintf(id, CF_BUFSIZE, "built-in FnCall %s-arg", fp->name);
const char *const id = "built-in FnCall format-arg";

/* We need to check all the arguments, ArgTemplate does not check varadic functions */
for (const Rlist *arg = finalargs; arg; arg = arg->next)
Expand All @@ -5348,14 +5346,14 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
}
}

if (!finalargs)
if (finalargs == NULL)
{
return FnFailure();
}

char *format = RlistScalarValue(finalargs);

if (!format)
if (format == NULL)
{
return FnFailure();
}
Expand All @@ -5366,12 +5364,12 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
char check_buffer[CF_BUFSIZE];
Buffer *buf = BufferNew();

if (check)
if (check != NULL)
{
BufferAppend(buf, format, check - format);
Seq *s;

while (check &&
while (check != NULL &&
(s = StringMatchCaptures("^(%%|%[^diouxXeEfFgGaAcsCSpnm%]*?[diouxXeEfFgGaAcsCSpnm])([^%]*)(.*)$", check, false)))
{
{
Expand All @@ -5385,7 +5383,7 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
{
// "%%" in format string
}
else if (rp)
else if (rp != NULL)
{
data = RlistScalarValue(rp);
rp = rp->next;
Expand All @@ -5401,8 +5399,6 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
char piece[CF_BUFSIZE];
memset(piece, 0, CF_BUFSIZE);

// CfOut(OUTPUT_LEVEL_INFORM, "", "format: processing format piece = '%s' with data '%s'", format_piece, percent ? "%" : data);

const char bad_modifiers[] = "hLqjzt";
const size_t length = strlen(bad_modifiers);
for (int b = 0; b < length; b++)
Expand All @@ -5418,43 +5414,38 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
}
}

if (strrchr(format_piece, 'd') || strrchr(format_piece, 'o') || strrchr(format_piece, 'x'))
if (strrchr(format_piece, 'd') != NULL || strrchr(format_piece, 'o') != NULL || strrchr(format_piece, 'x') != NULL)
{
long x = 0;
sscanf(data, "%ld%s", &x, piece); // we don't care about the remainder and will overwrite it
snprintf(piece, CF_BUFSIZE, format_piece, x);
BufferAppend(buf, piece, strlen(piece));
// CfOut(OUTPUT_LEVEL_INFORM, "", "format: appending int format piece = '%s' with data '%s'", format_piece, data);
}
else if (percent)
{
// "%%" -> "%"
BufferAppend(buf, "%", 1);
// CfOut(OUTPUT_LEVEL_INFORM, "", "format: appending int format piece = '%s' with data '%s'", format_piece, data);
}
else if (strrchr(format_piece, 'f'))
else if (strrchr(format_piece, 'f') != NULL)
{
double x = 0;
sscanf(data, "%lf%s", &x, piece); // we don't care about the remainder and will overwrite it
snprintf(piece, CF_BUFSIZE, format_piece, x);
BufferAppend(buf, piece, strlen(piece));
// CfOut(OUTPUT_LEVEL_INFORM, "", "format: appending float format piece = '%s' with data '%s'", format_piece, data);
}
else if (strrchr(format_piece, 's'))
else if (strrchr(format_piece, 's') != NULL)
{
snprintf(piece, CF_BUFSIZE, format_piece, data);
BufferAppend(buf, piece, strlen(piece));
// CfOut(OUTPUT_LEVEL_INFORM, "", "format: appending string format piece = '%s' with data '%s'", format_piece, data);
BufferAppendF(buf, format_piece, data);
}
else if (strrchr(format_piece, 'S'))
else if (strrchr(format_piece, 'S') != NULL)
{
char *found_format_spec = NULL;
char format_rewrite[CF_BUFSIZE];

strlcpy(format_rewrite, format_piece, CF_BUFSIZE);
found_format_spec = strrchr(format_rewrite, 'S');

if (found_format_spec)
if (found_format_spec != NULL)
{
*found_format_spec = 's';
}
Expand All @@ -5473,9 +5464,8 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
{
Writer *w = StringWriter();
JsonWriteCompact(w, value);
snprintf(piece, CF_BUFSIZE, format_rewrite, StringWriterData(w));
BufferAppendF(buf, format_rewrite, StringWriterData(w));
WriterClose(w);
BufferAppend(buf, piece, strlen(piece));
}
else // it might be a list reference
{
Expand All @@ -5498,9 +5488,8 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
}
WriterWrite(w, " }");

snprintf(piece, CF_BUFSIZE, format_rewrite, StringWriterData(w));
BufferAppendF(buf, format_rewrite, StringWriterData(w));
WriterClose(w);
BufferAppend(buf, piece, strlen(piece));
}
else // whatever this is, it's not a list reference or a data container
{
Expand All @@ -5516,7 +5505,6 @@ static FnCallResult FnCallFormat(EvalContext *ctx, ARG_UNUSED const Policy *poli
{
char error[] = "(unhandled format)";
BufferAppend(buf, error, strlen(error));
// CfOut(OUTPUT_LEVEL_INFORM, "", "format: error appending unhandled format piece = '%s' with data '%s'", format_piece, data);
}
}
else
Expand Down
28 changes: 28 additions & 0 deletions tests/acceptance/01_vars/02_functions/format_edge_case.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Test bug fix
# Former bug truncates strings greater than 4096 bytes
# There is no reason for format() to truncate strings

body common control
{
inputs => { "../../default.cf.sub" };
bundlesequence => { default("$(this.promise_filename)") };
version => "1.0";
}

##########################################################

bundle agent test {
vars:
"str" string => format('%s', 'Hello, everyone! This is the LONGEST TEXT EVER! I was inspired by the various other longest texts ever on the internet, and I wanted to make my own. So here it is! This is going to be a WORLD RECORD! This is actually my third attempt at doing this. The first time, I didnt save it. The second time, the Neocities editor crashed. Now Im writing this in Notepad, then copying it into the Neocities editor instead of typing it directly in the Neocities editor to avoid crashing. It sucks that my past two attempts are gone now. Those actually got pretty long. Not the longest, but still pretty long. I hope this one wont get lost somehow. Anyways, lets talk about WAFFLES! I like waffles. Waffles are cool. Waffles is a funny word. Theres a Teen Titans Go episode called Waffles where the word Waffles is said a hundred-something times. Its pretty annoying. Theres also a Teen Titans Go episode about Pig Latin. Dont know what Pig Latin is? Its a language where you take all the consonants before the first vowel, move them to the end, and add -ay to the end. If the word begins with a vowel, you just add -way to the end. For example, Waffles becomes Afflesway. Ive been speaking Pig Latin fluently since the fourth grade, so it surprised me when I saw the episode for the first time. I speak Pig Latin with my sister sometimes. Its pretty fun. I like speaking it in public so that everyone around us gets confused. Thats never actually happened before, but if it ever does, twill be pretty funny. By the way, twill is a word I invented recently, and its a contraction of it will. I really hope it gains popularity in the near future, because twill is WAY more fun than saying itll. Itll is too boring. Nobody likes boring. This is nowhere near being the longest text ever, but eventually it will be! I might still be writing this a decade later, who knows? But right now, its not very long. But Ill just keep writing until it is the longest! Have you ever heard the song Dau Dau by Awesome Scampis? Its an amazing song. Look it up on YouTube! I play that song all the time around my sister! It drives her crazy, and I love it. Another way I like driving my sister crazy is by speaking my own made up language to her. She hates the languages I make! The only language that we both speak besides English is Pig Latin. I think you already knew that. Whatever. I think Im gonna go for now. Bye! Hi, Im back now. Im gonna contribute more to this soon-to-be giant wall of text. I just realised I have a giant stuffed frog on my bed. I forgot his name. Im pretty sure it was something stupid though. I think it was FROG in Morse Code or something. Morse Code is cool. I know a bit of it, but Im not very good at it. Im also not very good at French. I barely know anything in French, and my pronunciation probably sucks. But Im learning it, at least. Im also learning Esperanto. Its this language that was made up by some guy a long time ago to be the universal language. A lot of people speak it. I am such a language nerd. Half of this text is probably gonna be about languages. But hey, as long as its long! Ha, get it? As LONG as its LONG? Im so funny, right? No, Im not. I should probably get some sleep. Goodnight! Hello, Im back again. I basically have only two interests nowadays: languages and furries. What? Oh, sorry, I thought you knew I was a furry. Haha, oops. Anyway, yeah, Im a furry, but since Im a young furry, I cant really do as much as I would like to do in the fandom. When Im older, I would like to have a fursuit, go to furry conventions, all that stuff. But for now I can only dream of that. Sorry you had to deal with me talking about furries, but Im honestly very desperate for this to be the longest text ever. Last night I was watching nothing but fursuit unboxings. I think I need help. This one time, me and my mom were going to go to a furry Christmas party, but we didnt end up going because of the fact that there was alcohol on the premises, and that she didnt wanna have to be a mom dragging her son through a crowd of furries. Both of those reasons were understandable. Okay, hopefully I wont have to talk about furries anymore. I dont care if youre a furry reading this right now, I just dont wanna have to torture everyone else.');
"list" slist => { $(str) };
"list_str" string => format('%S', "list");
"container" data => parsejson(' ["$(str)"] ');
"container_str" string => format('%S', "container");
}

bundle agent check {
methods:
"check" usebundle => dcs_check_state(test,
"$(this.promise_filename).expected.json",
$(this.promise_filename));
}
Loading

0 comments on commit 7c3ba84

Please sign in to comment.