Crashes parsing end of array or empty array
Closed this issue · 4 comments
JetForMe commented
The following JSON causes the code below it to fail when it gets to the end of the array. Specifically, I get a bad_alloc exception (on OS X):
Podtique(44576,0x7fff7c44d300) malloc: *** mach_vm_map(size=107202383921152) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
This happens on the line with " <===== bad_alloc" below.
[
{
"freq" : 0.1,
"desc" : "Desc1",
"playlist" :
[
]
}
]
[
{
"freq" : 0.1,
"desc" : "Desc2",
"playlist" :
[
"one",
"two"
]
}
]
bool
getFromJSONIter(picojson::value::array::const_iterator& inIter, const std::string& inKey, std::string& outVal)
{
if (!inIter->is<picojson::value::object>())
{
return false;
}
picojson::value::object obj = inIter->get<picojson::value::object>();
const picojson::value& v = obj[inKey];
if (!v.is<std::string>())
{
return false;
}
outVal = v.get<std::string>();
return true;
}
bool
getFromJSONIter(picojson::value::array::const_iterator& inIter, const std::string& inKey, double& outVal)
{
if (!inIter->is<picojson::value::object>())
{
return false;
}
picojson::value::object obj = inIter->get<picojson::value::object>();
const picojson::value& v = obj[inKey];
if (!v.is<double>())
{
return false;
}
outVal = v.get<double>();
return true;
}
bool
getFromJSONIter(picojson::value::array::const_iterator& inIter, const std::string& inKey, picojson::value::array& outVal)
{
if (!inIter->is<picojson::value::object>())
{
return false;
}
picojson::value::object obj = inIter->get<picojson::value::object>();
const picojson::value& v = obj[inKey];
if (!v.is<picojson::value::array>())
{
return false;
}
outVal = v.get<picojson::value::array>();
return true;
}
bool
Spectrum::parseSpectrum(const picojson::value& inJSON)
{
// Top level is an array…
if (!inJSON.is<picojson::array>())
{
return false;
}
const picojson::value::array& stations = inJSON.get<picojson::array>();
for (picojson::value::array::const_iterator iter = stations.begin(); iter != stations.end(); ++iter)
{
std::string desc;
if (!getFromJSONIter(iter, "desc", desc)) { continue; }
double freq;
if (!getFromJSONIter(iter, "freq", freq)) { continue; }
picojson::value::array playlist;
if (!getFromJSONIter(iter, "playlist", playlist)) { continue; }
LogDebug("Station: %s, freq: %f, tracks: %lu", desc.c_str(), freq, playlist.size());
int i = 0;
for (picojson::value::array::const_iterator trackIter = playlist.begin(); iter != playlist.end(); ++trackIter)
{
if (!trackIter->is<std::string>()) { continue; }
std::string track = trackIter->get<std::string>(); <===== bad_alloc
LogDebug("Track %02d: %s", i++, track.c_str());
}
}
return true;
}
JetForMe commented
Note that this doesn't happen if I iterate the array like this:
for(size_t idx = 0; idx < playlist.size(); ++idx)
{
const picojson::value& v = playlist[idx];
if (!v.is<std::string>()) { continue; }
std::string track = v.get<std::string>();
LogDebug("Track %02i: %s", idx, track.c_str());
}
JetForMe commented
Also, I noticed I was getting corrupted values for a few of the strings using the iterator method, but with the index approach it seems correct.
kazuho commented
Seems like an error in your code:
for (picojson::value::array::const_iterator trackIter = playlist.begin(); iter != playlist.end(); ++trackIter)
The condition to exit the loop should be trackIter != playlist.end()
.
JetForMe commented
Hahahahahahaa I'm such an idiot! I'm so sorry. I even looked at that line to be sure I had it right, thinking there was an issue at the end of the array. Wow. So sorry.