Correct output locally, incorrect on official USACO website

Problem Info

Bronze 2017 - Why Did the Cow Cross the Road II

Question

My code outputs the expected answer when running the sample case locally, but throws a runtime error/memory limit exceeded error in the official USACO analysis mode:

Upon further troubleshooting and trying it on the usaco.guide IDE, it throws the following error:

What I’ve Tried

  • Enabling -fsanitize=undefined,address flag in my compiler options
  • Using lldb to debug

I wasn’t able to reproduce the error seen above locally with any of these methods.

My Work

/*
USACO Bronze 2017: Why Did the Cow Cross the Road II
https://www.usaco.org/index.php?page=viewproblem2&cpid=712
*/

#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>

// Returns true if a character is in a string, false if it isn't
bool isInString(char character, std::string str) {

	if (std::find(str.begin(), str.end(), character) == str.end()) {
		return false;
	}
	
	return true;
}


void nextCow(std::string &roadTotal, int &answer) {
    // Store the letter of the first cow in currentCow
	char currentCow = *roadTotal.begin();
    // Delete its letter (since we don't need it anymore)
	roadTotal.erase(roadTotal.begin());

    // For each cow afterwards until currentCow strikes again, count the number of occurances
	std::string roadSegment = "";
	for (auto it = roadTotal.begin(); it < roadTotal.end(); it++) {
        // Check if we've reached currentCow, if so, tally up the double-occurances by counting the length of roadSegment. Then, break out of the loop
		if (*it == currentCow) {
			answer += roadSegment.size();
			roadTotal.erase(it);
			break;
		}

        // If we haven't reached currentCow, check if the current iterator is in roadSegment
		if (isInString(*it, roadSegment)) {
            // If so, that's a double occurance: erase the one in roadSegment so that it doesn't get tallied up later
			roadSegment.erase(std::find(roadSegment.begin(), roadSegment.end(), *it));
		} else {
            // If not, append it to roadSegment
			roadSegment.push_back(*it);
		}
	}
}


int main() {
	// For USACO contests before 2020
	std::ifstream fin("circlecross.in");
	std::ofstream fout("circlecross.out");

    // Read the input
	std::string roadTotal;
	fin >> roadTotal;

    // For each cow, determines the number of cows that cross its path
	int answer = 0;
	for (int i = 0; i <= 26; i++) {
		nextCow(roadTotal, answer);
	}

    // Output the answer
	fout << answer << "\n";
	return 0;
}

To determine the number of path crossings other cows make with cow i, I looked at the segment in between the entrance and exit of i. For each cow present in the segment, we can determine whether it crosses paths with cow i by counting the number of occurrences in the segment. If a particular cow only occurs once in the segment, we can deem that it crosses paths with cow i, since its entrance and exit are on either side of cow i's path. Conversely, if a cow occurs twice in the segment, we can deem that it doesn’t cross paths with cow i, since its entrance and exit are both on one side of cow i's path. By using this logic on each of the cows and remove the entrances and exits of a cow after we’ve counted all of its path crossings, I found the total number of crossings.

Fixed: <= sign should be < on line 47

If I compile with homebrew GCC and use lldb to print the backtrace, it prints where the error occurs. However, I wasn’t able to do the same with clang++.

benjaminqi:Desktop % g++-13 -g circlecross.cpp && ./a.out
zsh: segmentation fault  ./a.out
benjaminqi:Desktop % lldb a.out
(lldb) target create "a.out"
Current executable set to '/Users/benjaminqi/Desktop/a.out' (arm64).
(lldb) r
Process 9341 launched: '/Users/benjaminqi/Desktop/a.out' (arm64)
Process 9341 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x600020000000)
    frame #0: 0x0000000184d4d770 libsystem_platform.dylib`_platform_memmove + 288
libsystem_platform.dylib`:
->  0x184d4d770 <+288>: ldp    q0, q1, [x1]
    0x184d4d774 <+292>: add    x1, x1, #0x20
    0x184d4d778 <+296>: subs   x2, x2, #0x20
    0x184d4d77c <+300>: b.hi   0x184d4d768               ; <+280>
Target 0: (a.out) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x600020000000)
  * frame #0: 0x0000000184d4d770 libsystem_platform.dylib`_platform_memmove + 288
    frame #1: 0x000000010089a3f8 libstdc++.6.dylib`std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_erase(unsigned long, unsigned long) + 68
    frame #2: 0x000000010089af44 libstdc++.6.dylib`std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::erase(__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) + 36
    frame #3: 0x0000000100002c34 a.out`nextCow(roadTotal=0x000000016fdfea00, answer=0x000000016fdfe9fc) at circlecross.cpp:26:17
    frame #4: 0x0000000100002e84 a.out`main at circlecross.cpp:62:10
    frame #5: 0x000000018499d0e0 dyld`start + 2360
(lldb) q
Quitting LLDB will kill one or more processes. Do you really want to proceed: [Y/n] y
benjaminqi:Desktop % g++-13 --version
g++-13 (Homebrew GCC 13.2.0) 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

benjaminqi:Desktop % 

Interesting; I used homebrew clang++ to compile and it didn’t warn me of any undefined behavior either