Skip to content

Commit

Permalink
[c] int.TryParse checks overflow when C long longer than int.
Browse files Browse the repository at this point in the history
  • Loading branch information
pfusik committed Dec 10, 2024
1 parent 3a7a1ab commit 395c6ea
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 97 deletions.
57 changes: 33 additions & 24 deletions GenC.fu
Original file line number Diff line number Diff line change
Expand Up @@ -2001,6 +2001,7 @@ public class GenC : GenCCpp
WriteEnumHasFlag(obj, args, parent);
break;
case FuId.IntTryParse:
Include("limits.h");
this.IntFunctions.Add(FuId.IntTryParse);
Write("FuInt");
WriteTryParse(obj, args);
Expand Down Expand Up @@ -3488,7 +3489,7 @@ public class GenC : GenCCpp
this.CurrentMethod = null;
}

void WriteIntMaxMin!(string klassName, string method, string type, int op)
void StartLibraryMethod!(string type, string klassName, string method, string paramType)
{
WriteNewLine();
Write("static ");
Expand All @@ -3498,7 +3499,12 @@ public class GenC : GenCCpp
WriteChar('_');
Write(method);
WriteChar('(');
Write(type);
Write(paramType);
}

void WriteIntMaxMin!(string klassName, string method, string type, int op)
{
StartLibraryMethod(type, klassName, method, type);
Write(" x, ");
Write(type);
WriteLine(" y)");
Expand All @@ -3509,21 +3515,17 @@ public class GenC : GenCCpp
CloseBlock();
}

void WriteTryParseLibrary!(string signature, string call)
void StartTryParseLibrary!(string klassName, string type, string baseParam)
{
WriteNewLine();
Write("static bool Fu");
WriteLine(signature);
StartLibraryMethod("bool", klassName, "TryParse", type);
Write(" *result, const char *str");
Write(baseParam);
WriteCharLine(')');
OpenBlock();
WriteLine("if (*str == '\\0')");
WriteLine("\treturn false;");
WriteLine("char *end;");
WriteLine("errno = 0;");
Write("*result = strto");
Write(call);
WriteLine(");");
WriteLine("return *end == '\\0' && errno == 0;");
CloseBlock();
}

void WriteIntLibrary!(string klassName, string type, SortedSet<FuId> methods)
Expand All @@ -3533,13 +3535,7 @@ public class GenC : GenCCpp
if (methods.Contains(FuId.MathMax))
WriteIntMaxMin(klassName, "Max", type, '>');
if (methods.Contains(FuId.MathClamp)) {
WriteNewLine();
Write("static ");
Write(type);
Write(" Fu");
Write(klassName);
Write("_Clamp(");
Write(type);
StartLibraryMethod(type, klassName, "Clamp", type);
Write(" x, ");
Write(type);
Write(" minValue, ");
Expand All @@ -3550,10 +3546,19 @@ public class GenC : GenCCpp
CloseBlock();
}
if (methods.Contains(FuId.IntTryParse)) {
if (klassName == "Long")
WriteTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base");
else
WriteTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base");
StartTryParseLibrary(klassName, type, ", int base");
if (klassName == "Int") {
WriteLine("long l = strtol(str, &end, base);");
WriteLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)");
WriteLine("\treturn false;");
WriteLine("*result = (int) l;");
WriteLine("return true;");
}
else {
WriteLine("*result = strtoll(str, &end, base);");
WriteLine("return *end == '\\0' && errno == 0;");
}
CloseBlock();
}
}

Expand All @@ -3562,8 +3567,12 @@ public class GenC : GenCCpp
WriteIntLibrary("Int", "int", this.IntFunctions);
WriteIntLibrary("NInt", "ptrdiff_t", this.NIntFunctions);
WriteIntLibrary("Long", "int64_t", this.LongFunctions);
if (this.DoubleTryParse)
WriteTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end");
if (this.DoubleTryParse) {
StartTryParseLibrary("Double", "double", "");
WriteLine("*result = strtod(str, &end);");
WriteLine("return *end == '\\0' && errno == 0;");
CloseBlock();
}
if (this.StringAssign) {
WriteNewLine();
WriteLine("static void FuString_Assign(char **str, char *value)");
Expand Down
57 changes: 33 additions & 24 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11437,6 +11437,7 @@ void GenC::writeCallExpr(const FuExpr * obj, const FuMethod * method, const std:
writeEnumHasFlag(obj, args, parent);
break;
case FuId::intTryParse:
include("limits.h");
this->intFunctions.insert(FuId::intTryParse);
write("FuInt");
writeTryParse(obj, args);
Expand Down Expand Up @@ -12935,7 +12936,7 @@ void GenC::writeMethod(const FuMethod * method)
this->currentMethod = nullptr;
}

void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, std::string_view type, int op)
void GenC::startLibraryMethod(std::string_view type, std::string_view klassName, std::string_view method, std::string_view paramType)
{
writeNewLine();
write("static ");
Expand All @@ -12945,7 +12946,12 @@ void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, s
writeChar('_');
write(method);
writeChar('(');
write(type);
write(paramType);
}

void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, std::string_view type, int op)
{
startLibraryMethod(type, klassName, method, type);
write(" x, ");
write(type);
writeLine(" y)");
Expand All @@ -12956,21 +12962,17 @@ void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, s
closeBlock();
}

void GenC::writeTryParseLibrary(std::string_view signature, std::string_view call)
void GenC::startTryParseLibrary(std::string_view klassName, std::string_view type, std::string_view baseParam)
{
writeNewLine();
write("static bool Fu");
writeLine(signature);
startLibraryMethod("bool", klassName, "TryParse", type);
write(" *result, const char *str");
write(baseParam);
writeCharLine(')');
openBlock();
writeLine("if (*str == '\\0')");
writeLine("\treturn false;");
writeLine("char *end;");
writeLine("errno = 0;");
write("*result = strto");
write(call);
writeLine(");");
writeLine("return *end == '\\0' && errno == 0;");
closeBlock();
}

void GenC::writeIntLibrary(std::string_view klassName, std::string_view type, const std::set<FuId> * methods)
Expand All @@ -12980,13 +12982,7 @@ void GenC::writeIntLibrary(std::string_view klassName, std::string_view type, co
if (methods->contains(FuId::mathMax))
writeIntMaxMin(klassName, "Max", type, '>');
if (methods->contains(FuId::mathClamp)) {
writeNewLine();
write("static ");
write(type);
write(" Fu");
write(klassName);
write("_Clamp(");
write(type);
startLibraryMethod(type, klassName, "Clamp", type);
write(" x, ");
write(type);
write(" minValue, ");
Expand All @@ -12997,10 +12993,19 @@ void GenC::writeIntLibrary(std::string_view klassName, std::string_view type, co
closeBlock();
}
if (methods->contains(FuId::intTryParse)) {
if (klassName == "Long")
writeTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base");
else
writeTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base");
startTryParseLibrary(klassName, type, ", int base");
if (klassName == "Int") {
writeLine("long l = strtol(str, &end, base);");
writeLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)");
writeLine("\treturn false;");
writeLine("*result = (int) l;");
writeLine("return true;");
}
else {
writeLine("*result = strtoll(str, &end, base);");
writeLine("return *end == '\\0' && errno == 0;");
}
closeBlock();
}
}

Expand All @@ -13009,8 +13014,12 @@ void GenC::writeLibrary()
writeIntLibrary("Int", "int", &this->intFunctions);
writeIntLibrary("NInt", "ptrdiff_t", &this->nIntFunctions);
writeIntLibrary("Long", "int64_t", &this->longFunctions);
if (this->doubleTryParse)
writeTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end");
if (this->doubleTryParse) {
startTryParseLibrary("Double", "double", "");
writeLine("*result = strtod(str, &end);");
writeLine("return *end == '\\0' && errno == 0;");
closeBlock();
}
if (this->stringAssign) {
writeNewLine();
writeLine("static void FuString_Assign(char **str, char *value)");
Expand Down
57 changes: 33 additions & 24 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11693,6 +11693,7 @@ protected override void WriteCallExpr(FuExpr obj, FuMethod method, List<FuExpr>
WriteEnumHasFlag(obj, args, parent);
break;
case FuId.IntTryParse:
Include("limits.h");
this.IntFunctions.Add(FuId.IntTryParse);
Write("FuInt");
WriteTryParse(obj, args);
Expand Down Expand Up @@ -13163,7 +13164,7 @@ protected override void WriteMethod(FuMethod method)
this.CurrentMethod = null;
}

void WriteIntMaxMin(string klassName, string method, string type, int op)
void StartLibraryMethod(string type, string klassName, string method, string paramType)
{
WriteNewLine();
Write("static ");
Expand All @@ -13173,7 +13174,12 @@ void WriteIntMaxMin(string klassName, string method, string type, int op)
WriteChar('_');
Write(method);
WriteChar('(');
Write(type);
Write(paramType);
}

void WriteIntMaxMin(string klassName, string method, string type, int op)
{
StartLibraryMethod(type, klassName, method, type);
Write(" x, ");
Write(type);
WriteLine(" y)");
Expand All @@ -13184,21 +13190,17 @@ void WriteIntMaxMin(string klassName, string method, string type, int op)
CloseBlock();
}

void WriteTryParseLibrary(string signature, string call)
void StartTryParseLibrary(string klassName, string type, string baseParam)
{
WriteNewLine();
Write("static bool Fu");
WriteLine(signature);
StartLibraryMethod("bool", klassName, "TryParse", type);
Write(" *result, const char *str");
Write(baseParam);
WriteCharLine(')');
OpenBlock();
WriteLine("if (*str == '\\0')");
WriteLine("\treturn false;");
WriteLine("char *end;");
WriteLine("errno = 0;");
Write("*result = strto");
Write(call);
WriteLine(");");
WriteLine("return *end == '\\0' && errno == 0;");
CloseBlock();
}

void WriteIntLibrary(string klassName, string type, SortedSet<FuId> methods)
Expand All @@ -13208,13 +13210,7 @@ void WriteIntLibrary(string klassName, string type, SortedSet<FuId> methods)
if (methods.Contains(FuId.MathMax))
WriteIntMaxMin(klassName, "Max", type, '>');
if (methods.Contains(FuId.MathClamp)) {
WriteNewLine();
Write("static ");
Write(type);
Write(" Fu");
Write(klassName);
Write("_Clamp(");
Write(type);
StartLibraryMethod(type, klassName, "Clamp", type);
Write(" x, ");
Write(type);
Write(" minValue, ");
Expand All @@ -13225,10 +13221,19 @@ void WriteIntLibrary(string klassName, string type, SortedSet<FuId> methods)
CloseBlock();
}
if (methods.Contains(FuId.IntTryParse)) {
if (klassName == "Long")
WriteTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base");
else
WriteTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base");
StartTryParseLibrary(klassName, type, ", int base");
if (klassName == "Int") {
WriteLine("long l = strtol(str, &end, base);");
WriteLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)");
WriteLine("\treturn false;");
WriteLine("*result = (int) l;");
WriteLine("return true;");
}
else {
WriteLine("*result = strtoll(str, &end, base);");
WriteLine("return *end == '\\0' && errno == 0;");
}
CloseBlock();
}
}

Expand All @@ -13237,8 +13242,12 @@ void WriteLibrary()
WriteIntLibrary("Int", "int", this.IntFunctions);
WriteIntLibrary("NInt", "ptrdiff_t", this.NIntFunctions);
WriteIntLibrary("Long", "int64_t", this.LongFunctions);
if (this.DoubleTryParse)
WriteTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end");
if (this.DoubleTryParse) {
StartTryParseLibrary("Double", "double", "");
WriteLine("*result = strtod(str, &end);");
WriteLine("return *end == '\\0' && errno == 0;");
CloseBlock();
}
if (this.StringAssign) {
WriteNewLine();
WriteLine("static void FuString_Assign(char **str, char *value)");
Expand Down
3 changes: 2 additions & 1 deletion libfut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2336,8 +2336,9 @@ class GenC : public GenCCpp
void writeDestructFields(const FuSymbol * symbol);
void writeNewDelete(const FuClass * klass, bool define);
static bool canThrow(const FuType * type);
void startLibraryMethod(std::string_view type, std::string_view klassName, std::string_view method, std::string_view paramType);
void writeIntMaxMin(std::string_view klassName, std::string_view method, std::string_view type, int op);
void writeTryParseLibrary(std::string_view signature, std::string_view call);
void startTryParseLibrary(std::string_view klassName, std::string_view type, std::string_view baseParam);
void writeIntLibrary(std::string_view klassName, std::string_view type, const std::set<FuId> * methods);
void writeLibrary();
};
Expand Down
Loading

0 comments on commit 395c6ea

Please sign in to comment.