Ginger recently finished an advanced degree, and during her work, she of course had to work as a TA for a number of classes. Computer science professors are, at least in theory, capable of programming, and thus can build automation around assignments- providing students with templates to highlight specific tools and techniques, or to automate the process of grading.

Dr. Buchler taught the computer graphics course, and the ultimate assignment was to build a simple 3D game. Buchler provided a pre-scaffolded project with a set of templates that could be filled in, so the students didn’t need to worry about a lot of the boilerplate. Beyond that, Buchler didn’t offer much guidance about how students should collaborate, so students did what came naturally: they set up git repos and shared code that way.

The students who used Git, which was essentially all of them, started contacting Ginger. “My code is broken!” “It worked, on my machine when I wrote it, but now it doesn’t! I haven’t changed anything!”

Obviously, there must be an issue with the professor’s template, but when Ginger mentioned this to Buchler, he dismissed the concern. “I’ve been using this template for years, and have never had a problem. The students must have errors in their code.”

Ginger worked closely with one of the student groups, and if there were errors in the code, she couldn’t see them. And what immediately leapt out to her was that code which worked would suddenly break- but it only seemed like it happened after a commit.

The core pattern was that the students would write a fragment of a shader, and then the project would merge their fragment with a surrounding template to create a full GLSL shader that could actually execute, akin to how Shader Toy injects some additional code around your key logic.

Now, when loading code into the template, Buchler had written something like this: String[] vscr = new Scanner(Paths.get(ShaderProgram.class.getResource(shader).toURI())).useDelimiter("\\Z").next().split("\r\n");

There was no real reason for the split, but Buchler wanted to use an array of lines instead of a blob of text. That was also the source of the problem.

The split would remove Windows line endings from the students’ code. For the students, who were frequently on Windows, this meant that when their shader got loaded, all the newlines would get stripped from their code.

This meant a simple shader, like:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.xy;
    vec3 col = abs(vec3(sin(uv.x * 50.)));
    fragColor = vec4(col,1.0);
}

would get mashed into: void mainImage( out vec4 fragColor, in vec2 fragCoord ){ vec2 uv = fragCoord/iResolution.xy; vec3 col = abs(vec3(sin(uv.x * 50.))); fragColor = vec4(col,1.0);}. Not elegant, but syntactically valid.

Of course, if the students used any #define directives, or included single-line comments, that could easily blow up their shaders. But that didn’t explain why, for many, the code worked until a commit.

Remember, Buchler’s system would mash the students’ shader code into his own template. His template was, at least in its current form, using Unix-style line endings- just \n, not \r\n. So the template wouldn’t have its line endings stripped out, at least not by default. Until the students committed the repo. At that point, the entire shader would be put on a single line, and Buchler's template did include some #define statements.

Git has a core.autorcrlf parameter. It makes sure that the version stored in the commits is using a Unix-style LF, but the version stored on your filesystem uses CRLF on Windows. It’s a change you’d never notice, as any text editor worth its salt is going to transparently handle whatever line-ending character its offered, but it emphatically breaks Buchler’s template.

Ginger showed the students how to update the template project to avoid this particular bug, and told Buchler what she’d found. “You could just remove the split and it’d be fine,” Ginger suggested.

“I’ll look into it, I guess,” Buchler said.

Students finished their projects, Ginger moved on, but near the end of the following semester, she started hearing students complaining: “I’m doing Buchler’s graphics class, and my code just stopped working for no reason.”

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!