From 3534dcc966683c3cfcd846e629f9e2b461bc0fe9 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Sat, 4 Apr 2026 21:59:05 +0200 Subject: [PATCH] fix: warn Filehandle opened only for input for print/say to read-only fh When printing to a filehandle opened for reading only, the builtin print and say now set errno to Bad file descriptor, emit the warning (when warnings enabled via io category), and return undef. This was the last remaining Text::CSV failure: t/70_rt.t test 72. All 40 Text::CSV test files now pass (52723/52723 subtests). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../java/org/perlonjava/core/Configuration.java | 2 +- .../perlonjava/runtime/operators/IOOperator.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 1c8294666..5d718bcd5 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java +++ b/src/main/java/org/perlonjava/core/Configuration.java @@ -33,7 +33,7 @@ public final class Configuration { * Automatically populated by Gradle/Maven during build. * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String gitCommitId = "4aafb6057"; + public static final String gitCommitId = "a7261e446"; /** * Git commit date of the build (ISO format: YYYY-MM-DD). diff --git a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java index 97dc2d33d..3ad8c7349 100644 --- a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java +++ b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java @@ -734,6 +734,14 @@ public static RuntimeScalar print(RuntimeList runtimeList, RuntimeScalar fileHan try { // Write the content to the file handle return fh.write(sb.toString()); + } catch (java.nio.channels.NonWritableChannelException e) { + // Writing to a read-only filehandle (opened with "<") + getGlobalVariable("main::!").set("Bad file descriptor"); + WarnDie.warnWithCategory( + new RuntimeScalar("Filehandle opened only for input"), + new RuntimeScalar(""), + "io"); + return new RuntimeScalar(); // undef } catch (Exception e) { getGlobalVariable("main::!").set("File operation failed: " + e.getMessage()); return scalarFalse; @@ -779,6 +787,14 @@ public static RuntimeScalar say(RuntimeList runtimeList, RuntimeScalar fileHandl return scalarFalse; } return fh.write(sb.toString()); + } catch (java.nio.channels.NonWritableChannelException e) { + // Writing to a read-only filehandle (opened with "<") + getGlobalVariable("main::!").set("Bad file descriptor"); + WarnDie.warnWithCategory( + new RuntimeScalar("Filehandle opened only for input"), + new RuntimeScalar(""), + "io"); + return new RuntimeScalar(); // undef } catch (Exception e) { getGlobalVariable("main::!").set("File operation failed: " + e.getMessage()); return scalarFalse;